我遇到的情况是,函数头中默认参数的值受函数体内的if子句影响。我正在使用Python 3.7.3。
我们有两个功能f
和j
。我了解前两个功能的行为。我不了解第二个功能的行为。
def f(L=[]):
print('f, inside: ', L)
L.append(5)
return L
def j(L=[]):
print('j, before if:', L)
if L == []:
L = []
print('j, after if: ', L)
L.append(5)
return L
现在我们调用第一个函数三次:
>>> print('f, return: ', f())
f, inside: []
f, return: [5]
>>> print('f, return: ', f())
f, inside: [5]
f, return: [5, 5]
>>> print('f, return: ', f())
f, inside: [5, 5]
f, return: [5, 5, 5]
空列表[]
在函数的第一次调用时初始化。当我们将5
附加到L
时,将修改内存中列表的一个实例。因此,在第二个函数调用上,将此修改后的列表分配给L
。听起来很合理。
现在,我们调用第三个函数(j
)并获得:
>>> print('j, return: ', j())
j, before if: []
j, after if: []
j, return: [5]
>>> print('j, return: ', j())
j, before if: []
j, after if: []
j, return: [5]
>>> print('j, return: ', j())
j, before if: []
j, after if: []
j, return: [5]
根据输出,L
在每次调用函数j
的开头都是一个空列表。当我删除if子句时,在函数j
的主体中,该函数等于函数f
并产生相同的输出。因此,if子句似乎有一些副作用。测试len(L) == 0
而不是L == []
中的j
具有相同的效果。
我的问题与以下方面有关:
但是这些问题的答案和本教程仅回答了我已经知道的事情。
答案 0 :(得分:1)
如果全部归结为:
if L == [5]:
L = []
在这里,您无需更改默认参数的值,只需在本地绑定到新名称即可。
您可以改为:
if L == [5]:
L.clear()
或
if L == [5]:
L[:] = []
清除参数对象的数据。
答案 1 :(得分:1)
修改打印语句以同时打印id(L)
:
def j(L=[]):
print('j, before if:', L, id(L))
if L == []:
L = []
print('j, after if: ', L, id(L))
L.append(5)
return L
现在检查结果:
>>> j()
j, before if: [] 2844163925576
j, after if: [] 2844163967688
[5]
请注意ID的差异。当您到达修改L
的函数部分时,它不再与默认参数引用同一对象。您已经将L
反弹到一个新列表(其中L = []
位于if语句的主体中),因此,您永远不会更改默认参数。
答案 2 :(得分:0)
def a():
print "assigning default value"
return []
def b(x=a()):
x.append(10)
print "inside b",x
return x
print b()
print b()
print b()
尝试运行它。您会看到每次运行该函数时都未分配默认值 输出
assigning default value
inside b [10]
[10]
inside b [10, 10]
[10, 10]
inside b [10, 10, 10]
[10, 10, 10]
仅一次将'a'函数调用为默认值。上面在方法的编译方面对其余部分进行了很好的解释,因此不再重复相同的操作