【发布时间】:2014-05-09 10:23:07
【问题描述】:
这个问题的目的是确定我是否可以包装设置一个对象的属性,而不只写一个setter然后包装setter。
我正在尝试实现一个观察者模式,我不想编写比我需要的更多的代码(所以我当然会写一个很长的 StackOverflow 问题,哈哈 - 我认为长期回报是值得的它)。
我开始尝试用函数包装obj.__setattr__,但它并没有达到我预期的效果,所以现在我想知道如果我不包装分配或更改对象的属性是否可以只需编写一个 setter。
这是我尝试过的:
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"
如果我只写一个 setter,它会成为一个简单的钩子,比如:
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 包装直接,但我希望创建一些我可以在以下(虚构的伪代码)方式中使用的东西:
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
但是 this 是我更愿意在事后包装 setter 的原因。我有两个不同的对象,它们不一定需要彼此有硬编码的数据;只是一个带有self.score 属性的玩家对象和一个带有self.text 属性的记分牌对象,虽然在它们之间编写“胶水”当然是必要的,但我希望编写set_score 和set_text 的方法不会仅仅实现观察者模式并不重要。
如果我最终不能跳过编写一个(或多个)设置器,那么我想我会继续这样做;我只是希望避免它。
虽然现在这是一个非常具体的示例,但我也是在一般意义上提出问题,因为能够只观察属性的变化而不是围绕每个属性进行编码以做好准备似乎真的很方便也许正在观察其他对象的一些变化。 :/
【问题讨论】:
-
为什么不让它成为一个属性?
-
也许我不明白 @property 应该做什么 - 我看过它(在你的建议之前和之后),但我没有看到它对我有什么帮助