Is __setattr__ called when an existing attribute is incremented?
现有属性递增时是否调用了uu setattr_uuuu?
我有一个叫做C的班级,我正试图超载。这是C类内部的代码部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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 |
_根据python文档,
object.__setattr__(self, name, value): Called when an attribute assignment is attempted. This is called instead of the normal mechanism (i.e. store the value in the instance dictionary). name is the attribute name, value is the value to be assigned to it.
我知道你可以给一个变量赋值(例如:
假设属性A、B和C已经定义好了,我称之为
1 | Error: o.bump() raised exception TypeError: unsupported operand type(s) for +=: 'NoneType' and 'int' |
当现有属性递增时是否调用setattr?如果是,我将如何增加setattr中的现有属性?
注:假设在定义a、b和c之后调用
如果需要进一步澄清,请告诉我。
Python: Is __setattr__ called when an existing attribute is incremented?
答案是肯定的。使用简化版本的代码可以很容易地看到这一点:
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
运行该代码段会产生:
1 | Setting a to 11 |
您发布的代码的问题是,
解决方案是确保在调用bump()之前初始化属性:
1 2 3 4 5 6 | 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 | a += 1 |
相当于
1 | a = a.__iadd__(1) # (but `a` is only evaluated once.) |
只是对于可变类型,
因此,如果目标是
这样做是因为python有不可变的类型,对于这些类型,一个增强的赋值将不做任何事情。
这一点已经记录在语法参考条目中,用于增加的作业(emphasis mine):
An augmented assignment evaluates the target (which, unlike normal
assignment statements, cannot be an unpacking) and the expression
list, performs the binary operation specific to the type of assignment
on the two operands, and assigns the result to the original target.
The target is only evaluated once.
举例说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | In [44]: class C(object): ...: def __init__(self,a): ...: self.a=a ...: def __setattr__(self,attr,value): ...: print"setting `%s' to `%r'"%(attr,value) ...: super(C,self).__setattr__(attr,value) ...: def __setitem__(self,key,value): ...: print"setitem" ...: return setattr(self,key,value) ...: def __getitem__(self,key): ...: return getattr(self,key) ...: In [45]: c=C([]) setting `a' to `[]' In [46]: c['a']+=[1] setitem setting `a' to `[1]' In [29]: class A(int): ...: def __iadd__(s,v): ...: print"__iadd__" ...: return int.__add__(s,v) ...: def __add__(s,v): ...: print"__add__" ...: return int.__add__(s,v) ...: In [30]: c.a=A(10) setting `a' to `10' In [31]: c.a+=1 __iadd__ setting `a' to `11' |