从实例修改类属性,根据类型不同的行为?

时间:2016-07-13 14:27:24

标签: python oop object

如果我在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,即第二个实例的计数没有改变。为什么这样,为什么行为不同?

1 个答案:

答案 0 :(得分:2)

int类未定义+ =运算符(__iadd__方法)。这没有意义,因为它是不可改变的。

这就是+=默认为+然后=的原因。 reference

self.a += 1变为self.a = self.a + 1

现在,当您第一次拨打improve_a时,会发生以下情况:

  1. 读取类属性a并将其放入堆栈
  2. 1添加到堆栈中的项目
  3. 创建新的实例属性a 并为其分配堆栈上的值
  4. 这意味着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编写的话)。