Изменяемые и неизменяемые объекты в Python

Перевод статьи Mutable vs Immutable Objects in Pythonopen in new window.

Все значения в Python это объекты. Объекты делятся на изменяемые и неизменяемые.

Python, схема объектов

Каждая переменная ссылается на экземпляр объекта. При создании, объекту присваивается уникальный идентификатор (object id) и тип объекта. Тип объекта не меняется после создания, но может изменится состояние объекта. Изменяемые объекты меняют своё состояние после создания, а неизменяемые сохраняются в том виде в котором были созданы.

Встроенные неизменяемые типы: int, float, bool, str, tuple, unicode. Встроенные изменяемые типы list, set, dict. Пользовательские классы обычно изменяемы. Для имитирования неизменяемости переопределите методы изменения и удаления значений чтобы они возвращали исключение.

Python. таблица изменяемых и неизменяемых объектов

Чтобы узнать ссылается ли переменная на изменяемый или неизменяемый рассмотрим подробнее функции id() и type().

Функции id и type

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

Встроенная функция type() возвращает тип объекта. Рассмотрим два примера.

# Пример 1
>>> x = "Holberton"
>>> y = "Holberton"
>>> id(x)
140135852055856
>>> id(y)
140135852055856
>>> print(x is y) '''comparing the types'''
True
1
2
3
4
5
6
7
8
9
# Пример 2
>>> a = 50
>>> type(a)
<class:int>
>>> b = "Holberton"
>>> type(b)
<class: 'string'>
1
2
3
4
5
6
7

Проверим, с помощью этих функций, какие типы являются изменяемыми, а какие нет.

Изменяемые и неизменяемые объекты

Изменяемые объекты могут изменять свое состояние или содержимое, неизменяемые не могут. Практический пример проверки на изменяемость:

x = 10
y = x
1
2

Мы создали объект типа int. Идентификаторы x и y ссылаются на один объект.

id(x) == id(y)
id(y) == id(10)
1
2

Выполним простую операцию:

x = x + 1
1

Теперь

id(x) != id(y)
id(x) != id(10)
1
2

Ссылка находящаяся в переменной x изменилась. Изменилась именно ссылка, не сам объект, это показывает изменение идентификатора объекта. Объект 10 не изменился, переменная y продолжает ссылаться на него. Неизменяемые объекты не меняются после создания.

В случае изменяемых объектов

m = list([1, 2, 3])
n = m
1
2

Мы создали объект типа list. Идентификаторы m и n ссылаются на один объект — список из трёх элементов неизменяемого типа int.

id(m) == id(n)
1

Изменим список, удалим один элемент:

m.pop()
1

Идентификатор объекта не меняется:

id(m) == id(n)
1

Переменные m и n так же ссылаются на один и тот же объект списка после изменения списка. Список теперь содержит два элемента [1, 2].

Особенности изменяемых и неизменяемых объектов:

  • Python обрабатывает изменяемые и неизменяемые объекты по-разному.
  • Доступ к неизменяемым объектам быстрее чем к изменяемым.
  • Изменяемые объекты лучше использовать когда есть необходимость изменять размер или значение объекта после создания. Неизменяемые лучше применять когда объект останется всегда в том виде в котором был создан.
  • Неизменяемые объекты принципиально дороже в использовании когда их часто требуется "менять", так как любое изменение создаёт копию объекта.

Исключения в неизменяемости

В некоторых случаях неизменяемые объекты могут выглядеть как изменяемые.

Рассмотрим неизменяемый тип кортеж (tuple). Значения кортежа не могут быть изменены после создания. Но значениями кортежа являются последовательность переменных с неизменяемой привязкой к объектам. Это ключевой момент, связка объекта и переменной (или ссылка на объект) является неизменяемой, но не сам объект с которым связана переменная.

Рассмотрим кортеж

t = (‘holberton’, [1, 2, 3])
1

Кортеж t содержит элементы разных типов. Первый элемент это неизменяемая строка, а второй изменяемый список. Кортеж неизменяемый и не содержит методов для изменения своего содержимого. То же самое относится к строке. Но список изменяемый и содержит методы для изменения своих значений. Содержимое неизменяемого кортежа не может быть изменено, но изменяемые объекты входящие в кортеж могут менять свои значения.

Как объекты передаются в функции

При передачи параметров в функции изменяемые объекты ведут себя аналогично тому что в других языках называется "передача по ссылке". Изменения объекта внутри функции отражаются на исходном объекте:

def updateList(list1):
    list1 += [10]

n = [5, 6]
print(id(n))                  # 17357576

updateList(n)

print(n)                      # [5, 6, 10]
print(id(n))                  # 17357576
1
2
3
4
5
6
7
8
9
10

Неизменяемые объекты ведут себя так как будто происходит "передача по значению". Изменение объекта внутри функции не влияет на исходных объект:

def updateNumber(n):
    print(id(n))
    n += 10

b = 5
print(id(b))                   # 1552410608

updateNumber(b)                # 1552410608
print(b)                       # 5
1
2
3
4
5
6
7
8
9
Последниее изменение: 24.08.2023, 06:42:55