如果我在Python中创建一个类,并且我给它一个类属性(这可以直接从文档中获取,here),如
.details-favoriteicon {
color: crimson;
}
我认为,正如文档建议的那样,
时class Dog:
tricks = []
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick)
我知道这个技巧也被添加到d2中了:
d1 = Dog('d1')
d2 = Dog('d2')
d1.add_trick('trick')
print d2.tricks
这是因为['trick']
是一个类属性而不是一个实例属性,所以在所有实例中共享(如果这不是正统的话,请纠正我!)。
现在,假设我改为
tricks
我跑
class Dog:
a = 1
def __init__(self, name):
self.name = name
def improve_a(self):
self.a += 1
这分别给我2和1,即第二个实例的计数没有改变。为什么这样,为什么行为不同?
答案 0 :(得分:2)
int
类未定义+ =运算符(__iadd__
方法)。这没有意义,因为它是不可改变的。
这就是+=
默认为+
然后=
的原因。 reference
self.a += 1
变为self.a = self.a + 1
现在,当您第一次拨打improve_a
时,会发生以下情况:
a
并将其放入堆栈1
添加到堆栈中的项目a
并为其分配堆栈上的值这意味着class属性根本没有更改,并且您添加了新的实例属性。
在improve
对同一个对象的每次后续调用中,实例属性都会递增,因为属性查找在实例dict上开始,并且只有在该属性不存在时才会转到类dict。
如果你对一个重载__iadd__
方法的可变类做同样的事情,你会得到不同的行为:
class HasList:
some_list = []
def add_something(self, value):
some_list += [value]
fst = HasList()
sec = HasList()
fst.add_something(1)
fst.add_something(2)
sec.add_something(3)
print(HasList.some_list, fst.some_list, sec.some_list)
您将看到所有实例和类本身仍保持相同的列表。打印件每次显示相同的列表[1, 2, 3]
。您还可以检查所有三个列表是否相同:fst.some_list is sec.some_list and fst.some_list is HasList.some_list # -> True
。
这是因为list.__iadd__
只调用list.extend
并在方法内返回(至少如果是用python编写的话)。