【问题标题】:Is Python class variable static?Python类变量是静态的吗?
【发布时间】:2018-06-04 21:15:32
【问题描述】:

看到如下代码:

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

看起来python的类变量对每个实例都是独立的,因为将dog实例的powers变量从无电源更改为bark不会影响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???

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

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

【问题讨论】:

标签: python class


【解决方案1】:

一个实例变量名可以隐藏一个同名的类变量。

>>> 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
{}

类变量不是“静态”的(A.var 可以通过正常的属性访问来修改或删除)。实际发生的情况是:访问 a.var 首先尝试实例命名空间 (a.__dict__) 中的名称 var,如果失败,则查找返回到检查类的命名空间 (A.__dict__)。

在类对象上使用列表时看不到相同行为的原因是此行不是assignment statement

self.powers.append(power)

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

self.powers = self.powers + [power]  # not actually equivalent!

总而言之:当使用整数或字符串作为类属性时,您在实例命名空间中创建了一个条目(因为赋值语句),但是当使用列表时,您直接作用于类变量,这确实是在所有实例之间共享。

【讨论】:

  • 优秀的答案。我不敢相信这不是一个超级骗子。
猜你喜欢
  • 1970-01-01
  • 2015-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-09
  • 2012-09-14
  • 2013-09-08
相关资源
最近更新 更多