如何在 Python3 中正确调用 __setattr__() 作为 class 的一部分?

How to call __setattr__() correctly in Python3 as part of a class?

我想在设置对象属性时调用一个函数:

class MyClass():
    myattrib = None

    def __setattr__(self, prop, val):
        self.myattrib = val
        print("setting myattrib")

x = MyClass()
x.myattrib = "something"

问题是,这会产生无限递归。

想法是在设置成员变量时调用函数(并实际设置该成员变量),但同时 运行 额外代码(在 print() 语句中展示上面的例子)。

另一个明显的方法是使用 set_attrib() 函数,这在 Java 中很常见,但我想用 pythonic方式,直接设置属性,但同时运行需要额外的代码。

通过super()调用基本版本:

class MyClass(object):
    myattrib = None

    def __setattr__(self, prop, val):
        super().__setattr__('myattrib', val)
        print("setting myattrib")

您可能 不想 忽略这里的 prop 参数,它不一定是 'myattrib' 被设置的。

但是,考虑使用 属性 而不是拦截 all 属性设置:

class MyClass(object):
    _myattrib = None

    @property:
    def myattrib(self):
        return self._myattrib

    @myattrib.setter
    def myattrib(self, val):
        self._myattrib = val
        print("setting myattrib")

我添加了 object 作为 base-class;这是 Python 3 中的默认设置,但是 super()property 对象在 Python 2 中工作的要求。

如果你想在设置 any 属性时执行特定操作,请使用 __setattr__ 并使用 super 调用继承版本进行实际分配:

def __setattr__(self, prop, val):
    super().__setattr__(prop, val)
    print("setting {} to {!r}".format(prop, val)

如果您只想对一个属性(不是所有属性)做一些特殊的事情,您可能应该使用 property 代替:

class MyClass():
    @property
    def some_attribute(self):
        return self._val

    @some_attribute.setter
    def some_attribute(self, value):
        self._val = value
        print("set some_attribute to {!r}".format(value))