Python 默认可变参数的惯用方法

Python 默认可变参数的惯用方法,python,python-2.7,python-3.x,Python,Python 2.7,Python 3.x,在python中,如果直接将可变类型作为默认参数,则会出现众所周知的边缘情况: def foo(x=[]): return x y = foo() y.append(1) print foo() 通常的解决方法是将参数默认为None,然后在正文中设置它。然而,有三种不同的方法可以做到这一点,其中两种基本相同,但第三种完全不同 def foo(x=None): if x is None: x = [] return x 这是我通常看到的 def foo(x=No

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

def foo(x=[]): return x
y = foo()
y.append(1)
print foo()
通常的解决方法是将参数默认为
None
,然后在正文中设置它。然而,有三种不同的方法可以做到这一点,其中两种基本相同,但第三种完全不同

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 default,则不能使用它。但以我的经验来看,99%的案例都涉及到空列表/目录


你认为哪一个最像蟒蛇?我意识到这里有一些观点,但我希望有人能给出一个很好的例子或推理,说明什么是最惯用的。与大多数社区相比,python倾向于强烈鼓励人们以某种方式做事,因此我希望这个问题及其答案将是有用的,即使它不是完全黑白的。

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

def foo(x=None):
    if x is None:
        x = []
    return x
只有在以下情况下才能使用
x或[]
技巧:

  • 参数不会发生变化(因为您将用新集合替换空集合)
  • 您不关心参数的不同伪值之间的差异(因为您丢失了
    []
    {}
    ,我的特殊类与-
    \uuuubool\uuu
    之间的任何差异)
  • 您认为任何阅读您的代码的人都知道它是如何工作的(或者想去弄清楚它)

作为旁注,如果默认值为true,则可以使用
技巧:
x或[1]
如果
x
为false,则仍然是
[1]
。但是您将不能使用
[]
作为参数,因为它将被
[1]

替换,我会选择1,因为它更简单;它的“else”分支是隐含的。很难曲解它

在这种特殊情况下,我不同意#3:
bool(x)
对于
None
[]
{}
()
0
和其他一些东西同样是错误的。如果我错误地将一个
0
传递到一个需要列表的函数中,最好该函数快速失败,而不是将0误认为是一个空列表

在其他情况下,
c和x或者y可以是一个方便的三元运算符,但是您必须控制
c
的类型;如果它是局部变量而不是函数参数,则更容易实现


如果您经常发现自己用一个值替换
None
,请使用一个函数来替换该值。考虑一些类似于<代码> x=RePaseIn(x,[])< /> > .< /p>一般使用<代码> x= a或b>代码>来创建Python中的三元语句是不赞成的,并认为是拙劣的实践…那就是说去做吧。。。但我认为python三元语句(选项B)是最具python风格的。。。但是我很确定这个问题会被解决,因为它不太适合SO(所以讨厌“意见”而更喜欢“事实”),而且,如果你期待一个可变对象(例如
列表
),为什么不
x=x如果x else[]
?它稍微短一点,但如果
x
True
布尔值,则有一个“拐角”情况。“但是第三个id”。是吗?显式检查无>>检查任何虚假值我还有另一个给你:
def foo(**kwargs):返回kwargs.get('x',[])
“如果默认值为真,则可以使用
技巧:
x或[1]
仍将是
[1]
如果
x
是假的”当你通过
[]
作为参数,as
x
将错误地更改为
[1]
。我想这就是OP的意思。@flornquake是的,你是对的,也许我应该把它解释清楚。我认为这与默认值为真无关
x或[]
x或[1]
都将
0
替换为一个列表,这可能同样不受欢迎。但我现在明白你的意图了。@Mark它与python中通常期望的特定接口相关。不管怎样,通常为列表传递一个整数都是不好的。因此,如果默认值是一个dict,那么在常见情况下,我们将自己限制为类似dict的类型,实际上,这些类型的行为与dict非常相似(例如,默认和有序dict)。但是python中大多数truthy类型只有一个值为false。如果这是默认设置,那么在传递正确的类型时就不会出现问题。但如果默认值为真值(例如非空dict),则无法显式传递空dict,这是一个问题。好吧,很公平,我已经更新了最后一部分,请随意进行进一步编辑