Как работает механизм передачи аргументов по умолчанию в Python для изменяемых объектов?

В Python аргументы по умолчанию вычисляются только один раз, во время определения функции. Если аргумент по умолчанию - изменяемый объект (например, список или словарь), то этот объект создается единожды и используется при каждом вызове функции, когда аргумент явно не передан. Это означает, что изменение этого объекта внутри функции повлияет на последующие вызовы функции, так как будет изменен один и тот же объект в памяти. Рекомендуется использовать None в качестве значения по умолчанию и создавать новый изменяемый объект внутри функции, если это необходимо, чтобы избежать неожиданного поведения.

В Python, передача аргументов по умолчанию для изменяемых объектов, таких как списки или словари, может привести к неожиданному поведению, если не понимать, как это работает.

Суть проблемы: Аргументы по умолчанию создаются только один раз, когда функция определяется, а не при каждом вызове. Это значит, что если аргумент по умолчанию - изменяемый объект, то он будет один и тот же для всех вызовов функции, если он не будет переопределён при вызове.

Объяснение с примером:


def append_to_list(value, my_list=[]):
  my_list.append(value)
  return my_list

print(append_to_list(1))  # Вывод: [1]
print(append_to_list(2))  # Вывод: [1, 2]
print(append_to_list(3))  # Вывод: [1, 2, 3]
  

В этом примере, `my_list` инициализируется как пустой список только один раз при определении функции. Поэтому, при каждом последующем вызове `append_to_list` без указания `my_list`, мы изменяем один и тот же список, а не создаем новый.

Как правильно: Рекомендуется использовать `None` в качестве значения по умолчанию и создавать изменяемый объект внутри функции, если аргумент по умолчанию не предоставлен:


def append_to_list_safe(value, my_list=None):
  if my_list is None:
    my_list = []
  my_list.append(value)
  return my_list

print(append_to_list_safe(1))  # Вывод: [1]
print(append_to_list_safe(2))  # Вывод: [2]
print(append_to_list_safe(3))  # Вывод: [3]
  

Здесь мы проверяем, является ли `my_list` равным `None`. Если да, то создаем новый пустой список. Таким образом, при каждом вызове функции без указания `my_list`, создается новый список.

Вывод: Понимание этого механизма критически важно для избежания неожиданных side-effects и написания предсказуемого кода на Python. Всегда будьте осторожны при использовании изменяемых объектов в качестве аргументов по умолчанию.

0