我们都知道'dreaded mutable default argument'
我很惊讶地发现至少有一个内置使用了一个可变的默认参数deepcopy
(以及相关的__deepcopy__
)。
def deepcopy(x, memo=None, _nil=[]):
这只是模块作者的一个忽视,还是有一些关于deepcopy
行为的特别之处?
答案 0 :(得分:5)
是的,这是故意的,该对象被用作唯一的哨兵对象。它永远不会发生变异,也不会检查列表对象内容。它的唯一目的是拥有一个可以在is
测试中使用的唯一对象。
更常见的是使用None
作为哨兵来测试是否未设置某些内容,但有时您需要允许None
成为有效的设置值。在deepcopy()
的实现中,_nil
对象用于替换None
:
y = memo.get(d, _nil)
if y is not _nil:
return y
这样可以设置memo[d] = None
,因为如果memo.get(d)
存在或缺失None
,memo[d]
将返回>>> memo = {}; d = 'foo'
>>> _nil = []
>>> memo.get(d) is None
True
>>> memo.get(d, _nil) is _nil
True
>>> memo[d] = None
>>> memo.get(d) is None
True
>>> memo.get(d, _nil) is _nil
False
:
None
如果您考虑使用自己独有的非object()
哨兵对象,那么您现在可能想要使用object()
。但是当编写deepcopy()
函数时,_nil
在Python语言中还没有存在。
_nil
是使其成为局部变量的参数。这使查找_nil
引用比模块中的全局更便宜,请参阅Why does Python code run faster in a function?这在一个很容易被称为很多的函数中很重要用于复制自定义对象的深层和宽层结构。因此,正如名称的最初下划线所示,# Get start time as time
df['START_TIME'] = pd.to_datetime(df['START_TIME'],format='%H%M').dt.time
是一个实现细节。
另见Is there a way to set a default parameter equal to another parameter value?