默认可变参数的惯用方法

Nir*_*man 5 python python-2.7 python-3.x

在python中,如果直接将可变类型作为默认参数,则会出现一个众所周知的边缘情况:

def foo(x=[]): return x
y = foo()
y.append(1)
print foo()
Run Code Online (Sandbox Code Playgroud)

通常的解决方法是将参数默认为None然后将其设置在正文中.然而,有3种不同的方法可以做到这一点,其中2种基本相同,但第三种是完全不同的.

def foo(x=None):
    if x is None:
        x = []
    return x
Run Code Online (Sandbox Code Playgroud)

这就是我经常看到的.

def foo(x=None):
    x = [] if x is None else x
    return x
Run Code Online (Sandbox Code Playgroud)

语义相同.一条线更短,但有些人抱怨python的三元组是不自然的,因为它不是以条件开始并建议避免它.

def foo(x=None):
    x = x or []
Run Code Online (Sandbox Code Playgroud)

这是最短的.我今天才了解到这种疯狂.我知道lisp所以这对我来说可能不像一些python程序员那么令人惊讶,但我从没想过这会在python中运行.这种行为是不同的; 如果你传递的东西不是None但是评估为false(比如False),它就不会覆盖默认值.如果默认值不评估false,则无法使用它,因此如果您有非空列表或dict默认值,则无法使用它.但是,根据我的经验,空列表/摘要是99%的感兴趣的案例.

关于哪个是最pythonic的想法?我意识到这里有一个观点要素,但我希望有人可以给出一个很好的例子或推理,以确定什么是最惯用的.与大多数社区相比,python倾向于强烈鼓励人们以某种​​方式做事,所以我希望这个问题及其答案即使不完全是黑白也会有用.

Mar*_*ark 1

我想说第一种方法在一般情况下是最好的。第一种和第二种方式在功能上是等效的,但第一种方式对于新手来说更容易阅读。

def foo(x=None):
    if x is None:
        x = []
    return x
Run Code Online (Sandbox Code Playgroud)

x or []技巧只能在以下情况下使用:

  • 该参数不会发生变化(因为您用新集合替换了空集合)。
  • 您不关心参数的不同虚假值之间的关系(因为您会丢失[],{} , None, my-special-class-with-之间的任何差异__bool__)。
  • 您认为阅读您的代码的任何人都知道它是如何工作的(或者想要弄清楚它)。

顺便说一句,or如果默认值评估为真,则可以使用该技巧:如果为假,则x or [1]仍将如此。但您将无法用作参数,因为它将被替换。[1]x[][1]