Как можно переписать функцию с изменяемыми аргументами по умолчанию, чтобы избежать проблемы с общими объектами?

Чтобы избежать проблемы с общими объектами при использовании изменяемых аргументов по умолчанию, можно заменить их на None и инициализировать внутри функции:

def my_function(my_list=None):
  if my_list is None:
    my_list = []
  my_list.append("something")
  return my_list
  
Это гарантирует, что при каждом вызове функции без аргументов будет создаваться новый, независимый список.

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

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

Пример (проблема):

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

print(append_to_list(1))  # Output: [1]
print(append_to_list(2))  # Output: [1, 2] - Неожиданно!
print(append_to_list(3))  # Output: [1, 2, 3] - Неожиданно!

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

Решение:

def append_to_list_fixed(element, my_list=None):
  if my_list is None:
    my_list = []
  my_list.append(element)
  return my_list

print(append_to_list_fixed(1))  # Output: [1]
print(append_to_list_fixed(2))  # Output: [2] - Ожидаемо!
print(append_to_list_fixed(3))  # Output: [3] - Ожидаемо!

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

Этот подход можно применять к любому изменяемому типу данных, например, к словарям ({}) или множествам (set()).

0