传递给函数时列表会发生啥?
Posted
技术标签:
【中文标题】传递给函数时列表会发生啥?【英文标题】:What happen to a list when passed to a function?传递给函数时列表会发生什么? 【发布时间】:2015-09-21 17:05:40 【问题描述】:我试图了解将列表作为参数传递给函数时如何处理。所以我做了以下事情:
我初始化了一个列表:
ll = [1,2,3,4]
并定义一个函数:
def Foo(ar):
ar += [11]
我将列表传递给函数:
Foo(ll)
当我打印出来时,我得到了:
print ll # [1, 2, 3, 4, 11] #case(1)
到目前为止一切顺利。
现在我修改了函数以重置列表,使其只有一个元素:
def Foo(ar):
ar = [11]
我想起了语法:
Foo(ll)
当我重新打印它时,它产生了相同的列表:
print ll # [1, 2, 3, 4] # case(2)
我以为列表是作为参考传递的;所以无论我们对函数内部的列表做什么,都会改变从主程序传递的原始函数。所以对于 case(2) 我期待以下结果:
print ll # [11] # case(2) expected result
我错过了什么吗?
【问题讨论】:
ar = [11]
将名称分配给一个完全不同的对象。如果要替换列表的全部内容,请尝试ar[:] = [11]
。
我发现您选择的名称和值(ll
和 11
)令人不安......
很抱歉选择了名称和值。
【参考方案1】:
ar += [11]
不只是一个任务。这是一个方法调用(调用的方法是:__iadd__
)。当 Python 执行该行时,它会调用该方法,然后将 ar
分配给结果。 list
的__iadd__
方法修改当前的list
。
ar = [11]
是一个赋值,因此它只是更改本地名称ar
的值。但是函数内部的ar
名称和ll
变量的值之间没有联系。
你可能想要这样的东西:
ar[:] = [11]
【讨论】:
严格来说ar += [11]
其实还是一个赋值;它需要像ar = (1, 2, 3); ar += (11,)
这样的东西才能工作。
@user2357112 你说得对,我过于简单化了。已修改。
感谢您的帮助。我想我现在明白了。
这正是我需要的:ar[:] = [11]【参考方案2】:
您必须区分对象和对象的名称。 Python 中的列表是可变对象,因此只要您引用它,就可以更改它们。
名称只是对对象的引用。请记住,从技术上讲,Python 中没有变量,只有名称和对象,并且对象与名称绑定。
因此,考虑到这一点,让我们看看您的代码:
def Foo1(ar):
ar += [11]
此函数获取一个列表,将其绑定到本地名称ar
,然后修改该列表,添加一个新值。
但是这个其他代码:
def Foo2(ar):
ar = [11]
此函数获取一个列表,绑定到名称ar
,然后将名称ar
重新绑定到具有一个值的新列表。在这个函数内部,原始对象是未修改和模糊的。
那么当你这样做时:
a = [1,2,3]
然后调用:
Foo1(a)
修改列表添加一个新值,但是:
Foo2(a)
对a
的值没有任何作用。
如果你想编写一个函数来替换列表中的所有内容,你可以这样做:
def Foo3(a):
a[:] = [11]
此代码不会重新绑定a
,而是通过将内容替换为新列表来修改列表。
为了进一步说明我的观点,看这个例子:
a = []
b = []
c = a
a.append(1)
b.append(2)
c.append(3)
print a
print b
print c
它将打印:
[1, 3]
[2]
[1, 3]
你能说出原因吗?
【讨论】:
是不是因为名称 a 和 c 现在用来指代同一个对象?顺便说一句,感谢您的解释。【参考方案3】:像+=
这样的增强赋值可以做一些普通的=
赋值做不到的事情。当您分配一个名称时,如下所示:
ar = [11]
这是对ar
名称的操作。 ar
之前引用的列表对象是不变的,所以当你在函数外做print ll
时,你会看到原来的列表。
当你这样做时
ar += [11]
这不完全等同于
ar = ar + [11]
如果您使用ar = ar + [11]
,ll
将保持不变。但是,+=
要求如果可能,ar
引用的列表应该通过修改自己的状态而不是创建新列表来执行操作。由于列表是可变的,因此列表会修改自身以具有新的 11
元素,并且此更改通过 ll
变量可见。
【讨论】:
感谢您的解释!以上是关于传递给函数时列表会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章