Когда я пишу следующий код, моя IDE предупреждает о «изменяемом аргументе по умолчанию»:
VALUES = [ 1, 2, 3 ]
def f(values=VALUES):
print(values)
Вместо этого предлагается написать следующее:
VALUES = [ 1, 2, 3 ]
def f(values=None):
if values is None:
values = VALUES
print(values)
Конечно, этоизбегает иметь (изменяемый) список в качестве аргумента по умолчанию, и моя IDE больше не жалуется.Кажется, это улучшение.
Но с другой стороны, каков был первоначальный риск?Первоначальный риск состоял в том, что f()
может изменить список в своем коде, например, так:
VALUES = [ 1, 2, 3 ]
def f(values=VALUES):
values.append(4)
print(values)
Это могло бы изменить значение VALUES
навсегда (то есть не только локально), а затем вызыватьf()
все равно будет иметь измененное значение по умолчанию, которое, вероятно, не предназначено.Кроме того, учитывая код выше, VALUES
будет расти на один 4
с каждым вызовом f()
.Таким образом, эта ситуация, вероятно, будет не такой, как задумано, если только values
в f()
не изменится, что сложно реализовать.
Но решает ли проблема предложенное IDE "исправление"?
Я думаю, что не потому, что если бы код f()
теперь содержал values.append(4)
, то же самое произошло бы снова:
def f(values=None):
if values is None:
values = VALUES
values.append(4)
print(values)
Опять же, каждый вызов увеличил бы VALUES
на один 4
.
Реальное исправление было бы следующим:
def f(values=None):
if values is None:
values = VALUES.copy() # or VALUES[:] or similar
values.append(4)
print(values)
Но это IDE не предлагает и, конечно, это будет дорого, потому что копии создаются каждый раз.
Другие вопросы уже связаны с этой проблемой (например, Почему использование None устраняет проблему изменяемого аргумента Python по умолчанию? ), но в этом тикете они используют не такую константу, как VALUES
, а литерал []
, который создаетновое значение при каждом выполнении кода, поэтому оно похоже на подход .copy()
.
Теперь вопросы:
Почему в любой среде IDE это исправление предлагается (в данном случае сконстанта)?Возможно ли это исправить другие аспекты этой проблемы, о которых я не задумывался?
Есть ли лучший способ исправить исходную проблему, в которой нет хотя бы одной из двух проблем (значение по умолчанию может изменитьсянеожиданно, ② дорогостоящее копирование значения)?