Найти в Дзене
Креативный дизайн

Путешествие в глубины Python: Изменяемые и неизменяемые типы данных в функциях

Оглавление

Введение

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

Теоретическая основа

Ключевые концепции:

  • В Python всё является объектами;
  • Переменные - это имена, ссылающиеся на объекты;
  • Каждый объект имеет:
  1. Уникальный идентификатор;
  2. Тип;
  3. Значение;
  4. Счетчик ссылок.

Типы данных, такие как вещественные числа, целые числа, строки и все базовые коллекции делятся на изменяемые и неизменяемые типы.

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

В качестве примера можно привести следующее: number = 100. number — это имя и это имя ссылается на объект, в данном случае существенного типа (100 — это объект).

При создании объекту присваивается индивидуальный идентификатор, тип, значение и количество ссылок на это объект. В памяти эти данные так и хранятся.

Имя number ссылается на объект Python, в котором указывается индивидуальный идентификатор, тип, значение и количество ссылок на это объект.

Если number присвоить другое значение в Python, то number будет ссылаться уже на новый объект Python, который будет иметь новый индивидуальный идентификатор, тип, значение и количество ссылок на этот объект. А про старый объект он забывает, и храниться в памяти он будет со счётчиком ссылок равным 0. В результате, о будет удалён из памяти.

В таком случае у нас происходит не присваивание, а привязка имени number к ссылке.

Типы данных

Изменяемые (mutable) и неизменяемые (immutable) типы данных в Python определяют возможность модификации объекта после его создания.

В Python числа относятся к неизменяемым типам данных. К неизменяемым типам данным (immutable) так же относятся: int, float, str (строки), tuple (кортежи), тип bool.

Неизменяемые типы данных передаются в функцию по значению. Передавая имя number в функцию передается не ссылка на весь объект, а только его значение. И в таком случае, внутри функции и создаётся объект с этим значением.

В Python имеются и изменяемые типы данных, которые по английски называются mutable. К изменяемым типам данных относятся list (списки), dict (словари), set (множества).

В Python изменяемые типы данных передаются в функцию по ссылке. Передавая my_list в функцию передаётся не значение объекта, а ссылка на него. В результате чего, внутри функции меняется наш изначальный список. Так как здесь не создаётся новый объект, как в number.

Неизменяемые типы данных

  • Примеры: int, float, str, bool, tuple, frozenset, bytes
frozenset в Python — это неизменяемое множество. Оно работает как обычное множество, но после создания его нельзя изменить: нельзя добавить или удалить элементы.
  • Особенности: Любая операция модификации создаёт новый объект с уникальным идентификатором (id()). Исходные данные остаются неизменными в памяти. Передаются в функции по значению (создаётся копия значения). Безопасны для использования в многопоточных средах.

a = 100
print(id(a)) # Идентификатор: 140706928596224
a += 5
print(id(a)) # Создаётся новый идентификатор: 140706928596384

Код для вставки в программу
Код для вставки в программу
У Вас вывод идентификаторов будет другой
У Вас вывод идентификаторов будет другой

Изменяемые типы данных

  • Примеры: list, dict, set, bytearray
Bytearray в Python — это встроенная функция, которая возвращает объект, представляющий собой массив заданных байтов.
  • Особенности: Можно модифицировать на месте (без создания нового объекта). Идентификатор (id()) остаётся постоянным при изменениях. Передаются в функции по ссылке (изменения внутри функции затрагивают оригинал).

lst = [1, 2]
print(id(lst)) # 140324571629568
lst.append(3)
print(id(lst)) # Идентификатор не изменился: 140324571629568

Код для вставки в программу
Код для вставки в программу
У Вас вывод идентификаторов будет другой
У Вас вывод идентификаторов будет другой

Критически важные различия:

  • Хешируемость.
Хешируемость означает, что объект имеет хеш-значение, которое не изменяется на протяжении всего времени существования объекта.

Неизменяемые типы могут быть ключами словарей (требуют стабильного hash()). Изменяемые типы вызывают TypeError при попытке хеширования.

  • Поведение при копировании.

a = (1, [2]) # Кортеж с изменяемым списком внутри
# a[1] += [3] # Вызовет ошибку, но список внутри изменится!

  • Оптимизация памяти.

Python кеширует небольшие целые числа и строки для неизменяемых типов.

