我原本期望以下代码:
def a(l):
l.append(3)
def b(l):
l = 5
def c(l):
l = (2,-2)
numbers = [1,2,3,4,5]
a(numbers)
print(numbers)
b(numbers)
print(numbers)
c(numbers)
print(numbers)
打印:
[1, 2, 3, 4, 5, 3]
5
(2,-2)
但它打印出来:
[1, 2, 3, 4, 5, 3]
[1, 2, 3, 4, 5, 3]
[1, 2, 3, 4, 5, 3]
为什么?
编辑:
这是因为通过引用传递和通过共享调用之间的区别!
答案 0 :(得分:3)
我认为这是因为Python(如C和Java)有效地传递值。对于a()
函数,您按值传递引用。那里没有通过引用传递。
传递传递别名,它具有与通过引用传递类似的行为。
我已经看到计算机科学教授错误地声称Objective-C通过引用传递,因为教科书是这样说的,没有经过考虑。但它仍然只是值得传递。
答案 1 :(得分:2)
第一种方法(a
)实际上正在修改通过l.append(...)
传递的列表项
第二种和第三种方法(b
和c
)将参数l
重新分配给新值。此重新分配是函数的本地,并且不会返回,因此它将丢失。在执行numbers
和b(numbers)
后打印c(numbers)
时,您将打印由方法a
修改的值。
答案 2 :(得分:1)
Python中的大多数值都是不可变的,这意味着它们无法更新。这意味着变量的值不能改变。但是,可以将参考点设置为新的(不可变的)值。因此,在写作时
i = 4
i = 5
你实际上是首先使i
指向(不可变值)4,然后将i
指向(同样不可变的)值5。
L = [3,4]
L.append(5)
并使用新值[3, 4, 5]
更新相同的引用对象。
调用函数时,例如, i
和L
不会直接传递给该函数。而是传递对值的引用。原始引用也保存在调用环境中,以便在被调用函数返回时进行恢复。
查看您的功能意味着:
def a(l):
l.append(3)
此处,引用l
未更改/更新,因为append将更改引用内容的值。因此,当从函数l
返回时,将“恢复”到与函数中使用的值相同的值,并更新列表。
def b(l):
l = 5
def c(l):
l = (2,-2)
然而,在这两个函数中,由于赋值,引用l
被指向新的东西。因此我们修改了引用本身。然后,返回时,将恢复引用以指向调用范围中使用的值。因此,l
将再次成为原始列表,并且函数中使用的引用值将超出范围,该引用指向的任何值都将丢失/删除。
因此,这不仅仅是语义上的区别,而是引用或称为引用或通过共享调用,这必须做具有类型的不变性以及引用如何在Python中工作。