【问题标题】:Why Does List Argument in Python Behave Like ByRef?为什么 Python 中的 List 参数表现得像 ByRef?
【发布时间】:2009-10-09 03:14:43
【问题描述】:

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

【问题讨论】:

    标签: python reference argument-passing object-reference


    【解决方案1】:

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

    这是要记住的重要事项:

    对象不是通过引用传递的——对象引用是通过值传递的

    由于您拥有引用的副本,因此对该引用所指向的内容的任何操作都将就像您持有原始引用本身一样。

    【讨论】:

    • 人们经常想知道按引用传递和按值传递引用的区别是什么。不同之处在于,当您通过引用传递 x 时,“x = new_value”将更改被调用者变量的值(其中 x 是参数名称)。这在 Python(或 Andrew 提到的其他语言)中不会发生,这就是为什么我们不说它们通过引用传递。
    • 啊,我明白了。那么这与指针有什么关系吗?
    【解决方案2】:

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

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

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

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

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

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

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

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

    你能看出这两个函数之间的区别吗?一个是重新绑定 barename alist -- 对任何东西都没有任何影响。另一种方法是改变(改变、改变……)它作为参数接收的列表对象——通过将其内容设置为一个单项列表,其中一个 int 作为其唯一项。 完全,完全不同的东西!!!

    【讨论】:

    • 在 C# 中,结构不是通过引用传递的。每次分配时都会创建一个副本。
    • @recursive,当然,但列表不是结构。
    • 我知道,但我只是想说我认为你的第一句话太笼统了。虽然它适用于原始问题,但它是正确的。
    • @recursive,你是对的,我确实编辑了在 C# &c 的异常/并发症中提到盒装类型的答案——Python 没有,Java 有一些,C# 有更多,参数传递规则的此类例外/并发症!-)
    【解决方案3】:

    要添加到安德鲁的答案,如果您想保留原始列表,则需要明确制作列表的副本。您可以使用copy 模块来执行此操作,或者只是执行类似

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

    由于复制对象通常意味着性能下降,我发现在我的大型项目中明确使用复制模块很有帮助。这样一来,我就可以轻松找到所有需要使用更多内存的地方。

    【讨论】:

      猜你喜欢
      • 2012-07-19
      • 2012-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-14
      • 2016-09-04
      • 1970-01-01
      • 2015-12-10
      相关资源
      最近更新 更多