1) Так называемая проблема «Mutable Default Argument» - это, в общем, специальный пример, демонстрирующий, что: «Все функции с этой проблемой также страдают от аналогичной проблемы побочного эффекта от фактического параметра». Это противоречит правилам
Пример:
def foo(a=[]): # the same problematic function
a.append(5)
return a
>>> somevar = [1, 2] # an example without a default parameter
>>> foo(somevar)
[1, 2, 5]
>>> somevar
[1, 2, 5] # usually expected [1, 2]
Решение: копия Совершенно безопасным решением является copy
или deepcopy
входной сигнал сначала, а затем делать все с копией.
def foo(a=[]):
a = a[:] # a copy
a.append(5)
return a # or everything safe by one line: "return a + [5]"
Многие встроенные изменяемые типы имеют метод копирования, такой как some_dict.copy()
или some_set.copy()
, или могут быть скопированы легко, как somelist[:]
или list(some_list)
, Каждый объект также может быть скопирован с помощью copy.copy(any_object)
или более тщательным с помощью copy.deepcopy()
(последний полезен, если изменяемый объект состоит из изменяемых объектов). Некоторые объекты основаны на побочных эффектах, таких как «файл», и не могут быть осмысленно воспроизведены копией. копирование
Пример проблемы для аналогичного вопроса SO
class Test(object): # the original problematic class
def __init__(self, var1=[]):
self._var1 = var1
somevar = [1, 2] # an example without a default parameter
t1 = Test(somevar)
t2 = Test(somevar)
t1._var1.append([1])
print somevar # [1, 2, [1]] but usually expected [1, 2]
print t2._var1 # [1, 2, [1]] but usually expected [1, 2]
Он не должен быть ни сохранен ни в одном ] public экземпляра, возвращаемого этой функцией. (Предполагая, что атрибуты private экземпляра не должны быть изменены извне этого класса или подкласса по соглашению, т. Е. _var1
является частным атрибутом)
Заключение: Параметры входных параметров shouldn 'изменяются на месте (мутированные), и они не должны быть привязаны к объекту, возвращаемому функцией. (Если мы предпочитаем программирование без побочных эффектов, которые настоятельно рекомендуются, см. Wiki о «побочном эффекте» (первые два абзаца имеют смысл в этом контексте.).)
2) Только если побочный эффект на фактический параметр требуется, но нежелателен по параметру по умолчанию, тогда полезным решением является def ...(var1=None):
if var1 is None:
var1 = []
Подробнее ..
3) В некоторых случаях используется изменчивое поведение параметров по умолчанию .
Указатели на C увеличиваются не на байты, а на размер типа. То есть, если у вас есть указатель на int, он увеличивается на sizeof (int) - в вашем примере это 4.