Python类变量是静态的吗?

Rio*_*aki 7 python class

看到以下代码:

class Super:
    powers = 'no power'
    def __init__(self, name):
        self.name = name

    def add_power(self, power):
        self.powers = power

dog = Super('dog')
cat = Super('cat')

dog.add_power("bark")
print (dog.powers) # print bark
print (cat.powers) # print no power
Run Code Online (Sandbox Code Playgroud)

它看起来像python的类变量独立于每个实例,因为更改狗实例的powers变量从无权力到树皮不会影响cat实例的powers变量

但是,通过这样做:

class Super:
    powers = ["no power"]
    def __init__(self, name):
        self.name = name

    def add_power(self, power):
        self.powers.append(power) 

dog = Super('dog')
cat = Super('cat')

dog.add_power("bark")
print (dog.powers) # print ['no power', 'bark']
print (cat.powers) # print ['no power', 'bark']  # why cat.powers is also affected???
Run Code Online (Sandbox Code Playgroud)

示例显示powers变量(这次是一个列表)是静态的,因为将一个元素附加到dog实例powers也会影响cat实例powers.

我还尝试通过调用add_power将权限更改为int并将权力增加1,并且它们不会相互影响.所以我真的很困惑为什么将一个元素附加到列表中,这是一个类变量会影响其他实例.

wim*_*wim 9

实例变量名称可以隐藏同名的类变量.

>>> class A:
...     var = 'class var'
...     
>>> a = A()
>>> vars(a)  # no instance variables
{}
>>> a.var  # attribute lookup resolved at the class level
'class var'
>>> a.var = 'instance var'  # create an instance variable
>>> vars(a)  # the name `var` now exists in the instance dict
{'var': 'instance var'}
>>> a.var  # attribute lookup resolved at the instance level
'instance var'
>>> type(a).var  # note: the class variable still exists!
'class var'
>>> del a.var  # deletes from the instance dict
>>> a.var  # ..but the name `var` remains available at the class level
'class var'
>>> vars(a)  # instance dict is again empty
{}
Run Code Online (Sandbox Code Playgroud)

并非类变量是"静态"的(A.var可以通过普通属性访问进行修改或删除).发生的事情是:访问a.var首先尝试var实例的名称空间(a.__dict__)中的名称,如果失败则查找返回到检查类的名称空间(A.__dict__).

在类对象上使用列表时看不到相同行为的原因是此行不是赋值语句:

self.powers.append(power)
Run Code Online (Sandbox Code Playgroud)

使用赋值语句的看似等效的版本重新创建您观察到的相同名称阴影:

self.powers = self.powers + [power]  # not actually equivalent!
Run Code Online (Sandbox Code Playgroud)

总结:当为类属性使用整数或字符串时,您在实例命名空间中创建了一个条目(因为赋值语句),但是当使用列表时,您直接对类变量执行操作,这实际上是在所有类之间共享的实例.