在Python中追加与重新定义变量

时间:2015-10-19 20:04:42

标签: python python-2.7 append global-variables

首先,如果在其他地方已经回答了这个问题,请先道歉我的问题。我回顾了一些 Stack Overflow 建议的问题,但没有一个包含我正在寻找的答案。我也更感兴趣为什么这种情况比任何解决方法都要避免问题。我试着回答我自己的问题,但我只能将问题简化为更简单的问题。无论如何,有人可以帮我理解下面两组代码之间的区别,我可以理解不同输出的推理吗?

版本1(使用变量dog上的附加内容):

cat = [ ]
dog = [ ]
dog.append(1)
print dog # [1]
print cat # [ ]        
cat.append(dog)        
print dog # [1]
print cat # [ [1] ]
dog.append(1)
print dog # [1, 1]
print cat # [ [1, 1] ]        
dog.append(1)        
print dog # [1, 1, 1]        
print cat # [ [1, 1, 1] ]
cat.append(dog)        
print dog # [1, 1, 1]
print cat # [ [1, 1, 1], [1, 1, 1] ]

第2版(将dog重新定义为不同的列表):

cat = [ ]
dog = [ ]
dog = [1]
print dog # [1]
print cat # [ ]
cat.append(dog)
print dog # [1]
print cat # [ [1] ]
dog = [1, 1]
print dog # [1, 1]
print cat # [ [1] ]
dog = [1, 1, 1]
print dog # [1, 1, 1]
print cat # [ [1] ]
cat.append(dog)
print dog # [1, 1, 1]
print cat # [ [1], [1, 1, 1] ]

我对Python中append方法的天真理解使我期望版本1具有与版本2相同的输出。我不明白为什么追加dog会影响任何变量cat除非我通过追加或其他方式明确更改cat

4 个答案:

答案 0 :(得分:1)

在python中,将“names”视为对象的引用是有帮助的。换句话说:

cat = []

名称cat是列表实例的引用每个对象都可以有多个引用 ...

cat = tiger = []

此处cattiger引用相同的列表。

cat = []
tiger = cat

同样,cattiger引用相同的列表。

容器类型(例如list可以包含对其他对象的多个引用

cat = []
dog = [cat]

在这种情况下,dog中的第一个元素是cat引用的相同列表的引用。因此,如果我附加到cat引用的列表,dog的第一个元素引用的列表也会看到更改(因为它们引用 list)的相同实例。

当然,如何将引用放入容器中无关紧要:

cat = []
dog = []
dog.append(cat)

答案 1 :(得分:1)

将变量分配给列表时

dog = []

变量" dog"只需将引用存储到列表对象中,该列表对象位于内存中的某个位置。

如果您重新分配变量" dog"

dog = [1]

您已创建 new 列表对象,并存储了对它的引用。如果没有对它的引用,旧的列表对象将被垃圾收集(正确删除),因为它永远不会被访问。但是,您可以在另一个对象中存储对它的引用

cat.append(dog) # Stores a reference to the old list
dog = [1,1] # Defined another new list

您正在将狗插入猫而不是名称" dog",而是通过引用内存中的列表对象。现在是老狗"不是垃圾收集,因为它被cat引用。现在对狗引用的列表的更改不会影响" cat",因为这两个列表不同

答案 2 :(得分:1)

在python中,一切都是对象,并将对象视为内存位置。

当您追加时,您正在修改存储在对象中的值而不是内存位置。

当您将list dog附加到cat作为元素时,此元素也指向同一个对象。换句话说,有两个元素访问相同的对象,一个是变量' dog'和其他是猫的一个元素。因此,您对该对象所做的任何更改都会在“狗”和“狗”中显示出来。并且' cat'。这就是版本1中发生的事情。

在版本2中,在第一次追加后,您创建了一个新对象并将其分配给变量dog。现在可变的“狗”#39;和“猫”中的元素是指不同的对象。

如果您不希望对“狗”进行更改。对猫来说是可见的使用

cat.append(狗[:])

答案 3 :(得分:1)

这是许多编程语言的一个特性,而不仅仅是python。 这通常被称为通过引用传递(google it)。

在Python中,可变数据结构通常通过引用传递(例如list / dict等),而不可变数据结构(例如元组/字符串/ int)作为副本传递。 因此,在代码片段#1中,当您第一次执行cat.append(dog)时,cat现在可以引用狗列表。 (如果你来自C ++ / C背景,我可以"松散地"将它与指针的概念进行比较:不是c ++也有引用,所以我松散地说......)。

如果它仍然很复杂,请考虑cat拥有"地址" dog。如果dog发生变化,cat将发生相同的更改。

来到你的代码片段#2 ......

当您重新定义dog时,您基本上会使dog指向另一个列表。所以[1,1][1]完全是两个不同的列表。

为了进一步澄清这个概念(可变v / s不可变),尝试稍微不同的练习......

def func_mutable(dog):
    dog.append(1)

def func_immutable(strng):
    strng+="1"

dog = []
print dog #prints []
func_mutable(dog)
print dog #prints [1]

strng = "1"
print strng #prints "1"
func_immutable(strng)
print strng #still prints "1", and not "11"
函数调用后

dog更改,因为列表保存了引用,并且对引用所做的所有更改都反映在dog中(即函数的被调用者)。 strng不会改变,b / c当func_immutable执行strng+="1"时,它实际上复制了传递的参数strng,然后修改它。对 local 变量strng进行了修改,如果没有返回则丢失(在我的代码中就是这种情况)