2012-12-26 133 views
4

我有一个函数,我使用局部变量,然后在函数完成后返回最终变量。我想保留这个变量在函数前的记录,但全局变量和局部变量一起更新。下面是我的代码的缩写版本(其相当长)Python:局部变量神秘地更新全局变量

def Turn(P,Llocal,T,oflag): 
    #The function here changes P, Llocal and T then passes those values back 
    return(P, Llocal, T, oflag) 

#Later I call the function 
#P and L are defined here, then I copy them to other variables to save 
#the initial values 

P=Pinitial 
L=Linitial 
P,L,T,oflag = Turn(P,L,T,oflag) 

我的问题是,L和Linitial都更新,什么时候Llocal被更新,但我想Linitial不改变。 P不会改变,所以我对这里发生的事情感到困惑。帮帮我?谢谢!

为勇敢的人,整个代码是在这里:https://docs.google.com/document/d/1e6VJnZgVqlYGgYb6X0cCIF-7-npShM7RXL9nXd_pT-o/edit

+2

什么类型的对象?你能给出一个完整的,自包含的可运行的例子来证明你看到了什么吗? –

+0

P是一个整数,L是一个列表。 T也是一个整数,oflag是一个布尔值。我只通过IDLE的调试器发现了这个问题,它非常微妙。如果我显示全局变量和局部变量,我会看到L,Linitial和Llocal全部三个同时变化。我可以在这里上传整个代码,但是它有几百行。我现在担心的部分现在开始于190和57左右。目前它从第66行引发错误,但错误的根源是此变量更新。 – mykinz

+0

请注意[PEP-8](http://www.python.org/dev/peps/pep-0008/)建议为类名保留'CapWords'。 –

回答

1

列表是可变的。如果您将一个列表传递给一个函数,并且该函数修改了该列表,那么您将能够看到绑定到同一个列表的任何其他名称的修改。

要解决该问题,尝试修改此行:

L = Linitial 

这样:

L = Linitial[:] 

这片使得列表的浅表副本。如果您添加或删除存储在L列表中的项目,它将不会更改列表Lintial

如果要制作深度复制,请使用copy.deepcopy


P也不会发生同样的情况,因为它是一个整数。整数是不变的。

+0

我试过使用copy.deepcopy和L = Linitial [:]但我仍然像以前一样得到相同的错误。我正在通过调试器完成它,当我看到发生了什么时,我会回复。谢谢! – mykinz

+0

它现在可以工作!实际上我不得不两次做一个浅拷贝,当我定义Linitial和当我重新定义L.谢谢! – mykinz

2

的问题是,P和L是namesboundobjects,不重视自己。当你将它们作为参数传递给一个函数时,实际上是将一个绑定的副本传递给P和L.这意味着,如果P和L是可变对象,对它们所做的任何更改都将在函数调用之外可见。

您可以使用copy模块保存名称值的副本。

+0

作为一个说明,'copy'是一个模块,而不是一个函数。 –

+0

我认为这种情况下,函数接收到一个指针并在同一个对象上运行的初始值就足够了。然而,不可变对象通常在赋值时被复制隐含(例如数字和字符串),而可变对象将同一个指针分配给新名称,因此您有两个引用同一实例的名称。 –

+0

@ Nisan.H Python语言没有“指针”的概念,所以这没有用(尽管cPython,实现,使用指针)。而不可变对象不是“在赋值时复制”的。这个名字只是重新绑定到分配给的任何东西。 – jknupp

0

在Python中,变量只是对内存中对象或值的引用。例如,当你有一个清单x

x = [1, 2, 3] 

所以,当你将x另一个变量,我们称之为y,你只是创建一个新的参考(y)由x引用的对象( [1, 2, 3]列表)。

y = x 

当您更新x,你实际上是在更新由x所指向的对象,即列表[1, 2, 3]。由于y引用相同的值,它似乎也被更新。

请记住,变量只是对象的引用。

如果你真的想复制一个列表,你务必做好:

new_list = old_list[:] 

这里有一个很好的解释:http://henry.precheur.org/python/copy_list