← Назад к вопросам

Какая есть опасность при использовании изменяемых типов данных?

2.3 Middle🔥 161 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Опасности изменяемых типов данных

Изменяемые типы данных (mutable types) — список, словарь, множество (list, dict, set) — в Python представляют собой серьёзный источник ошибок, если их неправильно использовать. Вот главные опасности:

1. Неожиданное изменение исходных данных

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

def add_item(lst):
    lst.append(4)
    return lst

original = [1, 2, 3]
result = add_item(original)
print(original)  # [1, 2, 3, 4] — ИЗМЕНИЛСЯ!
print(result)    # [1, 2, 3, 4]

Этого избегаешь созданием копии:

def add_item(lst):
    new_lst = lst.copy()  # или lst[:]
    new_lst.append(4)
    return new_lst

original = [1, 2, 3]
result = add_item(original)
print(original)  # [1, 2, 3] — не изменился
print(result)    # [1, 2, 3, 4]

2. Проблемы с аргументами по умолчанию

Одна из самых опасных ошибок в Python — использование изменяемого типа как аргумента по умолчанию:

def append_to_list(item, lst=[]):
    lst.append(item)
    return lst

print(append_to_list(1))  # [1]
print(append_to_list(2))  # [1, 2] — уже есть 1!
print(append_to_list(3))  # [1, 2, 3]

Проблема: список создаётся один раз при определении функции и переиспользуется каждый раз. Правильно:

def append_to_list(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

3. Неглубокое копирование (shallow copy)

Метод .copy() копирует только первый уровень. Вложенные объекты остаются общими:

original = [[1, 2], [3, 4]]
copy = original.copy()  # Неглубокое копирование

copy[0].append(999)
print(original)  # [[1, 2, 999], [3, 4]] — изменился!

Решение — глубокое копирование:

import copy

original = [[1, 2], [3, 4]]
deep_copy = copy.deepcopy(original)

deep_copy[0].append(999)
print(original)  # [[1, 2], [3, 4]] — не изменился

4. Проблемы с общими ссылками

shared_list = [1, 2, 3]
reference1 = shared_list
reference2 = shared_list

reference1.append(4)
print(reference2)  # [1, 2, 3, 4]

Все переменные указывают на один и тот же объект в памяти.

5. Использование в словарях как ключи невозможно

Изменяемые типы нельзя использовать как ключи словаря (они не hashable):

data = {[1, 2]: "value"}  # TypeError: unhashable type: list

# Правильно — неизменяемый тип
data = {(1, 2): "value"}  # OK

Best Practices

Используй неизменяемые типы (tuple, frozenset) когда возможно:

# Плохо
positions = []
positions.append((10, 20))

# Хорошо
positions = ()
positions = positions + ((10, 20),)

Явно проектируй функции, которые не меняют входные данные (функциональный стиль):

# Плохо — имеет побочный эффект
def increment_all(nums):
    for i in range(len(nums)):
        nums[i] += 1

# Хорошо — чистая функция
def increment_all(nums):
    return [n + 1 for n in nums]

Документируй поведение:

def process_data(items):
    """Обрабатывает данные.
    
    Args:
        items: Будет модифицирован!
    """
    items.sort()

Понимание этих опасностей — критично для написания надёжного Python кода.