Примитивные и ссылочные типы данных: различия

🔍 Как Python хранит данные в памяти?

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

a = 42          # Примитивный тип (int)
b = [1, 2, 3]   # Ссылочный тип (list)

🧱 Примитивные типы: простое значение

Примитивные (скалярные) типы — это базовые "кирпичики", которые хранят непосредственное значение. В Python к ним относятся:

  • int (целые числа)
  • float (дробные числа)
  • bool (логические значения)
  • str (строки, но с оговорками*)
  • None (специальный тип)

🌟 Ключевая особенность: При присвоении создаётся новая копия значения.

x = 10
y = x  # Создаётся копия числа 10

x = 20
print(y)  # 10 — y не изменилось!

🏷️ Ссылочные типы: объекты и указатели

Ссылочные (составные) типы — это сложные структуры, которые хранятся как объекты в памяти. К ним относятся:

  • list (списки)
  • dict (словари)
  • set (множества)
  • tuple (кортежи*)
  • Экземпляры классов

🔄 Важно: Переменная содержит ссылку на объект, а не сам объект!

list1 = [1, 2, 3]
list2 = list1  # Обе переменные ссылаются на один объект!

list1.append(4)
print(list2)  # [1, 2, 3, 4] — изменение видно в list2!

⚡ Практические отличия: 3 важных следствия

1. Изменяемость vs Неизменяемость

  • Примитивные типы неизменяемы — любая операция создаёт новый объект.
  • Ссылочные типы обычно изменяемы (кроме tuple и frozenset).
s = "hello"
s[0] = "H"  # Ошибка! str неизменяем

lst = [1, 2]
lst[0] = 10  # OK, list изменяем

2. Сравнение значений

  • Примитивы сравниваются по значению.
  • Ссылочные типы сравниваются по идентичности (по умолчанию).
a = 1000
b = 1000
print(a == b)  # True — значения равны

lst1 = [1, 2]
lst2 = [1, 2]
print(lst1 is lst2)  # False — это разные объекты!

3. Передача в функции

  • Примитивы передаются по значению (копируются).
  • Ссылочные типы передаются по ссылке.
def modify(num, items):
    num += 10         # Не влияет на внешнюю переменную
    items.append(100) # Изменяет исходный список!

x = 5
lst = [1, 2]
modify(x, lst)
print(x)    # 5 (не изменился)
print(lst)  # [1, 2, 100] (изменился)

🛠️ Полезные инструменты для работы

1. Функция id() — адрес в памяти

x = 10
y = 10
print(id(x) == id(y))  # True — для маленьких int Python кэширует объекты

2. Оператор is — проверка идентичности

a = [1, 2]
b = a
print(a is b)  # True — это один и тот же объект

3. Модуль copy — контролируемое копирование

import copy

original = [[1, 2], [3, 4]]
shallow = copy.copy(original)     # Поверхностная копия
deep = copy.deepcopy(original)    # Глубокая копия

💡 Главное правило

Всегда учитывайте тип данных, с которым работаете:

  • Примитивы — безопасны при передаче, но менее гибки.
  • Ссылочные типы — мощные, но требуют осторожности с изменением.

Для глубокого погружения рекомендую разбор Данилы Бежина на YouTube: https://www.youtube.com/@DanilaBezhin.

Теперь вы готовы избегать коварных багов, связанных с неожиданными изменениями объектов! 🎯

Скрыть рекламу навсегда

🧠 Учёба без воды и зубрёжки

Закрытый Boosty с наработками опытного преподавателя.

Объясняю сложное так, чтобы щелкнуло.

🚀 Забрать доступ к Boosty