为什么Python中的列表参数与ByRef一样?

时间:2009-10-09 03:14:43

标签: python reference argument-passing object-reference

这可能适用于大多数语言,但我不确定。我是Python的初学者,一直致力于C#和VB中的列表副本。但是在Python中,只要我将列表作为参数传递并通过使用“for i in range”进行枚举,然后更改list参数的值,输入值实际上会更改原始列表。我认为Python应该默认按值传递参数,这样一旦函数完成,我在调用函数之前仍然有原始值。我错过了什么?谢谢!

3 个答案:

答案 0 :(得分:8)

Python确实按值传递参数,但是您接收的值是引用的副本(顺便说一下,这与C#,VB.NET和Java的行为完全相同)。

这是要记住的重要事项:

  

对象不通过引用传递 - 对象引用按值传递

由于您有参考文献的副本,因此对该参考文献指向的任何操作就像您自己持有原始参考文件一样。

答案 1 :(得分:4)

Python - 就像Java对原始标量所做的任何事情一样,并且像C#和VB.NET那样为默认类型参数而不是盒装类型和out / ref parms - 传递“按对象引用”(搜索那句话here - 这就是Guido,Python的架构师和创造者,用它来解释这个论证传递概念。)

每个名字都是对某个对象的引用;将名称(或任何其他表达式)作为参数传递只是创建对同一对象的另一个引用(函数体可以通过参数的名称访问)。 ((没有“对名称的引用”这样的东西: names ,它们是对象的一种引用,对象 - 句号))。

当你传递一个可变对象,即一个具有变异方法的对象(例如一个列表)时,被调用的函数可以通过直接或间接调用其变异方法来改变对象。 ((“间接”,我的意思是“通过运营商” - 例如:

somelist[len(somelist):] = [whatever]

somelist.append(whatever)完全相同。))

如果要将列表传递给函数,但希望函数能够以任何方式改变该列表,则必须传递副本列表而不是原始列表 - 就像在Java,C#,VB.NET中一样。

非常清楚重新绑定名称改变对象之间的区别。重新绑定名称(“barename”,即 - qualified-names不同;-) only 会影响名称 - NOT 任何对象任何。例如:

def f1(alist):
  alist = [23]

def f2(alist):
  alist[:] = [23]

你能发现这两个功能之间的区别吗?一个是重新绑定裸名 alist - 对任何事情都没有任何影响。另一种是通过将其内容设置为一个以int为唯一项目的单项列表来改变(更改,更改,...)它接收的列表对象。 完全,完全不同的东西!!!

答案 2 :(得分:0)

要添加到Andrew的答案,如果要保留原始列表,则需要明确复制列表。您可以使用copy模块执行此操作,或者只执行

之类的操作
a = [1,2]
b = list(a)

由于复制对象通常会影响性能,因此我发现在较大的项目中明确使用复制模块会很有帮助。这样,我可以很容易地找到我将要使用更多内存的所有地方。