我怀疑您希望原始代码能够正常工作的原因是因为您更熟悉使用 C++ 等语言传递引用。重要的是要注意按引用传递和按值传递的区别。了解使用的是哪一种 Python 更为重要。
简而言之,Python 实际上既不使用按引用传递,也不使用按值传递;传递是通过Python 中的对象完成的。
长答案:
可以使用 C进行值传递的示例:
#include <stdio.h>
void adding(int i) {
i = i + 1;
}
int main() {
int i = 0;
adding(i);
printf("i is %d\n", i); // will print "i is 0"
return 0;
}
这里, i 的值在传递给 时被复制adding()
。int i
inside
与原始insideadding(int i)
位于不同的内存位置。所以 inside ,只影响仅在 范围内已知的内存块中的值,in完全
不受影响,因为它驻留在不同的内存块中。int
i
main()
adding()
i = i + 1
adding()
i
main()
可以使用 C++ 进行引用传递的示例:
#include <iostream>
void adding(int &i) {
i = i + 1;
}
int main() {
int i = 0;
adding(i);
std::cout << "i is " << i << std::endl; // will print "i is 1"
return 0;
}
这里i
是通过引用传递的adding()
。i
inside指的是与inadding()
完全相同的内存块。因此,将递增到 1。i
main()
i
现在,让我们回到您的示例来讨论 Python(我通过猜测您的实际意思来修改 =]):
# Case 1
mylist = [1,2,3,4]
mylist.append(5) # will print [1,2,3,4,5]
# Case 2
mylist = [1,2,3,4]
def adding(mylist):
mylist.append(5)
adding(mylist)
print mylist # will print [1,2,3,4,5]
# Case 3
mylist = [1,2,3,4]
def adding(mylist):
mylist = mylist + [5]
adding(mylist)
print mylist # will print [1,2,3,4]
# Case 4
mylist = [1,2,3,4]
def adding(mylist):
mylist += [5]
adding(mylist)
print mylist # will print [1,2,3,4,5]
在这里,mylist
既不是通过值传递,也不是通过引用传递。它实际上是由对象传递的。
在 Python 中,mylist = [1,2,3,4]
创建一个列表[1,2,3,4]
并为其附加
标签
mylist
。这里要注意的重要一点是 list 是一个
对象(IIRC,每个对象都是它的一个PyObject
或一个扩展)。
了解这种区别将使您能够理解示例案例中的输出:
在案例 1中,直接.append()
在[1,2,3,4]
列表对象上调用以更改列表值,因此myobject
附加到的对象已更改。请注意,这也是可能的,因为列表是 Python 中的可变对象。
在Case 2中,mylist
在传递到 时不会被复制adding()
,它仍然“附加”到同一个列表对象,类似于Case 1。因此,调用
.append()
这个对象将改变对象本身。在 之外
adding()
,因为mylist
仍然附加到同一个对象(即使对象已经改变了自己),我们得到输出 [1,2,3,4,5]。
在案例 3中,在内部adding()
,局部变量mylist
附加到由[1,2,3,4]+[4]
. 但是原始mylist
指向的对象从未改变过,因此,输出仍然是
[1,2,3,4]
.
案例 4有点棘手。在 Python 中,列表是可变的,+=
充当类似 的快捷方式.extend()
,它作用于调用对象本身。因此,原始对象已被修改[1,2,3,4,5]
并mylist
仍然附加到它。可能还值得注意的是,对于元组、字符串和数字等不可变对象,+=
将创建一个新对象并将变量附加到它上面。
至于在 Python 中使用列表的不同方式,Fredrik Lundh 撰写的这篇文章包含了非常详尽的信息。