类中的python列表范围

类中的python列表范围,python,python-3.x,Python,Python 3.x,我遇到了一些与此代码有关的意外行为: from pprint import pprint class a (object): x = ['1'] class b (a): x = a.x x.append('2') class c (a): x = a.x x.append('3') class d (a): x = a.x x = 'nothing' if __name__ == '__main__': pprint(a

我遇到了一些与此代码有关的意外行为:

from pprint import pprint

class a (object):
    x = ['1']

class b (a):
    x = a.x
    x.append('2')

class c (a):
    x = a.x
    x.append('3')

class d (a):
    x = a.x
    x = 'nothing'

if __name__ == '__main__':
    pprint(a.x)
    pprint(b.x)
    pprint(c.x)
    pprint(d.x)
我收到输出:

['1', '2', '3']
['1', '2', '3']
['1', '2', '3']
'nothing'
但我希望得到:

['1']
['1', '2']
['1', '3']
'nothing'
我不明白的是:

  • 为什么附加到类b中的列表也会附加到类a中的列表
  • 为什么在c类中附加到该列表会同时附加到b和a
  • 为什么不将该变量重新分配给类d中的字符串对其他3个类没有影响
  • 你的线路

    class b (a):
        x = a.x
    
    a.x
    创建另一个“名称”,即
    x
    (在该范围内),但它们是相同的对象。如果您附加到
    x
    ,您也将附加到
    a.x
    ——它将附加到同一个对象

    你唯一能做不同事情的地方就是

    x = 'nothing'
    
    现在将
    x
    绑定到另一个对象,即字符串


    如果您将代码更改为

    class b (a):
        x = a.x.copy()
    
    您将得到不同的行为:这意味着
    x
    现在是列表副本的“名称”,即
    a.x

    您的行

    class b (a):
        x = a.x
    
    a.x
    创建另一个“名称”,即
    x
    (在该范围内),但它们是相同的对象。如果您附加到
    x
    ,您也将附加到
    a.x
    ——它将附加到同一个对象

    你唯一能做不同事情的地方就是

    x = 'nothing'
    
    现在将
    x
    绑定到另一个对象,即字符串


    如果您将代码更改为

    class b (a):
        x = a.x.copy()
    

    您将得到不同的行为:这意味着
    x
    现在是列表副本的“名称”,即
    a.x

    1。2.在执行
    x=a.x
    操作时,您只是将
    x
    赋值为指向唯一现有的列表,即
    a
    中的列表,因此在
    x
    上操作时,这会反映在
    a.x
    上,因为这是相同的列表,而不是副本。这对于
    b类
    c类
    都是正确的。复印

    x = list(a.x)
    

    3.当执行
    x='nothing'
    时,您将一个字符串分配到
    x
    中,该字符串不再指向列表,只指向列表。2.在执行
    x=a.x
    操作时,您只是将
    x
    赋值为指向唯一现有的列表,即
    a
    中的列表,因此在
    x
    上操作时,这会反映在
    a.x
    上,因为这是相同的列表,而不是副本。这对于
    b类
    c类
    都是正确的。复印

    x = list(a.x)
    

    3.在执行
    x='nothing'
    时,您将字符串分配到
    x
    中,而该字符串不再指向列表,只是这可能是新Python开发人员最难理解的事情之一,当他们最终理解时,它将成为真正的顿悟。你所拥有的与以下没有区别:

    >>> x = [1]; print(x)
    [1]
    
    >>> y = x; print(x); print(y)
    [1]
    [1]
    
    >>> y.append(2); print(x); print(y)
    [1, 2]
    [1, 2]
    
    >>> z = x; z = 'nothing'; print(x); print(y); print(z)
    [1, 2]
    [1, 2]
    nothing
    
    之所以这样做,是因为在Python中,一切都是对象,而变量只是对象的绑定

    因此
    x=[1]
    创建对象
    [1]
    ,并将
    x
    变量绑定到该对象

    然后执行
    y=x
    操作时,不会创建新对象,它只是将
    y
    绑定到现有对象。这意味着
    x
    y
    现在都绑定到同一个对象,因此,当您执行修改对象的操作时,例如
    x.append()
    ,将同时影响
    x
    y

    这不会发生在
    z=x时;z='nothing'
    因为第二步是创建一个新对象并将
    z
    绑定到它,这样
    x/y
    z
    现在就绑定到不同的对象

    以下两种情况都不会发生这种情况:

    z = x[:]
    z = [item for item in x]
    
    因为这两个对象也会创建一个新对象(原始对象(1)的副本),将
    x
    z
    分开

    通过检查每个变量的id(可能是您应该使用
    id
    的唯一原因)可以看到效果,为了可读性,删除了公共前缀:

    >>> print(id(x)); print(id(y)); print(id(z))
    49864
    49864
    53808
    
    您可以看到
    x
    y
    是相同的对象,而
    z
    则不同


    (1) 请记住,如果您的数据结构足够复杂,您可能需要进行深度复制,例如(添加注释):


    对于新的Python开发人员来说,这可能是最难理解的事情之一,当他们最终理解时,这将成为真正的顿悟。你所拥有的与以下没有区别:

    >>> x = [1]; print(x)
    [1]
    
    >>> y = x; print(x); print(y)
    [1]
    [1]
    
    >>> y.append(2); print(x); print(y)
    [1, 2]
    [1, 2]
    
    >>> z = x; z = 'nothing'; print(x); print(y); print(z)
    [1, 2]
    [1, 2]
    nothing
    
    之所以这样做,是因为在Python中,一切都是对象,而变量只是对象的绑定

    因此
    x=[1]
    创建对象
    [1]
    ,并将
    x
    变量绑定到该对象

    然后执行
    y=x
    操作时,不会创建新对象,它只是将
    y
    绑定到现有对象。这意味着
    x
    y
    现在都绑定到同一个对象,因此,当您执行修改对象的操作时,例如
    x.append()
    ,将同时影响
    x
    y

    这不会发生在
    z=x时;z='nothing'
    因为第二步是创建一个新对象并将
    z
    绑定到它,这样
    x/y
    z
    现在就绑定到不同的对象

    以下两种情况都不会发生这种情况:

    z = x[:]
    z = [item for item in x]
    
    因为这两个对象也会创建一个新对象(原始对象(1)的副本),将
    x
    z
    分开

    通过检查每个变量的id(可能是您应该使用
    id
    的唯一原因)可以看到效果,为了可读性,删除了公共前缀:

    >>> print(id(x)); print(id(y)); print(id(z))
    49864
    49864
    53808
    
    您可以看到
    x
    y
    是相同的对象,而
    z
    则不同


    (1) 请记住,如果您的数据结构足够复杂,您可能需要进行深度复制,例如(添加注释):


    当你这样定义它的时候。用父类和每个chil初始化变量x