我试图理解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]

请参见:如何通过引用传递变量?


当前回答

F实际上不会改变x的值(它总是对列表实例的相同引用)。相反,它改变了这个列表的内容。

在这两种情况下,都会将引用的副本传递给函数。在函数内部,

N被赋一个新值。只修改函数内部的引用,而不修改函数外部的引用。 X不会被赋一个新值:函数内部和外部的引用都不会被修改。相反,x的值被修改了。

由于函数内部和外部的x都指向相同的值,所以两者都看到了修改。相比之下,函数内部和外部的n指的是在函数内部重新赋值n后的不同值。

其他回答

N是一个int(不可变),并且一个副本被传递给函数,因此在函数中您正在更改副本。

X是一个列表(可变),指针的副本被传递给函数,因此x.a pend(4)改变了列表的内容。然而,你在你的函数中说x =[0,1,2,3,4],你不会在main()中改变x的内容。

Python is copy by value of reference. An object occupies a field in memory, and a reference is associated with that object, but itself occupies a field in memory. And name/value is associated with a reference. In python function, it always copy the value of the reference, so in your code, n is copied to be a new name, when you assign that, it has a new space in caller stack. But for the list, the name also got copied, but it refer to the same memory(since you never assign the list a new value). That is a magic in python!

我将重命名变量以减少混乱。N -> nf或nmain。X -> xf或xmain:

def f(nf, xf):
    nf = 2
    xf.append(4)
    print 'In f():', nf, xf

def main():
    nmain = 1
    xmain = [0,1,2,3]
    print 'Before:', nmain, xmain
    f(nmain, xmain)
    print 'After: ', nmain, xmain

main()

当你调用函数f时,Python运行时生成一个xmain的副本并将其赋值给xf,类似地,将nmain的副本赋值给nf。

在n的情况下,复制的值是1。

对于x,复制的值不是文本列表[0,1,2,3]。它是对那个列表的参考。Xf和xmain都指向同一个列表,所以当你修改Xf时,你也在修改xmain。

然而,如果你要写这样的东西:

    xf = ["foo", "bar"]
    xf.append(4)

您会发现xmain没有改变。这是因为,在行xf = ["foo", "bar"]中,您更改了xf以指向一个新的列表。对这个新列表所做的任何更改都不会对xmain仍然指向的列表产生影响。

希望这能有所帮助。: -)

F实际上不会改变x的值(它总是对列表实例的相同引用)。相反,它改变了这个列表的内容。

在这两种情况下,都会将引用的副本传递给函数。在函数内部,

N被赋一个新值。只修改函数内部的引用,而不修改函数外部的引用。 X不会被赋一个新值:函数内部和外部的引用都不会被修改。相反,x的值被修改了。

由于函数内部和外部的x都指向相同的值,所以两者都看到了修改。相比之下,函数内部和外部的n指的是在函数内部重新赋值n后的不同值。

有些答案在函数调用的上下文中包含“复制”一词。我觉得很困惑。

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中的名称之间的区别。