[英]What is the most Pythonic way to use an empty dictionary as a default argument?
Using default arguments of the form x={}
usually does not accomplish the intended purpose in Python, since default arguments are bound when a function is defined, not called. 使用
x={}
形式的默认参数通常无法在Python中实现预期目的,因为默认参数在定义函数时被绑定,而不是调用。
The convention seems to be to set mutable objects as default arguments with x=None
and then check x is None
to assign the proper default when the function is called. 约定似乎是将可变对象设置为
x=None
默认参数,然后在调用函数时检查x is None
以指定正确的默认值。
So if I would like to cast x
to a dictionary that is by default empty, I would use something like the following: 因此,如果我想将
x
转换为默认为空的字典,我会使用如下内容:
def f(x=None):
x = dict(x) if x is not None else {}
However, since dict
can take any iterable, I could also write this more succinct version: 但是,由于
dict
可以采用任何迭代,我也可以写这个更简洁的版本:
def f(x=()):
x = dict(x)
Which of these is the "right" approach? 以下哪种是“正确的”方法?
The idiomatic style is to not cast to dict
; 惯用的风格是不
dict
; that way someone could use any object that implements the correct mapping methods. 这样,有人可以使用任何实现正确映射方法的对象。
So, the most pythonic method is to use: 所以,最pythonic的方法是使用:
def f(x=None):
if x is None:
x = {}
and then just use mapping methods. 然后只使用映射方法。
So, you generally should not cast arguments to a dict. 所以,你通常不应该为dict转换参数。 You state your API accepts a mapping object instead, and expect callers to do the casting.
您声明您的API 接受映射对象,并期望调用者进行转换。
The only reason to accept both a dict
and an iterable is when you want to support ordered key-value pairs where duplicate keys are allowed, such as for the urllib.urlencode
function . 接受
dict
和iterable的唯一理由是当你想支持允许重复键的有序键值对时,例如urllib.urlencode
函数 。 In such a case a dict
cannot retain that information, and that method does not cast the iterable to a dict, but rather uses the dict as an iterable. 在这种情况下,
dict
不能保留该信息,并且该方法不会将迭代转换为dict,而是使用dict作为可迭代。
这里没有正确或错误的答案,但我会说第一个是更惯用的(这不会使第二个错误,或坏,或更糟,等等)
It needs to be mentioned that an empty dict
as an argument is only a problem if the function itself changes this dict
. 需要提到的是,如果函数本身改变了这个
dict
,那么空dict
作为参数只是一个问题。 In case the dict
is just read, no problem occurs whatsoever. 如果只读取
dict
,则不会出现任何问题。
And if there is a changing of the dict
intended, why should an empty dict
make sense as a default argument? 如果有意改变
dict
,为什么空dict
作为默认参数有意义呢? Since this hasn't been provided by the caller they do not have a reference to this and the changes done to the dict
are lost after the call. 由于呼叫者未提供此信息,因此他们没有对此进行引用,并且在呼叫之后对
dict
所做的更改将丢失。
The only case in which this might make sense is when the function needs to do something for which a changed version of its input is needed. 唯一可能有意义的情况是函数需要做一些需要更改其输入版本的东西。 In such a case the function should probably create the changed version without changing the input directly, for instance:
在这种情况下,函数应该可以在不直接更改输入的情况下创建更改的版本,例如:
# bad way:
def f(x={}):
x['newkey'] = 'newvalue'
print(x) # do something with the extended x
# probably better way:
def f(x={}):
new_dict = {}
new_dict.update(x)
new_dict.update({ 'newkey': 'newvalue' })
print(new_dict) # do something with the extended x
In this way (the latter one) the original x
is never changed, so no problem occurs. 以这种方式(后者),原始的
x
永远不会改变,因此不会出现问题。
I know that the mutable default argument problem is well-known and accepted to be a problem. 我知道可变的默认参数问题是众所周知的,并且被认为是一个问题。 But I also have the feeling that running into it is just a symptom of a more profound problem with the structure of the code it appears in and I wanted to point that out in this post.
但我也有这种感觉,遇到它只是它出现的代码结构的一个更深刻的问题的症状,我想在这篇文章中指出。 Or put the other way: In a soundly structured piece of code a mutable default argument should never result in an actual problem.
或者换句话说:在一个结构合理的代码片段中,一个可变的默认参数永远不会导致实际问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.