使用x={}
形式的默认参数通常无法实现Python中的预期目的,因为默认参数在定义函数时被绑定,而不是被调用。
约定似乎是将可变对象设置为x=None
的默认参数,然后检查x is None
以在调用函数时指定正确的默认值。
因此,如果我想将x
转换为默认为空的字典,我会使用以下内容:
def f(x=None):
x = dict(x) if x is not None else {}
但是,由于dict
可以进行任何迭代,我还可以编写这个更简洁的版本:
def f(x=()):
x = dict(x)
其中哪一种是“正确的”方法?
答案 0 :(得分:6)
惯用样式是不强制转换为dict
;这样,有人可以使用实现正确映射方法的任何对象。
所以,最pythonic的方法是使用:
def f(x=None):
if x is None:
x = {}
然后只使用映射方法。
所以,你通常不应该为dict转换参数。您声明您的API 接受一个映射对象,并期望调用者进行转换。
同时接受dict
和可迭代的唯一理由是,您希望支持允许重复键的有序键值对,例如urllib.urlencode
function。在这种情况下,dict
无法保留该信息,并且该方法不会将迭代转换为dict,而是将dict用作可迭代的。
答案 1 :(得分:1)
这里没有正确或错误的答案,但我会说第一个是更惯用的(不会使第二个错误,或者坏,或者更糟,等等。)
答案 2 :(得分:0)
需要指出的是,如果函数本身对此{1}进行了更改,则将空dict
作为自变量仅是一个问题。如果仅读取dict
,则不会发生任何问题。
如果要更改的dict
,为什么将空的dict
作为默认参数有意义?由于呼叫者尚未提供此消息,因此他们没有对此的引用,并且在呼叫后对dict
所做的更改会丢失。
唯一有意义的情况是函数需要执行需要更改其输入版本的操作。在这种情况下,该函数可能应该创建更改后的版本而无需直接更改输入,例如:
dict
通过这种方式(后一种),原始# 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
不会被更改,因此不会出现任何问题。
我知道可变默认参数问题是众所周知的,并且被认为是一个问题。但是我也有感觉,碰到它只是出现在其中的代码结构更深刻问题的征兆,我想在这篇文章中指出。或者换种说法:在一段结构合理的代码中,可变的默认参数永远不会导致实际问题。