当现有属性递增时,是否调用__setattr__?
我有一个名为 C 的课程,我试图重载__setattr__。这是类 C :
中的一段代码class C:
def bump(self):
self.a += 1
self.b += 1
self.c += 1
def __setattr__(self,name,value):
calling = inspect.stack()[1]
if 'private_' in name:
raise NameError("\'private_\' is in the variable name.")
elif '__init__' in calling.function:
self.__dict__['private_' + name] = value
elif name.replace('private_', '') in self.__dict__:
if self.in_C(calling):
if name.replace('private_', '') in self.__dict__.keys():
old_value = self.__dict__[name.replace('private_', '')]
new_value = old_value + value
self.__dict__[name.replace('private_', '')] = new_value
else:
self.__dict__[name.replace('private_','')] = value
else:
raise NameError()
else:
self.__dict__[name] = value
__ setattr__,根据Python docs,
object .__ setattr __(self,name,value):尝试进行属性赋值时调用。这被称为代替正常机制(即将值存储在实例字典中)。 name是属性名称,value是要分配给它的值。
我知道您可以为变量指定一个值(例如:C.__dict__[name] = value
),但是现有属性何时递增,例如self.a += 1
中的bump()
?
假设已经定义了属性 a , b 和 c ,我调用bump()
,然后调用{ {1}}。但是,我收到了这个错误:
__setattr__
现有属性递增时是否调用 setattr ?如果是这样,如何增加setattr中的现有属性?
注意:假设在定义a,b和c之后调用Error: o.bump() raised exception TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int'
。此外,bump()
是一个函数,用于检查in_C(calling)
是否从__setattr__
,C中的某个方法或C之外的方法调用。
告诉我是否需要进一步澄清。
答案 0 :(得分:5)
Python:当现有属性递增时调用__setattr__?
答案是肯定的。使用简化版代码很容易看到这一点:
class C(object):
def __init__(self, a):
object.__setattr__(self, 'a', a)
def __setattr__(self, name, value):
print('Setting {} to {}'.format(name, value))
object.__setattr__(self, name, value)
c = C(10)
c.a += 1
运行该代码段会产生:
Setting a to 11
您发布的代码的问题是+=
在调用__getattribute__
之前先调用__setattr__
。如果属性不存在,那就是失败。
解决方案是确保在调用 bump()之前初始化属性:
class C(object):
def __init__(self, a, b, c):
object.__setattr__(self, 'a', a)
object.__setattr__(self, 'b', a)
object.__setattr__(self, 'c', a)
除了该修复程序之外,还有其他错误(例如 inspect ),但这应该可以帮助您入门。
答案 1 :(得分:0)
虽然看起来似乎
a += 1
相当于a.__iadd__(1)
(如果a
有__iadd__
),它实际上相当于:
a = a.__iadd__(1) # (but `a` is only evaluated once.)
对于可变类型,__iadd__
返回相同的对象,因此您没有看到差异。
因此,如果目标是c.a
,则会调用c
的{{1}}。
同样,如果您执行类似__setattr__
的操作,则会调用__setitem__
。
这样做是因为Python具有不可变类型,否则增强赋值将无效。
在grammar reference entry for augmented assignments(强调我的)中记录了这一点:
增强分配评估目标(与正常情况不同) 赋值语句,不能解包)和表达式 list,执行特定于赋值类型的二进制操作 在两个操作数上,并将结果分配给原始目标。 目标仅评估一次。
举例说明:
c['a']+=1