75t*_*one 22 python arguments function mutable
我正在学习Python,我正在处理Mutable Default Argument问题.
# BAD: if `a_list` is not passed in, the default will wrongly retain its contents between successive function calls
def bad_append(new_item, a_list=[]):
a_list.append(new_item)
return a_list
# GOOD: if `a_list` is not passed in, the default will always correctly be []
def good_append(new_item, a_list=None):
if a_list is None:
a_list = []
a_list.append(new_item)
return a_list
Run Code Online (Sandbox Code Playgroud)
我知道a_list
只有在def
第一次遇到语句时才初始化,这就是为什么后续调用bad_append
使用相同的列表对象的原因.
我不明白的是为什么good_append
有所不同.它看起来像a_list
会仍然只初始化一次; 因此,该if
语句仅在第一次调用函数时才为真,这意味着a_list
只会[]
在第一次调用时重置,这意味着它仍然会累积所有过去的new_item
值并且仍然是错误的.
为什么不呢?我错过了什么概念?a_list
每次good_append
运行时如何擦干净?
Kar*_*tel 22
看起来a_list仍然只会初始化一次
"初始化"不是Python中变量发生的事情,因为Python中的变量只是名称."初始化"只发生在对象上,它是通过类' __init__
方法完成的.
当你写作时a = 0
,这是一项任务.这就是说" a
应该引用表达式所描述的对象0
".它不是初始化; a
可以在以后任何时候命名任何类型的任何其他东西,这是因为分配了其他内容而发生的a
.作业只是作业.第一个并不特别.
当你写作时def good_append(new_item, a_list=None)
,那不是"初始化" a_list
.它正在设置对象的内部引用,即评估的结果None
,以便在good_append
没有第二个参数的情况下调用时,该对象会自动分配给a_list
.
意思是a_list只会在第一次调用时重置为[]
不,a_list
被设置为[]
任何时间a_list
是None
开始.也就是说,当None
显式传递任何一个,或者省略参数时.
[]
发生此问题是因为表达式 []
仅在此上下文中计算一次.在编译函数时,[]
会对其进行评估,创建一个特定的列表对象 - 该对象恰好为空启动 - 并且该对象用作默认对象.
a_list
每次good_append
运行时如何擦干净?
它没有.它不需要.
你知道这个问题是如何用"可变的默认参数"来描述的吗?
None
是不可变的.
修改参数具有默认值的对象时会发生此问题.
a_list = []
不会修改a_list
之前提到的任何对象.这不可以; 任意对象不能神奇地就地转换为空列表.a_list = []
意思是" a_list
应停止参考之前提到的内容,并开始提及[]
".先前提到的对象未改变.
编译函数时,其中一个参数有一个默认值,该值 - 一个对象 - 被烘焙到函数中(它本身也是一个对象!).当您编写改变对象的代码时,该对象会发生变异.如果被引用的对象恰好是烘焙到函数中的对象,它仍然会发生变异.
但你不能变异None
.这是不可改变的.
你可以改变[]
.它是一个列表,列表是可变的.将项添加到列表会改变列表.
phi*_*hag 15
如果默认值是可变的,则问题仅存在,而None
不是.与函数对象一起存储的内容是默认值.调用该函数时,将使用默认值初始化函数的上下文.
a_list = []
Run Code Online (Sandbox Code Playgroud)
只是a_list
在当前函数调用的上下文中为名称指定一个新对象.它不会None
以任何方式修改.
glg*_*lgl 12
默认值a_list
(或任何其他默认值,就此而言)一旦初始化就存储在函数的内部,因此可以以任何方式进行修改:
>>> def f(x=[]): return x
...
>>> f.func_defaults
([],)
>>> f.func_defaults[0] is f()
Run Code Online (Sandbox Code Playgroud)
所以值in func_defaults
是相同的,这是众所周知的函数内部(并在我的例子中返回,以便从外部访问它).
IOW,当调用f()
是隐式时会发生什么x = f.func_defaults[0]
.如果随后修改了该对象,您将保留该修改.
相反,函数内部的赋值总是一个新的[]
.任何修改都将持续到最后一次引用为止[]
; 在下一个函数调用中,[]
创建一个new .
再说一遍,[]
在每次执行时获取相同的对象并不是真的,但它(仅在默认参数的情况下)只执行一次然后保留.