字典和数组作为类与实例变量

时间:2011-09-01 22:05:17

标签: python

这是赚取积分的简单方法。请解释以下内容:

class C:
    a = {}
    b = 0
    c = []

    def __init__(self):
        self.x = {}

    def d(self, k, v):
        self.x[k] = v
        self.a[k] = v;
        self.b = v
        self.c.append(v)

    def out(self, k):
        print(self.x[k], self.a[k], self.b, self.c[0])

c = C()
d = C()
c.d(1, 10)
d.d(1, 20)
c.out(1)  
d.out(1)

将输出以下内容:

10 20 10 10
20 20 20 10

为什么字典,列表和'普通'变量的表现各不相同?

编辑:我认为问题很明显,但让我更详细地说明一下:

我有一个有三个属性的类,a,b和c。我创建了该类的两个实例。然后我调用一个方法来修改每个实例的这些属性。当我检查属性时,我发现如果一个属性是一个字典,它将在所有实例中共享,而如果它是一个“普通”变量,它的行为就像人们期望的那样,对于每个实例都是不同的。

2 个答案:

答案 0 :(得分:5)

首先,[]不是数组,它是一个列表。这里的问题是属性解析和可变变量如何工作。让我们从

开始
class Foo(object):
    a = {}
    b = 0
    c = []

这将创建一个具有三个属性的类 - 可以通过类本身(例如Foo.a)或通过类'实例(Foo().a)获得这些属性。属性存储在名为__dict__的特殊内容中。类和实例都有一个(有些情况下这不是真的,但它们在这里无关紧要) - 但在Foo的情况下,当实例是实例时,实例__dict__为空已创建 - 所以当您执行Foo().a时,实际上您正在访问与Foo.a中相同的对象。

现在,您要添加__init__

class Foo(object):
    # ...

    def __init__(self):
        self.x = {}

这会创建一个不属于“__dict__”类的属性,但会在实例1中创建一个属性,因此您无法访问Foo.x,只能访问Foo().x。这也意味着x在每个实例中都是一个完全不同的对象,而类属性由所有类实例共享。

现在你要添加你的变异方法。

class Foo(object):
    # ...

    def mutate(self, key, value):
        self.x[key] = value
        self.a[key] = value
        self.b      = value
        self.c.append(value)

您是否记得self.x = {}创建了一个实例属性?这里self.b = value做了同样的事情 - 它根本不触及class属性,它创建了一个新的实例,实例掩盖了共享的一个(这就是引用在Python中的工作方式 - 赋值将名称绑定到一个对象) ,并且永远不会修改名称所指向的对象。)

但你没有重新绑定self.aself.c - 你就地改变它们(因为它们是可变的,你可以这样做) - 所以实际上你正在修改原始的类属性,这就是为什么你可以观察另一个实例中的变化(因为它们是由它们共享的)。 self.x表现不同,因为它不是类属性,而是实例1。

您还只打印self.c的第一个元素 - 如果您打印所有元素,则会看到[10, 20]

答案 1 :(得分:2)

a和c是类属性b,x是实例属性。

您应该阅读并理解Python: Difference between class and instance attributes