Введение
В Python механизм передачи данных в функции имеет свои особенности, которые важно понимать для эффективного программирования. Давайте разберем это на конкретных примерах.
Теоретическая основа
Ключевые концепции:
- В Python всё является объектами;
- Переменные - это имена, ссылающиеся на объекты;
- Каждый объект имеет:
- Уникальный идентификатор;
- Тип;
- Значение;
- Счетчик ссылок.
Типы данных, такие как вещественные числа, целые числа, строки и все базовые коллекции делятся на изменяемые и неизменяемые типы.
В 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 — это неизменяемое множество. Оно работает как обычное множество, но после создания его нельзя изменить: нельзя добавить или удалить элементы.
a = 100
print(id(a)) # Идентификатор: 140706928596224
a += 5
print(id(a)) # Создаётся новый идентификатор: 140706928596384
Изменяемые типы данных
- Примеры: list, dict, set, bytearray
Bytearray в Python — это встроенная функция, которая возвращает объект, представляющий собой массив заданных байтов.
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 (разные объекты)
Советы по использованию:
- Используйте неизменяемые типы для:
- Константных значений;
- Ключей словарей;
- Изменяемые типы подходят для:
- Динамически изменяемых коллекций;
- Кэширования данных в памяти;
Рекомендации:
- Для проверки типа используйте:
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}")
Результат работы кода:
Разбор кода построчно
- def modify_data(num, lst): — Определяем функцию с двумя параметрами;
- num += 10 — Создается новый объект, так как int неизменяемый;
- lst.append(4)) — Модифицируется существующий список:
- number = 100 — Создается ссылка на объект числа 100;
- 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
---------------------------------------------------