何时可以在函数调用中更改变量?

时间:2017-11-02 00:25:57

标签: python

在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_intappend_string没有达到我最初的预期,除了它与不变性有关整数和字符串。

1 个答案:

答案 0 :(得分:3)

欺骗目标中的解释很好地解释了发生了什么,但我将解决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]

'交换'更改用于引用列表的变量的名称,但仅在函数中。虽然底层对象的变异是永久性的,但变量的分配取决于范围。函数中的新l1l2也可能被称为其他内容,因为它们现在只是影响函数签名中定义的原始变量l1l2,反过来,它会影响主脚本中定义的l1l2。然后突变适用于原始列表。