默认可变参数的惯用方法

时间:2017-06-27 15:29:55

标签: python python-2.7 python-3.x

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

def foo(x=[]): return x
y = foo()
y.append(1)
print foo()

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

def foo(x=None):
    if x is None:
        x = []
    return x

这就是我经常看到的。

def foo(x=None):
    x = [] if x is None else x
    return x

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

def foo(x=None):
    x = x or []

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

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

2 个答案:

答案 0 :(得分:2)

我会选择#1,因为它更简单;暗示其“其他”分支。很难误解它。

在这种特殊情况下,我使用#3:bool(x)同样为None[]{}()0以及其他一些事情。如果我错误地将0传递给需要列表的函数,那么如果函数快速失败则更好,而不是将零误认为空列表!

在其他情况下,c and x else y可能是方便的三元运算符,但您必须控制c的类型;当它是局部变量而不是函数参数时,它会更容易。

如果你经常发现自己用None替换一个值,那么白色就是一个函数。考虑类似x = replace_none(x, [])

的内容

答案 1 :(得分:1)

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

def foo(x=None):
    if x is None:
        x = []
    return x

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

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

请注意,如果默认值为true,则可以使用__bool__技巧:如果or是假的,x or [1]仍为[1]。但是您无法使用x作为参数,因为它将被[]取代。