为什么Python在Class命名空间中以不同方式处理列表和整数?

时间:2012-12-17 17:09:38

标签: python class namespaces

这两个类定义的结构相同,除了在奇怪的()类定义中,属性'd'是一个列表,而在normal()类定义中它是一个int。我不明白为什么奇怪的()类导致self.d = d,而类normal()不是这种情况。为什么Python会在这种情况下处理int和列表?

class weird:
    def __init__(self):
        d = [1,2,3]
        self.d = d
        for x in range(3):
            d[x] = 10+x 
        print "d =", d
        print "self.d =", self.d

class normal:
    def __init__(self):
        d = 1
        self.d = d
        d = 11
        print "d =", d
        print "self.d =", self.d

当我运行代码时,我得到了

>>> a=weird()
d = [10, 11, 12]
self.d = [10, 11, 12]
>>> b=normal()
d = 11
self.d = 1

4 个答案:

答案 0 :(得分:7)

你正在混淆对象的变异。

在一种方法中,您为d分配了新值,更改了指向的内容:

d = 11

但在另一种方法中,您更改了d包含的值:

d[x] = 10 + x

注意那里的[x];从本质上讲,你是在告诉python这样做:

d.__setitem__(x, 10 + x)

指向列表的变量d的值永远不会更改。 d引用的列表中的值确实会发生变化。

看看我之前的这个答案,它更详细地说明了这两个陈述之间的区别:Python list doesn't reflect variable change

答案 1 :(得分:2)

事实上,这里的语言完全一致。您正在观察两种不同的行为,因为您正在执行两种根本不同的操作。

__init__的前两行在两个类中都是一致的(d的不同类型除外):

class WeirdOrNormal:
    def __init__(self):
        d = ... # 1 or [1, 2, 3]
        self.d = d

此时,dself.d都指向同一个对象。

然而,在那之后,两个班级分歧:

  1. weird通过引用修改对象:

    for x in range(3):
        d[x] = 10+x 
    

    由于dself.d都指向同一个对象,因此可以通过两者来观察更改。

  2. normal重新绑定d指向self.d以外的其他地方:

    d = 11
    

    通过这样做,您已经打破了dself.d之间的链接。他们现在完全独立。

  3. 如果您要更改weird以重新引用引用,就像normal那样,您会看到这两个类的行为一致:

    class notweird:
        def __init__(self):
            d = [1,2,3]
            self.d = d
            d = [10+x for x in self.d]
            print "d =", d
            print "self.d =", self.d
    
    a = notweird()
    

    打印

    d = [11, 12, 13]
    self.d = [1, 2, 3]
    

答案 2 :(得分:1)

对于文档:

  

值可以改变的对象被认为是可变的;对象的   一旦创建它们,值就不可更改,称为不可变。 (该   包含对a的引用的不可变容器对象的值   当后者的值改变时,可变对象可以改变;然而   容器仍然被认为是不可变的,因为收集了   它包含的对象无法更改。所以,不变性不是   与具有不可改变的值严格相同,它更加微妙。)   对象的可变性由其类型决定;例如,   数字,字符串和元组是不可变的,而词典和   列表是可变的。

在您的情况下list是可变的,int是不可变的。没什么奇怪的。

有关Data model的更多信息。

答案 3 :(得分:0)

在第一个示例中,dself.d都指向可变对象。向对象中的元素添加10时,您正在修改该可变对象。由于dself.d都指向该对象,因此它们都“看到”了结果。

在第二个示例中,您将重新分配d以指向不同的不可变数字,因此dself.d指向两个不同的事物。

注意区别:在一种情况下,它们都指向您正在更改的相同值,而在另一种情况下,它们指向两个不同的值。