当另一个对象的属性发生变化时,如何让对象调用方法?

时间:2015-11-15 23:09:24

标签: python python-3.x

我想建立一个系统,只要修改了不同对象的属性,就会调用一个对象的方法,并将新值作为方法的参数。我怎么能做到这样的事情?

编辑:代码示例/澄清:

我的代码看起来像这样:

class SharedAttribute(object):  #I use this as a container class to share attributes between multiple objects
    def __init__(self, value):
        self.value = value

class BaseObject(object):
    def __init__(self, **shared_attributes:
        for (key, value) in shared_attributes:
            if isinstance(value, SharedAttribute):
                setattr(self, key, value)

            else:
                setattr(self, key, SharedAttribute(value))

class MyObject(BaseObject):
    def __init__(self, value1, value2):
        BaseObject.__init__(self, value1, value2)

    def on_value_changed(self, new_value):
        #Do something here

    def incrementValue(self):
        self.value1.value += 1

然后它将被实现为:

a = MyObject(value1 = 1)
b = MyObject(value1 = MyObject.value1)  #a and b are storing references to the same attribute, so when one changes it, it's changed for the other one too.

我想设置它,所以如果我打电话给a.incrementValue(),我会调用b.on_value_changed,并以SharedAttribute的新值作为参数。有没有办法做到这一点?

2 个答案:

答案 0 :(得分:0)

一种方法是使用类似于Django使用ModelManager' s(model.objects的方式)的经理风格属性:

class Foo(object):
    def method_to_call(self, new_val):
        print('Hello from manager. Doing stuff with {}'.format(new_val))


class Bar(object):
    manager = Foo()

    def __init__(self, your_attr):
        self.your_attr = your_attr

    def __setattr__(self, key, val):
        if key == 'your_attr':
            self.manager.method_to_call(val)
        super(Bar, self).__setattr__(key, val)

使用它:

>>> bar = Bar('some value')
Hello from manager. Doing stuff with some value
>>> bar.your_attr = 'A new value'
Hello from manager. Doing stuff with A new value

如果您想使用Foo的特定实例来管理Bar的特定实例,则可以修改__init__()以获取Foo的实例并使用它。由于我们在此处进行super()调用,因此跟踪您的继承非常重要。我不知道你的应用是如何设置的,但如果你使用多重继承,事情可能会变得奇怪。

答案 1 :(得分:0)

如果您具体了解哪些属性正在更新,并且您对这些属性有特殊了解,那么每当某些对象的每个属性发生变化时,您都不需要知道 - 然后你可能只想通过属性获得某种观察者模式。

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

否则,如果你试图获得泛型(你可能不想要),那么你最终会包装一个类属性而不是一个实例属性,这有其自身的优点和缺点。

class B(object):
    pass

def wrapper(objmethod):
    def _inner(*args, **kwargs)
        some_other_thing_you_wanted_to_happen()
        return objmethod(*args, **kwargs)
    return _inner

B.__setattr__ = wrapper(B.__setattr__)

这真的是一种JavaScript-y原型,但是那些像Python一样看起来像Python的人可能会把他们的烹饪勺子弄出来并用它们来打击你。

我认为,如果你想这样做,你会想要坚持装饰者。属性访问器不会以一种你可以“挂钩”而不编写getter / setter的方式公开,因此你几乎肯定会想要属性和装饰器。