Python:本地变量神秘地更新全局变量

4
我有一个函数,在其中使用局部变量,然后在函数完成后传回最终变量。我想要记录下函数执行前该变量的值,但全局变量也会随着局部变量的更新而更新。以下是我代码的简化版本(它相当长)。
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)

我的问题是,当Llocal被更新时,L和Linitial都被更新了,但我希望Linitial不改变。P没有改变,所以我对这里发生的事情感到困惑。能帮忙吗?谢谢!
勇敢的人可以在这里找到整个代码:https://docs.google.com/document/d/1e6VJnZgVqlYGgYb6X0cCIF-7-npShM7RXL9nXd_pT-o/edit

2
对象有哪些类型?您能否提供一个完整的、自包含的可运行示例来演示您所看到的内容? - Mark Byers
P是一个整数,L是一个列表。T也是一个整数,oflag是一个布尔值。我只是通过IDLE的调试器发现了这个问题,它非常微妙。如果我显示全局和局部变量,我会看到L、Linitial和Llocal三个变量同时改变。我可以在这里上传整个代码,但它有几百行。我现在担心的部分从190和57开始。目前它会从第66行抛出一个错误,但错误的根本原因是这个变量的更新。 - mykinz
请注意,PEP-8 建议将 CapWords 保留给类名。 - Gareth Latty
1
@user1930726 请提供一个简短但可运行的示例,展示该问题。 - Gareth Latty
下次请使用http://pastebin.com/或类似工具来分享您的代码。 :) - Valdir Stumm Junior
3个回答

2
问题在于 P 和 L 是绑定到对象而不是值本身的名称。当您将它们作为参数传递给函数时,实际上是传递了 P 和 L 的绑定副本。这意味着,如果 P 和 L 是可变对象,则对它们所做的任何更改都将在函数调用外可见。
您可以使用 copy 模块保存名称的值的副本。

作为一条注释,copy 是一个模块,而不是一个函数。 - Gareth Latty
我认为在这种情况下,理解函数接收指针并且对与初始对象相同的对象进行操作就足够了。然而,不可变对象通常在赋值时隐式复制(例如数值和字符串),而可变对象将相同的指针分配给新名称,因此您有两个名称引用同一实例。 - Nisan.H
@Nisan.H Python语言本身没有指针的概念,因此这并不实用(尽管实现中的cPython确实使用了指针)。而且不可变对象在赋值时并不会被“复制”。名称只是重新绑定到被分配的任何内容。 - jeffknupp

1
列表是可变的。如果您将一个列表传递给一个函数,并且该函数修改了列表,则您将能够从绑定到同一列表的任何其他名称中看到修改。
为解决问题,请尝试更改此行:
L = Linitial

转换为:

L = Linitial[:]

这个切片会对列表进行浅拷贝。如果您在存储在L中的列表中添加或删除项目,它不会更改Lintial列表。

如果您想进行深层复制,请使用{{link1:copy.deepcopy}}。


这种情况在 P 中不会发生,因为它是一个整数。整数是不可变的。

我已经尝试使用copy.deepcopy和L = Linitial[:],但我仍然得到与之前相同的错误。我正在使用调试器解决问题,看到发生了什么后我会回复。谢谢! - mykinz
现在它能运行了!实际上我必须进行两次浅复制,一次是在定义Linitial时,另一次是在重新定义L时。谢谢! - mykinz

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接