在Python中设置假定为列表的参数的默认值的最佳实践?

时间:2021-03-15 17:07:39

I have a Python function that takes a list as a parameter. If I set the parameter's default value to an empty list like this:

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

def func(items=[]):
    print items

Pylint would tell me "Dangerous default value [] as argument". So I was wondering what is the best practice here?

Pylint会告诉我“危险的默认值[]作为参数”。我想知道这里最好的做法是什么?

4 个解决方案

#1


71  

Use None as a default value:

使用None作为默认值:

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

The problem with a mutable default argument is that it will be shared between all invocations of the function -- see the "important warning" in the relevant section of the Python tutorial.

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

#2


6  

I just encountered this for the first time, and my immediate thought is "well, I don't want to mutate the list anyway, so what I really want is to default to an immutable list so Python will give me an error if I accidentally mutate it." An immutable list is just a tuple. So:

我第一次遇到这种情况,我当时的想法是“好吧,反正我也不想改变列表,所以我真正想要的是默认为一个不可变的列表,所以如果我不小心改变了它,Python会给我一个错误。”不可变列表只是一个元组。所以:

  def func(items=()):
      print items

Sure, if you pass it to something that really does want a list (eg isinstance(items, list)), then this'll get you in trouble. But that's a code smell anyway.

当然,如果您将它传递给真正需要列表的对象(例如isinstance(items, list)),那么这会给您带来麻烦。但无论如何,这是一种代码味道。

#3


3  

For mutable object as a default parameter in function- and method-declarations the problem is, that the evaluation and creation takes place at exactly the same moment. The python-parser reads the function-head and evaluates it at the same moment.

对于可变对象作为函数和方法声明中的默认参数,问题是,计算和创建发生在完全相同的时刻。python-parser读取函数头并同时评估它。

Most beginers asume that a new object is created at every call, but that's not correct! ONE object (in your example a list) is created at the moment of DECLARATION and not on demand when you are calling the method.

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

For imutable objects that's not a problem, because even if all calls share the same object, it's imutable and therefore it's properties remain the same.

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

As a convention you use the None object for defaults to indicate the use of a default initialization, which now can take place in the function-body, which naturally is evaluated at call-time.

作为一种约定,您使用None对象作为默认值来指示使用默认初始化,现在可以在function-body中进行初始化,在调用时自然会对其进行评估。

#4


1  

In addition and also to better understand what python is, here my little themed snippet:

此外,为了更好地理解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]

#1


71  

Use None as a default value:

使用None作为默认值:

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

The problem with a mutable default argument is that it will be shared between all invocations of the function -- see the "important warning" in the relevant section of the Python tutorial.

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

#2


6  

I just encountered this for the first time, and my immediate thought is "well, I don't want to mutate the list anyway, so what I really want is to default to an immutable list so Python will give me an error if I accidentally mutate it." An immutable list is just a tuple. So:

我第一次遇到这种情况,我当时的想法是“好吧,反正我也不想改变列表,所以我真正想要的是默认为一个不可变的列表,所以如果我不小心改变了它,Python会给我一个错误。”不可变列表只是一个元组。所以:

  def func(items=()):
      print items

Sure, if you pass it to something that really does want a list (eg isinstance(items, list)), then this'll get you in trouble. But that's a code smell anyway.

当然,如果您将它传递给真正需要列表的对象(例如isinstance(items, list)),那么这会给您带来麻烦。但无论如何,这是一种代码味道。

#3


3  

For mutable object as a default parameter in function- and method-declarations the problem is, that the evaluation and creation takes place at exactly the same moment. The python-parser reads the function-head and evaluates it at the same moment.

对于可变对象作为函数和方法声明中的默认参数,问题是,计算和创建发生在完全相同的时刻。python-parser读取函数头并同时评估它。

Most beginers asume that a new object is created at every call, but that's not correct! ONE object (in your example a list) is created at the moment of DECLARATION and not on demand when you are calling the method.

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

For imutable objects that's not a problem, because even if all calls share the same object, it's imutable and therefore it's properties remain the same.

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

As a convention you use the None object for defaults to indicate the use of a default initialization, which now can take place in the function-body, which naturally is evaluated at call-time.

作为一种约定,您使用None对象作为默认值来指示使用默认初始化,现在可以在function-body中进行初始化,在调用时自然会对其进行评估。

#4


1  

In addition and also to better understand what python is, here my little themed snippet:

此外,为了更好地理解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]