在 Python 中设置应该是列表的参数的默认值的最佳实践?

我有一个 Python 函数,它接受一个列表作为参数。如果我将参数的默认值设置为一个空列表,如下所示:

def func(items=[]):
print items

Pylint 会告诉我“危险的默认值[]作为参数”,所以我想知道这里的最佳实践是什么?

25172 次浏览

使用 None作为默认值:

def func(items=None):
if items is None:
items = []
print items

可变缺省参数的问题在于它将在函数的所有调用之间共享——请参阅 Python 教程的相关部分中的“重要警告”。

对于在函数和方法声明中作为默认参数的可变对象,问题在于求值和创建同时进行。Python 解析器读取函数头并同时计算它。

大多数初学者都认为每次调用都会创建一个新对象,但这并不正确!一个对象(在您的示例中是一个列表)是在 DECLARATION 时创建的,而不是在调用该方法时按需创建的。

对于不可变对象,这不是问题,因为即使所有调用共享同一个对象,它也是不可变的,因此它的属性保持不变。

作为一种约定,您使用 None对象作为默认值来指示默认初始化的使用,默认初始化现在可以在函数体中进行,而函数体自然是在调用时进行计算的。

除此之外,为了更好地理解 python 是什么,这里是我的小主题片段:

from functools import wraps
def defaultFactories(func):
'wraps function to use factories instead of values for defaults in call'
defaults = func.func_defaults
@wraps(func)
def wrapped(*args,**kwargs):
func.func_defaults = tuple(default() for default in defaults)
return func(*args,**kwargs)
return wrapped


def f1(n,b = []):
b.append(n)
if n == 1: return b
else: return f1(n-1) + b


@defaultFactories
def f2(n,b = list):
b.append(n)
if n == 1: return b
else: return f2(n-1) + b


>>> f1(6)
[6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1]
>>> f2(6)
[1, 2, 3, 4, 5, 6]

这是我第一次遇到这种情况,我的第一反应是: “好吧,我不想对列表进行变异,所以我真正想要的是默认设置为不可变列表,这样如果我不小心变异了它,Python 就会给我一个错误。”不可变列表只是一个元组。所以:

def func(items=()):
print items

当然,如果你把它传递给真正想要一个列表的东西(如实例(条目,列表)) ,那么这会给你带来麻烦。但那是代码的味道。