Is list pass by value or by reference?
考虑下面的代码,乍一看它做的是相同的事情,但结果不同,有时它似乎列表是传递值,有时列表似乎是传递引用:
1 2 3 4 5 6 7 8
| lst = [1, 2]
def f(lst):
# lst = lst + [3] # seems pass by value
# lst += [3] # strange! same as above but seems pass by reference
lst = lst.append(3) # seems pass by reference
return lst
f(lst)
print(lst) |
有人能告诉我发生了什么事吗?
- 型区别在于赋值,而不是传递语义。
- 型请参阅stackoverflow.com/questions/575196
- 型我想你现在已经有了所有的链接。我只是建议在有些地方印上id(name),当你有这样的疑问的时候。
- 型python没有引用和指针的概念。它的工作方式是可变对象(如lists和dicts)作为引用传递,而所有其他对象都是按值传递的。
- 型@马蒂诺那不是真的。对于任何类型的对象,评估策略都是完全相同的。
- 型答案是Python既不使用评估策略,也不使用共享调用,这是Java、露比、JavaScript等使用的完全相同的评估策略。另一件事是,在某些情况下,您使用的是Mutor方法,而另一些则不是,因此列表连接操作符EDCOX1 3总是创建并返回副本。增广分配+=修改到位,.append也修改到位。
- 型@马蒂诺:Python名称是一个引用。将名称传递给函数时,将使用形参名称在本地函数的作用域中创建一个新名称,该名称指向与函数调用参数相同的对象。我看到它被称为"共享参考"。它不会复制对象。总是这样。这与总是复制值或引用副本的C不同。然后(在python中)对象可以是可变的或不可变的。可变的可以在适当的地方改变。但赋值总是创建一个新对象。
- 型@progmatico erm,赋值从不创建新对象。埃多克斯1〔6〕
- 型顺便说一下@juanpa.arrivilaga有没有这个规范的名字,每个人看起来都用了一个稍微不同的名字。
- 型@编程井芭芭拉·利斯科夫(BarbaraLiskov)首先把CLU描述为"共享呼叫",但它从未真正起飞过。它在不同的社区有不同的名字。我认为"按任务呼叫"可能是一个很好的方法,但我已经放弃了希望,希望在社区之间达成任何协议。
- 型关键阅读:nedbatchelder.com/text/names.html为了理解python相对简单的语义,只需阅读链接,不用担心"按值调用"和"按引用调用"。
- 型好啊。我指的是以前用过的名字。
- 型我指的是在函数内部分配一个参数名,将其重新绑定到右侧的不同对象,如果您没有保留对它的另一个引用,那么您将失去对原始对象的访问,至少使用该名称。"但是,赋值总是创建一个新对象"是完全错误的。但我从没想过这样的事。
- 型我在想它和一个不同的本地对象绑定在一起。我想我是这样写的,因为当你分配一个不变的,而你认为你改变了原始的(因此不同的值,和可能的新对象)。
- 型赋值不"创建"任何东西(如果不重复使用,则名称本身除外),实际上您甚至不知道右侧的不可变项是新的还是相同值的重复使用对象。但是"总是绑定到不同的对象"肯定更好。请注意,这当然不考虑变量的增广赋值。
- 型我也相信@martineau比他自己的话更清楚…
型
它是通过引用值传递的。因此,对对象的修改可以在函数外部看到,但是将变量分配给新对象不会改变函数外部的任何内容。
它与在C中传递指针或Java中的引用类型基本相同。
+=情况的结果是因为该运算符实际上在适当的位置修改了列表,所以效果在函数之外是可见的。lst.append()也是一个就地操作,这解释了您最后一个案例。