Кэширование — это процесс хранения копии данных во временном хранилище (кеше) для быстрого доступа при повторном запросе.


5 is 5 → True (один объект)
[] is [] → False (разные объекты)

Советы по использованию:

  • Используйте неизменяемые типы для:
  1. Константных значений;
  2. Ключей словарей;
  3. Данных в многопоточных приложениях.
  • Изменяемые типы подходят для:
  1. Динамически изменяемых коллекций;
  2. Кэширования данных в памяти;
  3. Сложных структур с вложенными элементами.

Рекомендации:

  • Для проверки типа используйте:

isinstance(x, (int, str)) # Для неизменяемых
isinstance(x, (list, dict)) # Для изменяемых

  • Для безопасной модификации используйте копии:

new_list = old_list.copy() # Поверхностное копирование
from copy import deepcopy
new_obj = deepcopy(old_obj) # Глубокое копирование

Практический пример

Выше написано правильное написание кода
Выше написано правильное написание кода
Тот же код ниже для копирования и вставки в программу. Не забывайте про необходимый отступ пробелами в определённых местах в начале строки, так как код на сервере блога может отображаться некорректно.

# Демонстрация работы с изменяемыми и неизменяемыми типами данных

def modify_data(num, lst):

print(f"Inside function - initial num id: {id(num)}")
num += 10 # Создается новый объект
print(f"Inside function - modified num id: {id(num)}")

print(f"Inside function - initial lst id: {id(lst)}")
lst.append(4) # Модифицируется существующий объект
print(f"Inside function - modified lst id: {id(lst)}")

return num


# Демонстрация работы с неизменяемым типом (int)
number = 100
print(f"Original number id: {id(number)}")
result = modify_data(number, [1, 2, 3])
print(f"After function number: {number}, id: {id(number)}")
print(f"Function result: {result}")

# Демонстрация работы с изменяемым типом (list)
my_list = [1, 2, 3]
print(f"Original list: {my_list}")
modify_data(number, my_list)
print(f"Modified list: {my_list}")

Результат работы кода:

-7

Разбор кода построчно

  1. def modify_data(num, lst): — Определяем функцию с двумя параметрами;
  2. num += 10 — Создается новый объект, так как int неизменяемый;
  3. lst.append(4)) — Модифицируется существующий список:
  4. number = 100 — Создается ссылка на объект числа 100;
  5. my_list = [1, 2, 3] — Создается ссылка на список.

Результат выполнения (у Вас будут другие id)

Original number id: 2238061940048

Inside function - initial num id: 2238061940048

Inside function - modified num id: 2238061940368

Inside function - initial lst id: 2238067374720

Inside function - modified lst id: 2238067374720

After function number: 100, id: 2238061940048

Function result: 110

Original list: [1, 2, 3]

Inside function - initial num id: 2238061940048

Inside function - modified num id: 2238061940368

Inside function - initial lst id: 2238067374720

Inside function - modified lst id: 2238067374720

Modified list: [1, 2, 3, 4]

Process finished with exit code 0

Рекомендации по улучшению кода

  • Добавление типизации;
  • Использование докстрингов;
Использование докстрингов (docstrings) — это способ документирования кода, который помогает другим разработчикам понять, что делает конкретный элемент программы.
  • Добавление проверок.

Заключение

Ключевые выводы:

  • Неизменяемые типы (int, str, tuple) при модификации создают новые объекты;
  • Изменяемые типы (list, dict, set) модифицируются «на месте»;
  • При работе с функциями важно учитывать эти различия;
  • Использование типизации и проверок делает код более надежным;
  • Понимание механизма работы с объектами критично важно для эффективного программирования на Python.

Практические советы:

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

ПОЛЕЗНЫЕ РЕСУРСЫ:

---------------------------------------------------

Сообщество дизайнеров в VK

https://vk.com/grafantonkozlov

Телеграмм канал сообщества

https://t.me/grafantonkozlov

Архив эксклюзивного контента

https://boosty.to/antonkzv

Канал на Дзен

https://dzen.ru/grafantonkozlov

---------------------------------------------------

Бесплатный Хостинг и доменное имя

https://tilda.cc/?r=4159746

Мощная и надежная нейронная сеть Gerwin AI

https://t.me/GerwinPromoBot?start=referrer_3CKSERJX

GPTs — плагины и ассистенты для ChatGPT на русском языке

https://gptunnel.ru/?ref=Anton

---------------------------------------------------