Как Python обрабатывает изменения значений по умолчанию для изменяемых типов (например, списков)?

При обработке значений по умолчанию, Python вычисляет их только один раз при определении функции. Если значение по умолчанию - изменяемый тип (например, список), то этот объект создается только один раз. Последующие вызовы функции будут использовать один и тот же изменяемый объект. Это может привести к неожиданным результатам, когда функция изменяет значение по умолчанию, так как эти изменения сохраняются между вызовами. Чтобы избежать этого, рекомендуется использовать None в качестве значения по умолчанию и создавать новый объект внутри функции:
def my_function(data=None):
    if data is None:
      data = []
    # ...
  

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

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

Пример:

    
def append_to_list(item, my_list=[]):
    my_list.append(item)
    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(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    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` в качестве значения по умолчанию и создавайте новый объект внутри функции.
0