【发布时间】:2017-11-02 00:25:57
【问题描述】:
在 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]
有人能解释一下这里发生了什么吗?
编辑:已确定此问题的possible duplicate;那里的答案部分地向我解释了发生了什么,我仍然不明白为什么,例如,上面的函数swap_lists 实际上并没有交换列表。现在我在进一步考虑它,我仍然不明白为什么上面的increment_int 和append_string 没有做我最初期望的事情,除了它与整数和字符串的不变性有关.
【问题讨论】:
-
感谢您指出可能的重复 - 阅读该问题和答案很有帮助,但我仍然觉得我不明白这里发生了什么。我在底部添加了一个编辑,承认可能的重复,但我仍然非常感谢某人更深入的回答!
-
您可以改变可变对象,但分配(包括交换)会将新对象绑定到名称,因此它的效果对于包含该名称的范围是本地的。请看Facts and myths about Python names and values
-
Python 中的“变量”最好被视为对象的标签。该对象存在或不附有任何标签(嗯,有点——如果该对象没有被任何其他对象引用,那么它就会被销毁,但这是一个旁白)。作为对象的点独立于附加到它的标签或标签而存在。例如
l1 = l2 = [1, 2, 3]会创建两个标签,它们粘在同一个列表上。这与对象的可变性或不变性无关。当一个标签被分配给一个对象,然后你将它分配给另一个对象时,你只是在交换那个标签。
标签: python