Цель этого вопроса - определить, могу ли я обернуть установку атрибута объекта без, просто написав установщик и затем обернув установщик.
Я пытаюсь реализовать шаблон Observer, и я не хочу писать больше кода, чем мне нужно (поэтому, конечно, я напишу большой длинный вопрос StackOverflow, ха - я считаю, что долгосрочная отдача того стоит).
Я начал экспериментировать, пытаясь обернуть obj.__setattr__
функцией, но она не сделала того, что я ожидал, поэтому теперь мне интересно, могу ли я даже обернуть присвоение или изменение атрибута объекта, если я не просто напишу установщик.
Вот что я пробовал:
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"
Если я просто напишу сеттер, получится простой крючок, например:
class A(object):
def __init__(self, x):
self.x = x
def set_x(self, new_x):
self.x = x
Но я хотел бы иметь возможность реализовать шаблон наблюдателя таким образом, чтобы всякий раз, когда 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()
и т. Д. И т. Д.
РЕДАКТИРОВАТЬ: Спасибо, что указали мне на свойства, но я не понимаю, как это может помочь мне обернуть это так, как я реализовываю до сих пор.
Например, если у меня есть объект как таковой:
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
wraps напрямую, но я надеялся создать что-то, что можно было бы использовать следующим образом (воображаемый псевдокод):
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
не будет иметь решающего значения, просто чтобы реализовать Паттерн наблюдателя.
Если в конечном итоге я не могу пропустить написание сеттера (или сеттеров), то, полагаю, я продолжу и сделаю это таким же образом; Я просто надеялся избежать этого.
И хотя сейчас это очень конкретный пример, я также спрашиваю в общем смысле, потому что кажется действительно удобным иметь возможность просто наблюдать за атрибутом на предмет изменений вместо того, чтобы кодировать каждый атрибут, чтобы быть готовым к просмотру некоторых изменения какого-то другого объекта. : /