我有一个将列表作为参数的 Python 函数。如果我将参数的默认值设置为一个空列表,如下所示:
def func(items=[]):
print items
Pylint 会告诉我“危险的默认值 [] 作为参数”。所以我想知道这里的最佳做法是什么?
我有一个将列表作为参数的 Python 函数。如果我将参数的默认值设置为一个空列表,如下所示:
def func(items=[]):
print items
Pylint 会告诉我“危险的默认值 [] 作为参数”。所以我想知道这里的最佳做法是什么?
用作None
默认值:
def func(items=None):
if items is None:
items = []
print items
可变默认参数的问题在于它将在函数的所有调用之间共享——请参阅Python 教程相关部分中的“重要警告” 。
我第一次遇到这个,我的直接想法是“好吧,我不想改变列表,所以我真正想要的是默认为不可变列表,所以如果我不小心Python会给我一个错误变异它。” 不可变列表只是一个元组。所以:
定义函数(项目=()): 打印项目
当然,如果你将它传递给确实需要一个列表的东西(例如 isinstance(items, list)),那么这会给你带来麻烦。但无论如何,这是一种代码气味。
对于可变对象作为函数和方法声明中的默认参数,问题在于,评估和创建发生在完全相同的时刻。python-parser 读取函数头并同时对其进行评估。
大多数初学者都认为每次调用都会创建一个新对象,但这是不正确的!一个对象(在您的示例中为列表)是在声明时创建的,而不是在您调用该方法时按需创建的。
对于不可变对象来说这不是问题,因为即使所有调用共享同一个对象,它也是不可变的,因此它的属性保持不变。
作为约定,您使用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]