Изменяемые и неизменяемые типы данных в Python
Оригинальная статья: Bob — Mutable vs Immutable Data Types in Python
Задумывались ли вы, почему в Python есть изменяемые и неизменяемые типы?
Вы когда-нибудь сталкивались с подобной ошибкой в Python?
>>> s = 'hello' >>> s[0] = 'H' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'str' object does not support item assignment
В этой статье я приведу несколько практических примеров и покажу некоторые преимущества использования неизменяемых типов.
Типы
Согласно справочнику по языку Python, раздел Модель данных:
Значение некоторых объектов может измениться. Объекты, чье значение может измениться, называются изменяемыми; объекты, значение которых неизменяемо после их создания, называются неизменяемыми … Изменчивость объекта определяется его типом; например, числа, строки и кортежи неизменны, а словари и списки изменчивы.
Давайте посмотрим на некоторые примеры.
Создание строки String
Когда я начал изучать Python, меня не слишком волновало как происходит конкатенации строк. Я часто использовал длинные цепочки строительного кода типа такого:
>>> s = 'hello' >>> s += 'world' >>> s += ...
Однако, если мы посмотрим на id каждой строки во время создание всего предложения мы увидем:
>>> s = 'hello' >>> id(s) 4341555696 >>> s += 'world' >>> id(s) 4341545584 => new object created!
Видно на каждом этапе создание предложения создается новая строка. Что может быть иногда не эффективно с точки зрения производительности. Возможно в подобной ситуации предпочтительно использовать изменяемый тип (например список):
>>> l = ['hello'] >>> id(l) 4341463496 >>> l.append('world') >>> id(l) 4341463496 => same object
Использование списков в данной ситуации будет обходится дешевле с точки зрения производительности, потому что вы можете изменить размер объекта на лету.
С другой стороны, размер неизменяемых типов заранее известен в памяти, что делает их более быстрыми во время доступа к ним (Более подробное можно почитать тут: Кортежи имеют тенденцию работать лучше, чем списки — Tuples tend to perform better than lists).
Неизменность
Еще одним преимуществом неизменяемых типов является гарантия того, что эти объекты никогда не изменятся.
Изменяемые типы могут неожиданно быть изменены где-либо в вашей программе:
>>> l ['hello', 'world'] >>> ll = l # где-то была сделана shallow копия >>> l[0] = 'spam' >>> l ['spam', 'world'] >>> ll ['spam', 'world'] # Опс, не преднамеренное поведение!
Или вот еще несколько коварных проблем:
- Изменяемые аргументы по умолчанию, общий анти-шаблон
- Сложные объекты — Compound objects
- Несколько потоков, изменяющих объект (хотя вы можете использовать блокировку)
- Изменчивые объекты / общее состояние (ООП) могут привести к условиям гонки (пример)
Дальнейшее чтение: 5 Benefits of Immutable Objects Worth Considering for Your Next Project
Небольшое дополнение
Обратите внимание, что неизменность иногда не гарантируется на 100%. Например, вы можете иметь кортеж со списком внутри него:
>>> a = (1, [2, 3], 4) >>> a[0] = 2 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> a[1].append(3.5) >>> a (1, [2, 3, 3.5], 4)
Просто нужно с осторожностью относиться.
При этом этот пример идеально согласуется с понятием неизменности кортежей. Кортеж содержит ссылку на список — и список может быть изменен, но не может быть заменен другим списком.
Исследуя немного больше, я наткнулся на статью Лучано Рамальо «Python tuples: immutable but potentially changing», которая интересна в этом контексте:
Неизменным является физическое содержимое кортежа, состоящее только из ссылок на объекты. Значение списка, на который ссылается допустим некий список dum[1], может изменится, но идентификатор объекта, на который ссылаются, будет все тот же. У кортежа нет способа предотвратить изменение значений его элементов, которые являются независимыми объектами и могут быть доступны через ссылки вне кортежа. Списки и другие изменяемые объекты внутри кортежей могут изменяться, но их идентификаторы всегда будут одинаковыми.
React и функциональное программирование
Да, давайте немного перейдем к JS. Если вы хотите узнать больше о парадигмах неизменяемости и функционального программирования, интересно взглянуть на React:
Проще проверить, равны ли два объекта, если они неизменны, и React использует эту концепцию для оптимизации производительности.
Более подробно: Master the JavaScript Interview: What is Functional Programming?
Функциональный код имеет тенденцию быть более лаконичным, более предсказуемым и более простым для тестирования, чем императивный или объектно-ориентированный код, но если вы не знакомы с ним и общими шаблонами, связанными с ним, функциональный код также может показаться более сложным, и документация по нему может быть непроницаемой для новичков.
Я надеюсь, что это статья обратит ваше внимание на изменяемые и неизменяемые типы данных и что это значит для вашего кода …
Сохраняйте спокойствие и пишите код на Python!
— Bob
спасибо, статья была полезной
Четко, понятно. Спасибо.