Best practice for setting the default value of a parameter that's supposed to be a list in Python?
我有一个将列表作为参数的python函数。如果我将参数的默认值设置为如下空列表:
1 2 | def func(items=[]): print items |
皮林特会告诉我"危险的默认值[]作为参数"。所以我想知道这里的最佳实践是什么?
使用
1 2 3 4 | def func(items=None): if items is None: items = [] print items |
可变默认参数的问题在于,它将在函数的所有调用之间共享——请参见Python教程的相关部分中的"重要警告"。
我第一次遇到这个问题,我的第一个想法是"好吧,反正我不想改变列表,所以我真正想要的是默认为不可变列表,这样如果我不小心改变了它,python就会给我一个错误。"不可变列表只是一个元组。所以:
1 2 | def func(items=()): print items |
当然,如果你把它传递给某个真正想要列表的东西(比如isinstance(items,list)),那么这会给你带来麻烦。但无论如何,这是一种代码味道。
对于可变对象作为函数和方法声明中的默认参数,问题在于,计算和创建发生在完全相同的时刻。python解析器读取函数头并同时对其进行评估。
大多数人都认为每次调用都会创建一个新对象,但这不正确!声明时创建一个对象(在示例中是一个列表),调用方法时不按需创建。
对于不成问题的可修改对象,因为即使所有调用共享同一对象,它也是可修改的,因此它的属性保持不变。
作为一种惯例,您将
此外,为了更好地理解python是什么,下面是我的主题小片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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] |