Лучшая практика для установки значения по умолчанию для параметра, который должен быть списком в Python?
У меня есть функция Python, которая принимает список как параметр. Если я установил значение по умолчанию для параметра в пустой список, например:
def func(items=[]):
print items
Пилинт скажет мне "Опасное значение по умолчанию [] как аргумент". Поэтому мне было интересно, что здесь лучше всего?
Ответы
Ответ 1
Используйте None
как значение по умолчанию:
def func(items=None):
if items is None:
items = []
print items
Проблема с изменяемым аргументом по умолчанию заключается в том, что он будет разделяться между всеми вызовами функции - см. "важное предупреждение" в соответствующем разделе учебника Python.
Ответ 2
Я впервые столкнулся с этим в первый раз, и моя непосредственная мысль "ну, я все равно не хочу мутировать список, так что я действительно хочу, чтобы по умолчанию был неизменный список, поэтому Python даст мне ошибку если я случайно мутирую его". Неизменяемый список - это всего лишь кортеж. Итак:
def func(items=()):
print items
Конечно, если вы передадите его тому, что действительно хочет список (например, isinstance (items, list)), тогда это вызовет у вас проблемы. Но что-то запах кода в любом случае.
Ответ 3
Для изменяемого объекта в качестве параметра по умолчанию в описании функций и методов проблема заключается в том, что оценка и создание происходит точно в тот же момент. Python-парсер считывает функцию-head и оценивает ее в тот же момент.
Большинство начинающих считают, что новый объект создается при каждом вызове, но это неверно! Один объект (в вашем примере список) создается в момент ДЕКЛАРАЦИИ, а не по требованию, когда вы вызываете метод.
Для imutable объектов, которые не являются проблемой, потому что, даже если все вызовы имеют один и тот же объект, он может быть imutable и поэтому свойства остаются неизменными.
В качестве соглашения вы используете объект None
для значений по умолчанию для указания использования инициализации по умолчанию, которая теперь может выполняться в теле функции, которая, естественно, оценивается во время вызова.
Ответ 4
Кроме того, чтобы лучше понять, что такое 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]