Python - can I wrap attribute assignment without getter / setter record

The purpose of this question is to determine if I can wrap the setting of an attribute of an object, not just write a setter, and then wrap the setter.

I am trying to implement the Observer pattern, and I do not want to write more code than I need (therefore, of course, I will write the big long question StackOverflow, hah - I believe that it costs a long-term gain).

I started experimenting, trying to wrap the obj.__setattr__function, but he didn’t do what I expected from it, so now I wonder if I can even wrap the assignment or change the attribute of the object, if I don’t, just write a setter.

This is what I tried:

class A(object):
    pass

def wrapper(obj, func):
    def inner(*args, **kwargs):
        print "called it"
        return func(*args, **kwargs)
    return inner

Stick = A()
Stick.__setattr__ = wrapper(Stick, Stick.__setattr__)
Stick.x = 14    #does not print "called it"

If I just write the setter, this will make a simple hook, something like:

class A(object):
    def __init__(self, x):
        self.x = x

    def set_x(self, new_x):
        self.x = x

Observer , , obj.x - , . obj.x int, , obj.x += some_int, , , / obj.x , , obj.set_x(), obj.add_to_x(), obj.subtract_from_x(), obj.times_x() .. ..

EDIT: , , , , .

, :

class Foo(object):
    def __init__(self, ex):
        self._x = ex
    @property
    def x(self):
        return self._x
    @x.setter
    def x(self, value):
        self._x = value

... , , @x.setter, -, ( ) :

A.x.setter = observing_function(A, A.x.setter)

... , A.x observing_function , .

- "", . ( , ), , , / , .

:

def add_to_score(self, pts):
    self.score += pts
    scoreboard_object.text = self.score

... , . , , : P

. , ; self.score self.text, "" , , , set_score set_text wouldn , Observer.

( ), , , ; .

, , , , , , - .:/

+4
2

, . .

( pub/sub - , ). , , , .

class ScoreChanged(Event):
    ...

class Character(ListenerMixin):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, new):
        old = self._score
        self._score = new
        self.fire_event(ScoreChanged(self, old, new))

protag = Character()
scoreboard = Scoreboard()
scoreboard.listen_event(protag, ScoreChanged, scoreboard.on_score_change)

protag.score += 10

-, , . , , , .

, , , , .

+1

, , :

class A(object):
    pass

def wrapper(func):
    def inner(*args, **kwargs):
        print "called it"
        return func(*args, **kwargs)
    return inner

Stick = A()
A.__setattr__ = wrapper(A.__setattr__)
Stick.x = 14    # prints "called it"
Stick.x *= 2    # also prints "called it"
0

Source: https://habr.com/ru/post/1534088/


All Articles