我试图理解Python对变量作用域的方法。在这个例子中,为什么f()能够改变x的值,就像main()所感知的那样,但不能改变n的值?
def f(n, x):
n = 2
x.append(4)
print('In f():', n, x)
def main():
n = 1
x = [0,1,2,3]
print('Before:', n, x)
f(n, x)
print('After: ', n, x)
main()
输出:
Before: 1 [0, 1, 2, 3]
In f(): 2 [0, 1, 2, 3, 4]
After: 1 [0, 1, 2, 3, 4]
请参见:如何通过引用传递变量?
有些答案在函数调用的上下文中包含“复制”一词。我觉得很困惑。
Python永远不会复制你在函数调用期间传递的对象。
函数参数是名称。当你调用一个函数时,Python将这些参数绑定到你传递的任何对象(通过调用者作用域中的名称)。
对象可以是可变的(如列表),也可以是不可变的(如Python中的整数和字符串)。一个可以改变的可变对象。您不能更改名称,只能将其绑定到另一个对象。
你的例子不是关于作用域或命名空间,而是关于Python中对象的命名、绑定和可变性。
def f(n, x): # these `n`, `x` have nothing to do with `n` and `x` from main()
n = 2 # put `n` label on `2` balloon
x.append(4) # call `append` method of whatever object `x` is referring to.
print('In f():', n, x)
x = [] # put `x` label on `[]` ballon
# x = [] has no effect on the original list that is passed into the function
这里有一些漂亮的图片,展示了其他语言中的变量和Python中的名称之间的区别。
如果用完全不同的变量重写函数,并且我们对它们调用id,那么它就很好地说明了这一点。我一开始不明白这一点,读了jfs的帖子和很好的解释,所以我试着理解/说服自己:
def f(y, z):
y = 2
z.append(4)
print ('In f(): ', id(y), id(z))
def main():
n = 1
x = [0,1,2,3]
print ('Before in main:', n, x,id(n),id(x))
f(n, x)
print ('After in main:', n, x,id(n),id(x))
main()
Before in main: 1 [0, 1, 2, 3] 94635800628352 139808499830024
In f(): 94635800628384 139808499830024
After in main: 1 [0, 1, 2, 3, 4] 94635800628352 139808499830024
Z和x有相同的id。就像文章所说的那样,不同的标签对应相同的底层结构。