简体   繁体   English

使用空字典作为默认参数的最Pythonic方法是什么?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM