`__setattr__` 仅对未在对象属性中找到的名称有效吗?

2 投票
3 回答
2283 浏览
提问于 2025-04-17 12:16

我想在对象的属性找不到的时候才使用 __setattr__,就像 __getattr__ 一样。

我真的需要用 try-except 吗?

def __setattr__(self, name, value):
    try:
        setattr(super(Clazz, self), name, value)
    except AttributeError:
        # implement *my* __setattr__
        pass

3 个回答

0

__setattr__ 是一个特殊的方法,如果它存在的话,每当你给对象设置属性时,这个方法就会被调用。

不过,你的示例代码让我有点困惑。你想通过这句代码: setattr(super(Clazz, self), name, value) 来做什么呢?

是想在 self 上设置一个属性,同时把 self 看作是它的父类的一个实例吗?这听起来没什么意义,因为对象还是 "self"。

另一方面,尝试在通过 "super" 调用返回的对象上使用 "setattr" 总是会出现属性错误,无论这个属性在父类中是否存在。这是因为 super 返回的不是父类本身,而是一个包装对象,当需要属性时它会去父类那里获取。因此,你可以在 super 返回的对象上使用 "hasattr",但不能使用 "setattr"。我觉得应该是这样,所以我在控制台上试了一下:

>>> class A(object):pass
... 
>>> class B(A): pass
... 
>>> b = B()
>>> super(B,b)
<super: <class 'B'>, <B object>>
>>> setattr(super(B,b), "a", 5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'super' object has no attribute 'a'
>>> A.a = 1
>>> setattr(super(B,b), "a", 5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'super' object has no attribute 'a'

但是,你可以直接在对象本身上使用 "hasattr",然后这样继续:

def __setattr__(self, attr, value):
    if hasattr(self, value):
        #this works because retrieving "__setattr__" from the 
        # result of the supercall gives the correct "__setattr__" of the superclass.
        super(Clazz, self).__setattr__(self, attr, value)
    else:
        # transform value /or attribute as desired in your code
        super(Clazz, self).__setattr__(self, attr, value)
3

有很多时候,当你调用 hasattr 时,它的表现可能和你预想的不一样(比如,你重写了 __getattr__ 方法,让它总是返回一个值),所以另一种在正确的位置设置合适属性的方法可以是这样的:

def __setattr__(self, k, v):
    if k in self.__dict__ or k in self.__class__.__dict__:
        super(Clazz, self).__setattr__(k, v)
    else:
        # implement *my* __setattr__
        pass
3

你可以使用 hasattr() 这个函数:

def __setattr__(self, name, value):
    if hasattr(super(Clazz, self), name):
        setattr(super(Clazz, self), name, value)
    else:
        # implement *my* __setattr__
        pass

撰写回答