在Python中,可以更改函数中的某些类型的对象而不必返回任何内容。对于某些对象,情况并非如此。
例如,如果我们将字典传递给函数并在函数中对其进行更改,则原始字典将被更改:
def add_key(d, key):
d[key] = True
d = {}
print d
# {}
add_key(d, 1)
print d
# {1: True}
相反,我们不能像这样更改整数:
def increment_int(i):
i += 1
i = 1
print i
# 1
increment_int(i)
print i
# still 1!
起初,我认为也许规则只是不能以这种方式在函数内更改不可变对象。一个类似的示例不适用于字符串:
def append_string(s1, s2):
s1 += s2
s = "hello"
print s
# "hello"
append_string(s, " world")
print s
# "hello", not "hello world" :(
不过,我感到困惑,因为似乎某些操作应用于函数内可变对象的操作将在以后可见,而其他操作则不可见。例如,将项目附加到列表确实可以:
def append_list(l, val):
l.append(val)
l = []
print l
# []
append_list(l, 1)
print l
# [1]
而交换两个列表的名称则不会:
def swap_lists(l1, l2):
l1, l2 = l2, l1
l1 = [1]
l2 = [2]
print l1, l2
# [1] [2]
swap_lists(l1, l2)
print l1, l2
# still [1] [2], even though lists are mutable!
又一个具有看似奇怪和意外行为的示例:
def swap_then_append(l1, l2):
l1, l2 = l2, l1
l1.append(1)
l2.append(2)
l1 = []
l2 = []
print l1, l2
# [] []
swap_then_append(l1, l2)
print l1, l2
# [2] [1]
有人可以解释这里发生了什么吗?
编辑:已确定此问题的可能重复项;那里的答案部分地告诉了我发生了什么,但是我仍然不明白为什么,例如,swap_lists
上面的函数实际上并未交换列表。现在,我在进一步思考,我仍然不真正理解为什么increment_int
以及append_string
超出了我最初期望的范围,除了它与整数和字符串的不变性有关。
dupe目标中的解释可以很好地说明发生了什么,但是我将介绍发生的情况swap_then_append
。
def swap_then_append(l1, l2):
print l1,l2
# [3],[4]
l1, l2 = l2, l1
print l1,l2
# [4] [3]
l1.append(1)
l2.append(2)
l1 = [3]
l2 = [4]
print l1, l2
# [3] [4]
swap_then_append(l1, l2)
print l1, l2
# [3,2] [4,1]
“交换”更改用于引用列表的变量的名称,但仅在函数中。虽然基础对象的突变是永久的,但变量的分配取决于范围。新l1
和l2
在功能上还不如叫别的东西,因为他们现在只是阴影原始变量l1
,并l2
在函数签名,这反过来,阴影的定义l1
,并l2
在主脚本中定义。然后将这些突变应用于原始列表。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句