可怕的初始值 - 可变类型共享相同的引用?

时间:2013-05-14 06:11:05

标签: python

我刚刚拥有。我无法相信这是真的,但经过测试,我发现它是:

class A(object):
    v = []

a = A()
b = A()

您认为以下代码会返回什么?

a.v is b.v

代码怎么样?

a.v.append(1)
a.v[0] == b.v[0]

果然,a.v is b.v,他们都将相同的参考分享到相同的列表。来自一个,以及其他所有编程语言背景,这有什么意义?

在Java中,如果我要写一个这样的类:

class A {
    public Object[] v = new Object[]{};
}

...在我最疯狂的梦想中,我绝不会认为该类的两个实例将共享相同的数组引用。

我的主要问题是,Python类中的初始值是否与Java,C#等相同?为什么类的所有实例都对同一个列表共享相同的引用?

4 个答案:

答案 0 :(得分:13)

您已定义了类属性而不是实例属性。 Python正在做正确的事情。

而不是

class A(object):
    v = []               # Class attribute, shared across all instances!

你需要

class A(object):
    def __init__(self):  # Instance attribute, created anew for each new object
        self.v = []

答案 1 :(得分:3)

Java语法与Python不同。根据您的Java知识尝试猜测正确使用的东西并不是一个好主意

class A(object):
    v = []  # class attribute


class A(object):
    def __init__(self):
        self.v = []  # instance attribute

好的,这些规则很有趣。

如果您尝试访问self.v,首先Python查找实例属性,如果没有查看该类,然后是父类,直到找到一个或引发属性错误

当您分配到self.v时,它始终会将其绑定到实例属性,即使它之前没有。

然后有描述符......

答案 2 :(得分:2)

那是因为v属性(在C ++中认为是static成员变量)。

如果您需要非共享成员属性,则必须在构造函数中声明它:

class A(object):
    def __init__(self):
        selv.v = []

答案 3 :(得分:1)

class A(object):
    v = []

此处v是一个类属性而非实例属性,它们仅在类定义期间定义一次。所以,这就是为什么他们指向同一个对象。

改为使用实例属性:

class A(object):
    def __init__(self):
        self.v = []     #different for each instance
a= A()
b = A()
print a is b  #prints False