【问题标题】:Python function is changing the value of passed parameterPython函数正在改变传递参数的值
【发布时间】:2014-05-31 14:07:45
【问题描述】:

这是我开始的一个例子

mylist = [["1", "apple"], ["2", "banana"], ["3", "carrot"]]

def testfun(passedvariable):
    for row in passedvariable:
        row.append("Something else")
    return "Other answer"


otheranswer = testfun(mylist)
print mylist

我希望mylist 没有改变。

然后我尝试删除该临时列,但没有奏效:

mylist = [["1", "apple"], ["2", "banana"], ["3", "carrot"]]

def testfun(passedvariable):
    for row in passedvariable:
        row.append("Something else")

    # I'm now finished with the "Something else" column, so remove it
    for row in passedvariable: row = row[:-1]
    return "Other answer"


otheranswer = testfun(mylist)
print mylist

我想尝试使用不同的参考:

mylist = [["1", "apple"], ["2", "banana"], ["3", "carrot"]]

def testfun(passedvariable):
    copyofdata = passedvariable
    for row in copyofdata:
        row.append("Something else")

    # I'm now finished with the "Something else" column, so remove it
    for row in copyofdata: row = row[:-1]
    return "Other answer"


otheranswer = testfun(mylist)
print mylist

我已经写了几个月的小 Python 脚本,但以前从未遇到过。我需要了解什么,以及如何将列表传递给函数并临时对其进行操作(但保持原件不变?)。

【问题讨论】:

  • copyofdata 不是该列表的副本,它只是对同一列表的另一个引用。
  • 其他答案 = testfun(mylist[:])。这是在发送之前复制列表的 Pythonesque 方式
  • testfun(list(mylist))

标签: python parameter-passing


【解决方案1】:

Python 通过共享传递所有内容(作为值传递的引用,请参阅call by sharing),但是集成的数字和字符串类型是不可变的,因此如果您更改它们,引用的值将被更改,而不是对象本身。对于像列表这样的可变类型,制作一个副本(例如list(passedvariable))。如果您正在修改列表中的可变对象(只能包含引用!),您将需要执行深层复制,这样做使用

import copy
copy.deepcopy(passedvariable)

参见https://docs.python.org/2/library/copy.html(Python 2.6 起可用)

请注意,由于引用本身是按值传递的,因此您不能将作为参数传递的引用更改为指向函数外部的其他内容(即,passedvariable = passvariable[1:] 不会更改在函数外部看到的值) .一个常见的技巧是传递一个包含一个元素的列表并更改该元素。

【讨论】:

  • 或者更确切地说,赋值和在可变值上调用变异方法是有区别的。 row.append("Something else")row = row + ["Something else"] 不同;第一个修改绑定到row 的可变对象;第二个只是让row 引用一个不同的对象,而row 引用的原始列表保持不变。
  • 是的,这就是我对最后一部分的理解
  • 不,Python只有传值。
  • @newacct 对不起,你错了。它与 C++ 中的引用传递有点不同,因为赋值将重新绑定引用,而不是更改引用指向的值。这可能会令人困惑,但它通过引用传递,实际上是Python中传递参数的唯一方法,没有按值传递。
  • @Joe:你熟悉 Java 语言吗? Python 中赋值和传递的语义与 Java 中的完全相同,并且可以在 Internet 或 Stack Overflow 上查看任何地方,并且 Java 被普遍描述为仅按值传递。必须在不同语言中一致地使用术语。
【解决方案2】:

函数外的mylistpassedvariable 是同一个列表对象。因此,更改列表无处不在。第三个示例中的copyofdata 也是如此。它不是副本,而是相同的列表对象。要进行复制,您必须显式复制列表,在您的情况下,您甚至必须复制列表的每个元素,因为它们也是列表对象。 现在看第二个例子row = row[:-1]:在这里你复制一个列表,除了最后一个元素。所以之前的row并没有改变,而是绑定了一个新的列表对象,同名row

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多