Python неизменяемые типы данных: Синтаксис Python: изменяемые и неизменяемые типы данных | PyNSK
Синтаксис Python: изменяемые и неизменяемые типы данных | PyNSK
Все типы данных в Python относятся к одной из 2-х категорий: изменяемые (mutable) и неизменяемые (unmutable).
Многие из предопределённых типов данных Python — это типы неизменяемых объектов:
- числовые данные (int, float, complex)
- символьные строки (class ‘str’)
- кортежи (tuple)
Другие типы определены как изменяемые:
- списки (list)
- множества (set)
- словари (dict).
Вновь определяемые пользователем типы (классы) могут быть определены как неизменяемые или изменяемые.
Изменяемость объектов определённого типа является принципиально важной характеристикой, определяющей, может ли объект такого типа выступать в качестве ключа для словарей (dict) или нет.
Подробнее по ссылке — https://www. ibm.com/developerworks/ru/library/l-python_details_02/
Date
Categories
Синтаксис Python
Tags
типы данных
Share on Twitter
Share on Facebook
Предлагаем почитать:
Списки в Python: изменяемость, доступ к элементам
Список представляет собой последовательность в Python. Словарное значение списка — «некоторое количество связанных элементов или имен, написанных или напечатанных последовательно».
Мы часто используем списки и в повседневной жизни (например, составление списка покупок), и в программах (например, создание списка простых чисел). Мы составляем списки всякий раз, когда хотим сгруппировать определенные элементы по определенным критериям.
Список в Python предоставляет те же функциональные возможности, позволяющие группировать элементы с возможностью произвольного доступа к каждому элементу, изменения каждого элемента, добавления или удаления элемента из него.
Итак, начнем с создания списка.
list1 = [1,2,3,4,5] >>> list1 [1, 2, 3, 4, 5] >>> type(list1) <type 'list'>
type() — это функция в Python, которая возвращает тип объекта переменной.
Создать список в Python очень просто. Вы можете сделать это двумя способами. Первый: заключить в квадратные скобки элементы, которые мы видели в приведенном выше примере. Другой — использовать функцию list().
>>> list1 = list([1,2,3,4,5]) >>> list1 [1, 2, 3, 4, 5] >>> type(list1) <type 'list'>
У списков есть интересная особенность: они хранят ссылки на объекты или элементы в нем. Таким образом, при переназначении списка на другую переменную Python изменяет только ссылку, а не создает новый объект списка.
# id() function returns the object id. >>> id(list1) 4426491160 >>> list2 = list1 >>> id(list2) 4426491160
Мы видим, что обе переменные ссылаются на один и тот же объект. Это очень сильно ускоряет выполнение программы. Список — это глобальная переменная, то есть, когда вы объявляете список и передаете его функции в качестве аргумента, а не копируете и передаете функции, Python передает ссылку на список.
Доступ к элементам
Python назначает индекс каждому из элементов списка, нумерация идет с нуля. Итак, если вы хотите получить доступ к определенному элементу в списке, вы можете обратиться к нему по его индексу. Для этого вы должны знать индекс элемента. Впрочем, даже если вы этого не знаете, не беспокойтесь, для этого есть одно решение. Но пока давайте попробуем получить доступ к элементам по их индексу.
>>> list1 [1, 2, 3, 4, 5] >>> print(list1[0]) 1 >>> print(list1[2]) 3 >>> print(list1[1]) 2
Python выбросит IndexError
, если вы передадите индекс, который не связан со списком, или если этот индекс не ссылается на объект.
>>> list1 [1, 2, 3, 4, 5] >>> print(list1[9]) Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range >>>
Бывают ситуации, когда вы знаете, к какому элементу вы хотите получить доступ, но не знаете его индекс. В таких ситуациях вы можете найти этот элемент в соответствующем списке, а функция поиска (функция index()
в случае списков) возвращает индекс этого элемента.
>>> list1 [1, 2, 3, 4, 5] >>> list1.index(2) 1 // index of 2
Поведение списков при изменении
Список как тип данных относится к категории изменяемых структур данных. Слово «изменяемый» означает, что вы можете вносить любые изменения в структуру данных даже после ее определения. Итак, какие изменения вы можете произвести по отношению к списку? Вы можете обновить, добави
Изменяемые и неизменяемые объекты в Python
Перевод статьи Mutable vs Immutable Objects in Python.
Все значения в Python это объекты. Объекты делятся на изменяемые и неизменяемые.
Каждая переменная ссылается на экземпляр объекта. При создании, объекту присваивается уникальный идентификатор (object id) и тип объекта. Тип объекта не меняется после создания, но может изменится состояние объекта. Изменяемые объекты меняют своё состояние после создания, а неизменяемые сохраняются в том виде в котором были созданы.
Встроенные неизменяемые типы: int
, float
, bool
, str
, tuple
, unicode
. Встроенные изменяемые типы list
, set
, dict
. Пользовательские классы обычно изменяемы. Для имитирования неизменяемости переопределите методы изменения и удаления значений чтобы они возвращали исключение.
Чтобы узнать ссылается ли переменная на изменяемый или неизменяемый рассмотрим подробнее функции 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 >>> x = «Holberton» >>> y = «Holberton» >>> id(x) 140135852055856 >>> id(y) 140135852055856 >>> print(x is y) »’comparing the types»’ True |
# Пример 2
>>> a = 50
>>> type(a)
<class: ‘int’>
>>> b = «Holberton»
>>> type(b)
<class: ‘string’>
| # Пример 2 >>> a = 50 >>> type(a) <class: ‘int’> >>> b = «Holberton» >>> type(b) <class: ‘string’> |
Проверим, с помощью этих функций, какие типы являются изменяемыми, а какие нет.
Изменяемые и неизменяемые объекты
Изменяемые объекты могут изменять свое состояние или содержимое, неизменяемые не могут. Практический пример проверки на изменяемость:
Python для лаборатории | Изменяемые и неизменяемые объекты
от Акилеса Караттино
23 августа 2018 г.
изменчивый
уп
неизменный
объекты
Люди, начинающие программировать на Python, быстро обнаруживают существование списков и кортежей. Оба определены одинаково и выглядят одинаково. Иногда они даже используются как взаимозаменяемые. Таким образом, возникает очевидный вопрос: почему у нас есть два разных типа элементов для одной и той же цели? Ответ заключается в понимании различий между изменяемыми и неизменяемыми типами данных в Python.
Даже после программирования приложений Python в течение некоторого времени может оказаться трудным выбор между списками или кортежами. Иногда последствия приводят к появлению неясных ошибок, которые очень трудно найти и исправить. В этой статье мы обсудим различия между списками и кортежами или, в более общем смысле, изменяемые и неизменяемые типы данных и то, как их можно использовать в наших программах.
Списки и кортежи
В Python, когда мы хотим определить список, мы можем сделать следующее:
>>> var1 = [1, 2, 3]
И мы можем получить его элементы по их положению:
>>> var1 [0]
1
>>> var [1]
2
Если мы хотим заменить значение элемента, мы можем сделать следующее:
>>> var1 [0] = 0
>>> var1 [0]
0
Мы можем сделать то же самое с кортежем, в определении которого используется ()
вместо []
:
>>> var2 = (1, 2, 3)
>>> var2 [0]
1
Однако, если мы попытаемся изменить значение элемента, мы получим ошибку:
>>> var2 [0] = 0
Отслеживание (последний вызов последний):
Файл "", строка 1, в
TypeError: объект 'tuple' не поддерживает присвоение элемента
Это первое важное различие между списком и кортежем. После определения кортежи не могут изменять свои значения, но списки могут. В этом смысле мы можем сказать, что кортежи — это неизменяемых , а списки — изменяемые . Решение о том, когда использовать тот или иной вариант, будет зависеть от приложения. Следует учитывать одно отличие: кортежи работают очень быстро, когда нам нужно получить доступ к их значениям. Тем не менее, списки намного эффективнее используют память, если нам когда-нибудь понадобится их расширить на более позднем этапе.
Возможность изменять переменную после ее определения — вот что делает объекты изменяемыми или неизменяемыми.Кортежи и списки — это только первые примеры. Мы можем глубже понять, как работает Python.
Изменяемые и неизменяемые типы данных
Вдохновленные превосходной статьей, написанной Лучано Рамальо, мы можем рассматривать переменные в Python как метки, а не как блоки. В Python переменная — это метка, которую мы присваиваем объекту; это то, как мы, люди, должны это идентифицировать. Однако важны данные, лежащие в основе метки, ее значение и тип.
Полезным инструментом для понимания этой концепции является функция id
.Мы можем применить его к любой переменной, и она вернет свою идентичность. Если мы хотим быть уверены в том, что имеем дело с одним и тем же объектом, мы можем проверить, одинаково ли значение, возвращаемое идентификатором id
. Мы можем сделать следующее:
>>> var1 = [1, 2, 3]
>>> var2 = (1, 2, 3)
>>> идентификатор (var1)
44045192
>>> идентификатор (var2)
43989032
Легко видеть, что обе переменные имеют разные идентичности. Теперь мы можем расширить список и кортеж некоторыми новыми значениями и проверить, совпадают ли их идентификаторы:
>>> var1 + = [4, 5]
>>> var2 + = (4, 5)
>>> print (var1)
[1, 2, 3, 4, 5]
>>> print (var2)
(1, 2, 3, 4, 5)
>>> идентификатор (var1)
44045192
>>> идентификатор (var2)
30323024
Приведенный выше код уже показывает кое-что интересное: мы добавили одинаковые значения как к списку ( var1,
), так и к кортежу ( var2
). Однако, если мы спросим их идентификатор, мы увидим, что var1
не изменил свой идентификатор, а var2
имеет новый. Это означает, что мы расширили список, но создали совершенно новый кортеж. Это одна из причин, почему управление памятью более эффективно для списков, чем для кортежей, когда мы пытаемся их расширить.
Кортежи — не единственный неизменяемый тип данных в Python. Тем не менее, они являются отличным инструментом для изучения, потому что их можно напрямую сравнивать со списками, которые можно изменять.Другие неизменяемые типы данных:
- внутренний
- поплавок
- десятичное
- комплекс
- булев
- строка
- кортеж
- диапазон
- морозильник
- байтов
Возможно, мы не думали об этом раньше, но когда мы присваиваем переменной целое число, число с плавающей запятой и т. Д., Ее нельзя заменить. Мы можем проверить это, проверив этот код:
>>> var1 = 1
>>> идентификатор (var1)
1644063776
>>> var1 + = 1
>>> идентификатор (var1)
1644063808
Вы видите, что совершенно новый var1
создается, когда мы добавляем значение самому себе; следовательно, его идентичность меняется. То же самое произойдет со всеми другими типами данных, перечисленными выше.
Изменяемые объекты , с другой стороны, следующие:
- список
- словарь
- комплект
- массив байтов
- пользовательские классы
Это те объекты, которые можно изменять на месте, не создавая новый для хранения обновленных значений. Вот почему мы можем расширить список без изменения его идентификатора или изменить словарь, сохранив тот же базовый объект:
>>> var1 = {'a': 1, 'b': 2}
>>> идентификатор (var1)
140711021092288
>>> var1 ['b'] = 3
>>> идентификатор (var1)
140711021092288
>>>
Две метки для одного объекта
Интересный образец дает два имени (т.е. две метки) к одной и той же переменной, например:
>>> var1 = [0, 1, 2]
>>> var2 = var1
>>> идентификатор (var1)
44372872
>>> идентификатор (var2)
44372872
И var1
и var2
имеют одинаковый идентификатор, что означает, что они являются метками для одного и того же объекта. В Python мы можем проверить это, используя is
вместо сравнения идентичности:
>>> var1 - это var2
Правда
А если обновить одно из значений var1
:
>>> var1 + = [3, 4, 5]
>>> print (var2)
[0, 1, 2, 3, 4, 5]
>>> var1 - это var2
Правда
Мы видим, что после обновления значения var1
значение var2
также изменилось.Это происходит только с изменяемыми типами. С неизменяемыми объектами, поскольку новый объект создается для обновления значения, каждое имя будет указывать на другой объект. Тот же пример, что и раньше, но с кортежами:
>>> var1 = (1, 2)
>>> var2 = var1
>>> var1 - это var2
Правда
>>> var1 + = (3, 4)
>>> var1 - это var2
Ложь
>>> var2
(1, 2)
Одинаковые объекты
Иногда нам нужно сравнить, имеют ли две переменные одинаковые базовые значения, а не указывают ли они на один и тот же объект.Мы можем использовать оператор ==
для сравнения содержимого, а не идентичности объектов. Мы можем определить два списка с одинаковыми значениями:
>>> var1 = [1, 2, 3]
>>> var2 = [1, 2, 3]
Если мы проверим идентификаторы var1
и var2
, мы получим, что это разные объекты:
>>> var1 - это var2
Ложь
Хотя мы видим, что они одинаковы (мы определили, что они имеют одинаковые значения), это два разных объекта.Если мы хотим сравнить значения вместо идентичностей, мы можем
сделать следующее:
>>> var1 == var2
Правда
Пример выше также работает, если мы определили бы кортежи вместо списков. Тот факт, что содержимое одинаково, недостаточно, чтобы знать, указывают ли переменные на один и тот же объект.
Синглтоны
Не вдаваясь в подробности, стоит упомянуть, что существует тип объекта, называемый синглтоном.По определению, это объекты, которые можно создать только один раз. Следовательно, любая указывающая на них переменная должна указывать на один и тот же объект. Давайте посмотрим на быстрый пример с использованием некоторых целых чисел:
>>> а = 1
>>> b = 1
>>> а равно 1
Правда
>>> а это б
Правда
>>> а == б
Правда
В Python целые числа от -5 до 256 являются одиночными. Переменная, указывающая на любой из них, будет иметь тот же идентификатор, что и любая другая переменная, указывающая на то же число.Этот подход гениален для экономии памяти, потому что у нас есть только одно целое число и столько переменных, сколько мы хотим указать на него. Но целые числа — не единственные одиночные числа. Например, логические значения и None
также являются синглетонами:
>>> a = Верно
>>> а верно
Правда
>>> b = Нет
>>> b - Нет
Правда
>>> b == Нет
Правда
Использование - это
вместо ==
имеет другие преимущества. Первое — это скорость.Мы можем запустить в командной строке следующее:
python -m timeit "1 == 1"
А потом:
python -m timeit "1 равно 1"
В среднем первое выражение занимает около 20 наносекунд, а второе — около 17 наносекунд. Синглтоны — это тема, которую нужно рассматривать независимо, потому что мы также можем определить свои собственные.
Изменяемые объекты и функции
Мы только что видели, что если у нас есть два изменяемых объекта с одинаковым идентификатором, это один и тот же объект.Если мы изменим одно, мы изменим и другое. То же самое применимо при работе с функциями, которые принимают изменяемые объекты в качестве аргументов. Представьте, что мы разрабатываем функцию, которая принимает на вход список, делит все свои аргументы на два, а затем возвращает среднее значение. Функция будет выглядеть так:
def div_and_average (var):
для i в диапазоне (len (var)):
var [i] / = 2
avg = сумма (var) / len (var)
возврат в среднем
Очень интересно посмотреть, что происходит, когда мы используем эту функцию:
my_list = [1, 2, 3]
печать (разделить_и_среднее (мой_лист))
печать (мой_лист)
Вывод будет:
1. 0
[0,5, 1,0, 1,5]
Когда мы выполняем функцию, мы меняем значения переменной my_list
. Это очень мощно, потому что позволяет нам изменять элементы списка на месте , когда мы возвращаем другой элемент. Однако иногда мы не хотим этого делать и хотим сохранить значение исходного списка. Может показаться хорошей идеей создать новую переменную. Например:
def div_and_average (var1):
var = var1
[...]
Однако мы увидим, что это не меняет вывод. Как мы видели ранее, идентификаторы var
и var1
будут одинаковыми. Чтобы обойти это, мы можем сделать копию объекта с помощью модуля copy
:
импортная копия
def div_and_average (var1):
var = copy.copy (var1)
[...]
Мы видим, что исходная переменная my_list
не изменилась. То, что мы только что сделали, называется мелкой копией объекта.Также возможно выполнить копию на глубину , но мы оставим ее последствия для другой статьи. Вы можете проверить Глубокие и неглубокие копии объектов, чтобы узнать больше о предметах.
Аргументы по умолчанию в функциях
Распространенной практикой при определении функции является присвоение ее аргументам значений по умолчанию. С одной стороны, это позволяет нам включать новые параметры без изменения кода нисходящего потока. Тем не менее, он также позволяет нам вызывать функцию с меньшим количеством аргументов, что упрощает использование.Давайте посмотрим, например, на функцию, которая увеличивает значение
элементы списка. Код будет выглядеть так:
def Увеличить_значения (var1 = [1, 1], значение = 0):
значение + = 1
var1 [0] + = значение
var1 [1] + = значение
вернуть var1
Если мы вызовем эту функцию без аргументов, она будет использовать значение по умолчанию [1, 1]
для списка и значение увеличения по умолчанию 0
. Что произойдет, если мы используем эту функцию дважды без аргументов?
печать (увеличить_значения ())
печать (увеличение_значения ())
В первый раз он печатает [2, 2]
, как ожидалось, но во второй раз он печатает [3, 3]
. Это означает, что аргумент функции по умолчанию меняется каждый раз, когда мы ее запускаем. Когда мы запускаем скрипт, Python оценивает определение функции только один раз и создает список по умолчанию и значение по умолчанию. Поскольку списки изменяемы, каждый раз, когда мы вызываем функцию, мы меняем ее аргумент по умолчанию. Однако значение , значение
является неизменным и остается неизменным для всех последующих вызовов функций.
Следующий логичный вопрос: как этого не допустить? Короткий ответ — использовать неизменяемые типы в качестве аргументов по умолчанию для функций.Мы могли бы использовать Нет
, например:
def Увеличить_значения (var1 = None, value = 0):
если var1 равно None:
var1 = [1, 1]
...
Конечно, решение всегда зависит от варианта использования. Мы можем захотеть обновить значение по умолчанию от одного вызова к другому. Представьте себе случай, когда мы хотим выполнить дорогостоящие вычисления. Тем не менее, мы не хотим дважды запускать функцию с одним и тем же входом и вместо этого использовать кеш значений.Мы могли сделать следующее:
def вычислить (var1, var2, cache = {}):
пытаться:
значение = кеш [var1, var2]
кроме KeyError:
значение = дорого_вычисление (переменная1, переменная2)
кеш [var1, var2] = значение
возвращаемое значение
Когда мы запускаем Calculate
в первый раз, в словаре cache
ничего не будет храниться. Когда мы выполняем функцию более одного раза, cache
начнет изменяться, добавляя новые значения.Если мы в какой-то момент повторим аргументы, они станут частью словаря, и сохраненное значение будет возвращено. Обратите внимание, что мы используем обработку исключений, чтобы не проверять явным образом, существует ли уже комбинация значений в памяти.
Наши неизменные объекты
Python очень гибкий, и он дает нам большой контроль над тем, как настроить его поведение. Как видно из списка в начале этой статьи, пользовательские классы принадлежат к изменяемым типам.Но что произойдет, если мы захотим определить неизменяемые объекты? Ответ состоит в том, чтобы изменить поведение класса при назначении атрибутов, чего мы можем добиться, повторно реализовав метод __setattr__
.
класс MyImmutable:
def __setattr __ (я, ключ, значение):
Raise TypeError ('MyImmutable не может быть изменен после создания экземпляра')
Если мы создадим экземпляр класса и попытаемся присвоить значение его атрибуту, появится ошибка:
>>> my_immutable = MyImmutable ()
>>> my_immutable.var1 = 2
Отслеживание (последний вызов последний):
Файл ". \ AE_custom_objects.py", строка 14, в
my_immutable.var1 = 2
Файл ". \ AE_custom_objects.py", строка 7, в __setattr__
поднять TypeError ('MyImmutable не может быть изменен после создания экземпляра')
TypeError: MyImmutable не может быть изменен после создания экземпляра
У нас есть объект, который мы не можем изменить после создания экземпляра. Но это также означает, что мы ничего не можем с этим поделать. Представьте, что мы хотели бы сохранить некоторые начальные значения.Если мы создадим стандартный метод __init__
, он потерпит неудачу:
класс MyImmutable:
def __init __ (self, var1, var2):
self.var1 = var1
self.var2 = var2
[...]
Как только мы попытаемся создать экземпляр этого класса, будет вызвана ошибка TypeError
. Даже внутри самого класса присвоение значений атрибутам достигается с помощью метода __setattr__
. Чтобы обойти это, нам нужно использовать объект super ()
:
класс MyImmutable:
def __init __ (self, var1, var2):
супер().__setattr __ ('переменная1', переменная1)
super () .__ setattr __ ('переменная2', переменная2)
def __setattr __ (я, ключ, значение):
поднять TypeError ('MyImmutable не может быть изменен после создания экземпляра')
def __str __ (сам):
вернуть 'MyImmutable var1: {}, var2: {}'. format (self.var1, self.var2)
Что теперь мы можем использовать следующим образом:
>>> my_immutable = MyImmutable (1, 2)
>>> печать (my_immutable)
MyImmutable var1: 1, var2: 2
>>> my_immutable.var1 = 2
[...]
TypeError: MyImmutable не может быть изменен после создания экземпляра
Это своего рода обходной путь, но, возможно, мы сможем найти применение этому типу шаблона. Еще один интересный ресурс, который стоит проверить — это [namedtuple] https://docs.python.org/3/library/collections.html#collections. namedtuple). Как следует из названия, он позволяет нам иметь неизменяемые объекты с именованными атрибутами. Его исходный код может стать отличным источником вдохновения для понимания внутренней работы Python.
Выводы
Понимание различий между изменяемыми и неизменяемыми типами Python не является важной темой, пока не станет слишком поздно.В большинстве случаев мы можем разрабатывать сложные приложения, обменивая кортежи на списки. Мы можем даже изменять значение переменной внутри функции, не осознавая этого и без значительных последствий. Но в конечном итоге может случиться так, что мы обнаружим серьезную ошибку, которую трудно отследить, и которая может быть связана с использованием (или неправильным использованием) изменяемых типов.
От себя лично обнаружил такую ошибку, проводя сложный эксперимент с микроскопом. Я хотел иметь возможность автоматически перефокусироваться на определенных ярких точках после получения изображения.Первое время алгоритм работал нормально. Во второй раз все было нормально, но в третий и последующие даже близко не подошли к желаемым значениям. Проблема заключалась в определении начального диапазона для сканирования в виде списка и делении его на коэффициент после каждой итерации.
Пример кода доступен на Github
Если вы хотите продолжить обучение, вы можете узнать больше о том, почему кажется, что кортежи меняются, и что происходит, когда вы используете изменяемые или неизменяемые переменные в качестве атрибутов класса.
Типы данных Python
Тип данных определяет тип переменной, будь то целочисленная переменная, строковая переменная, кортеж, словарь, список и т. Д. В этом руководстве вы узнаете о типах данных и их использовании в Python.
Типы данных Python
Типы данных
Python делятся на две категории: изменяемые типы данных и неизменяемые типы данных.
Неизменяемые типы данных в Python
1. Числовой
2. Строка
3.Кортеж
Изменяемые типы данных в Python
1. Список
2. Словарь
3. Установить
1. Числовой тип данных в Python
Integer — В Python 3 нет верхней границы для целого числа, что означает, что мы можем иметь значение настолько большое, насколько позволяет наша системная память.
# Целое число число = 100 печать (число) print ("Тип данных переменной num равно", type (num))
Выход:
Long — Тип данных Long не рекомендуется в Python 3, потому что в нем нет необходимости, поскольку целое число не имеет верхнего предела, нет смысла иметь тип данных, который допускает больший верхний предел, чем целые числа.
Float — Значения с десятичной точкой являются значениями с плавающей запятой, указывать тип данных в Python не требуется. Он автоматически определяется на основе значения, которое мы присваиваем переменной. Например, здесь fnum — это тип данных с плавающей запятой.
# число с плавающей запятой fnum = 34,45 печать (fnum) print ("Тип данных переменной fnum равен", type (fnum))
Выход:
Комплексное число — Числа с действительной и мнимой частью называются комплексными числами.В отличие от других языков программирования, таких как Java, Python может идентифицировать эти комплексные числа со значениями. В следующем примере, когда мы печатаем тип переменной cnum, он печатается как комплексное число.
# комплексное число cnum = 3 + 4j печать (cnum) print ("Тип данных переменной cnum равен", type (cnum))
Вывод:
9. Мутация — документация Python Tips 0.1
Изменяемые и неизменяемые типы данных в Python вызывают много головной боли
для начинающих программистов.Проще говоря, изменчивый означает «возможность изменения».
а неизменяемый означает «постоянный». Хотите, чтобы у вас закружилась голова? Учти это
пример:
foo = ['привет'] печать (foo) # Вывод: ['привет'] bar = foo bar + = ['пока'] печать (foo) # Вывод: ['привет', 'пока']
Что только что произошло? Мы этого не ожидали! Мы ждали
примерно так:
foo = ['привет'] печать (foo) # Вывод: ['привет'] bar = foo bar + = ['пока'] печать (foo) # Ожидаемый результат: ['привет'] # Вывод: ['привет', 'пока'] печать (полоса) # Вывод: ['привет', 'пока']
Это не ошибка.Это изменчивость в действии. Всякий раз, когда вы назначаете
в другую переменную изменяемого типа данных, любые изменения
данные отражаются обеими переменными. Новая переменная — это просто псевдоним
для старой переменной. Это верно только для изменяемых типов данных. Вот
Попался, связанный с функциями и изменяемыми типами данных:
def add_to (число, цель = []): target.append (число) вернуть цель add_to (1) # Вывод: [1] add_to (2) # Вывод: [1, 2] add_to (3) # Вывод: [1, 2, 3]
Вы могли ожидать, что он будет вести себя иначе.Вы могли ожидать
что новый список будет создан при вызове add_to
следующим образом:
def add_to (число, цель = []): target.append (число) вернуть цель add_to (1) # Вывод: [1] add_to (2) # Вывод: [2] add_to (3) # Вывод: [3]
И снова эту боль вызывает изменчивость списков. В
Python аргументы по умолчанию оцениваются один раз, когда функция
определяется не каждый раз, когда функция вызывается. Вы никогда не должны определять
аргументы по умолчанию изменяемого типа, если вы не знаете, что делаете.Вы должны сделать что-то вроде этого:
def add_to (element, target = None): если цель - Нет: target = [] target.append (элемент) вернуть цель
Теперь всякий раз, когда вы вызываете функцию без аргумента target
,
новый список создан. Например:
add_to (42) # Вывод: [42] add_to (42) # Вывод: [42] add_to (42) # Вывод: [42]
Типы данных Python
- Подписывайтесь на нас
- Python
- ASP.NET Core
- MVC
- IoC
- Веб-API
- C #
- TypeScript
- Node.js
- Больше
✕
. Учебники .NET
- ASP.NET Core
- ASP.NET MVC
- IoC
- веб-API
- C #
- LINQ
Учебники по скриптам
- TypeScript
- AngularJS 1
- Узел.js
- D3.js
- jQuery
- JavaScript
Другие учебные пособия
- Python
- Sass
- HTTPS
Тесты навыков
- ASP.NET Core
- ASP.NET MVC
- LINQ
- C #
- веб-API
- IoC
- TypeScript
- AngularJS
- Node.js
- jQuery
- JavaScript
- Статьи
- Тесты
- Напишите нам
- Учебники по Python
- Python — начало работы
- Что такое Python?
- Где использовать Python?
- История версий Python
- Установить Python
- Python — оболочка / REPL
- Python — IDLE
- Python — IDE
- Python — синтаксис
- Python — получение пользовательского ввода
- Python — отображение вывода
- Python — Ключевые слова
- Python — переменные
- Python — Типы данных
- номер
- Строка
- Список
- Кортеж
- Задавать
- толковый словарь
- Python — Операторы
- Python — если, элиф, еще
- Python — цикл пока
- Python — цикл For
Разница между изменяемым и неизменяемым в Python
Все в Python — это объект .Вы должны понимать, что Python представляет все свои данные как объекты. Изменчивость объекта определяется его типом. Некоторые из этих объектов, например списки и словари, являются изменяемыми , что означает, что вы можете изменять их содержимое, не меняя их идентичности. Другие объекты, такие как целые числа, числа с плавающей запятой, строки и кортежи, не могут быть изменены.
Строки неизменяемы
Строки неизменяемы в Python, что означает, что вы не можете изменить существующую строку.Лучшее, что вы можете сделать, — это создать новую строку, которая является вариацией исходной.
пример
message = «неизменяемые строки»
сообщение [0] = ‘p’
печать (сообщение)
Вместо вывода «ptrings immutable» этот код выдает ошибку времени выполнения:
TypeError: объект ‘str’ не поддерживает назначение элементов
Почему строки Python неизменяемы?
Это означает, что строковое значение не может быть обновлено .Неизменяемость — это чистое и эффективное решение для одновременного доступа. Наличие неизменяемых переменных означает, что независимо от того, сколько раз метод вызывается с одной и той же переменной / значением, результат всегда будет одним и тем же. Наличие изменяемых переменных означает, что вызов одного и того же метода с теми же переменными не может гарантировать тот же результат, потому что переменная может быть изменена в любое время другим методом или, возможно, другим потоком, и именно здесь вы начинаете сходить с ума от отладки .
Список изменяемый
Пример изменяемого
my_list = [10, 20, 30]
печать (мой_лист)
выход
[10, 20, 30]
продолжить …
my_list = [10, 20, 30]
my_list [0] = 40
печать (мой_лист)
выход
[40, 20, 30]
Кортеж неизменяемый
Неизменяемый пример
my_yuple = (10, 20, 30)
печать (my_yuple)
выход
(10, 20, 30)
продолжить…
my_yuple = (10, 20, 30)
my_yuple [0] = 40
печать (my_yuple)
выход
Отслеживание (последний вызов последний):
Файл «test.py», строка 3, в
my_yuple [0] = 40
TypeError: объект ‘tuple’ не поддерживает назначение элементов
Если вы хотите написать наиболее эффективный код, вы должны знать разницу между mutable и immutable в python. Объединение строк в циклы тратит много памяти , поскольку строки неизменяемы, объединение двух строк вместе фактически создает третью строку, которая является комбинацией двух предыдущих.Если вы много итерируете и создаете большую строку, вы потратите много памяти на создание и выбрасывание объектов. Используйте технику соединения со сжатием списка.
Python по-разному обрабатывает изменяемые и неизменяемые объекты. Неизменяемые объекты быстрее доступны, чем изменяемые объекты. Кроме того, неизменяемые объекты принципиально дорого «изменять», потому что это требует создания копии. Изменение изменяемых объектов обходится недорого.
Ищете работу на Python?
Скорее всего, вам нужно будет доказать, что вы знаете, как работать с Python.Эти вопросы для собеседования по Python были разработаны специально, чтобы познакомить вас с характером вопросов, с которыми вы можете столкнуться во время собеседования по предмету Программирование на Python . Вот основные примеры вопросов для собеседования на Python, и ответы на них даны чуть ниже. Эти примеры вопросов составлены нашей командой экспертов, которая тренируется по Python training , чтобы дать вам представление о типах вопросов, которые могут быть заданы на собеседовании.
Перейти к … Вопросы для собеседования по Python
Кортежи Python неизменяемы, за исключением случаев, когда они изменяемы
Пролог
«Когда я использую слово, — пренебрежительно сказал Шалтай-Болтай, — оно означает именно то, что я выбрал для его значения — ни больше, ни меньше».
«Вопрос в том, — сказала Алиса, — можешь ли ты сделать слова значимыми так много разных вещей».
«Вопрос в том, — сказал Шалтай-Болтай, — кто должен быть хозяином — вот и все.’
Являются ли кортежи изменяемыми или неизменяемыми?
В Python кортежи неизменяемы, а «неизменяемость» означает, что значение не может измениться. Это хорошо известные основные факты о Python. Хотя кортежи — это больше, чем просто неизменяемые списки (как объясняется в главе 2 превосходного «Свободного Python» Лучано Рамальо), здесь есть некоторая двусмысленность. Лучано написал отличное сообщение в блоге на эту тему.
Прежде чем мы сможем получить подробный ответ на вопрос «Кортежи изменчивы или неизменны?» , нам нужна дополнительная информация.
Некоторая справочная информация
Согласно модели данных Python, «объекты являются абстракцией Python для данных, и все данные в программе Python представлены объектами или отношениями между объектами». Каждое значение в Python — это объект, включая целые числа, числа с плавающей запятой и логические значения. В Java это «примитивные типы данных», которые считаются отдельными от «объектов». Не так в Python. Каждое значение в Python является объектом, и фантастический доклад Неда Бэтчелдера «Факты и мифы об именах и значениях Python» Неда Батчелдера более подробно описывает это.
Таким образом, объект datetime.datetime (2018, 2, 4, 19, 38, 54, 798338)
datetime является не только объектом, но и целым числом 42
, а логическое значение True
— объектом.
Все объекты Python имеют три вещи: значение, тип и идентификатор. Это немного сбивает с толку, потому что мы часто случайно говорим, например, «значение 42
», хотя 42
также называется объектом, который сам имеет значение. Но неважно, давайте продолжим наш пример 42
.Введите в интерактивную оболочку следующее:
>>> спам = 42 >>> спам 42 >>> тип (спам) <класс 'int'> >>> id (спам) 1594282736
Переменная spam
относится к объекту, который имеет значение 42
, тип int
и идентификатор 1594282736
. Идентификатор — это уникальное целое число, которое создается при создании объекта и никогда не изменяется в течение всего времени существования объекта.Тип объекта также не может измениться. Может измениться только стоимость объекта.
Попробуем изменить значение объекта, введя в интерактивную оболочку следующее:
>>> спам = 42 >>> спам = 99
Вы можете подумать, что изменили значение объекта с 42
на 99
, но это не так. Все, что вы сделали, это заставили спама
ссылаться на новый объект. Вы можете подтвердить это, вызвав функцию id ()
и заметив, что спам
относится к совершенно новому объекту:
>>> спам = 42 >>> id (спам) 1594282736 >>> спам = 99 >>> id (спам) 1594284560
Целые числа (а также числа с плавающей запятой, логические значения, строки, замороженные наборы и байты) неизменяемы; их ценность не меняется.Списки (и словари, множества, массивы и байтовые массивы), с другой стороны, изменяемы. Это может привести к общей ошибке Python:
>>> spam = ['собаки', 'кошки'] >>> egg = spam # копирует ссылку, а не список >>> спам ['собаки', 'кошки'] >>> яйца ['собаки', 'кошки'] >>> spam.append ('moose') # изменяет список, на который ссылается спам >>> спам ["собаки", "кошки", "лось"] >>> яйца ["собаки", "кошки", "лось"]
Причина, по которой яиц
изменилось, несмотря на то, что мы добавили только значение к спаму
, состоит в том, что спам
и яиц
относятся к одному и тому же объекту.Строка egg = spam
делает копию ссылки, а не объекта. (Вы можете использовать функции copy ()
или deepcopy ()
модуля copy
, если вы хотите скопировать объект списка.)
Глоссарий в официальной документации Python говорит о «неизменяемом» (выделено мной):
«Объект с фиксированным значением. Неизменяемые объекты включают числа, строки и кортежей. . Такой объект нельзя изменить. Новый объект должен быть создан, если необходимо сохранить другое значение. «
В официальной документации Python (и во всех других книгах, руководствах и ответах на StackOverflow, которые я нашел) кортежи описываются как неизменяемые. И наоборот, в глоссарии говорится об «изменчивом»:
«Изменяемые объекты могут изменять свое значение, но сохраняют свой
id ()
. См. Также неизменяемые».
Давайте перейдем к обсуждению того, как значение и идентичность влияют на операторы ==
и is
.
==
против это
Оператор равенства ==
сравнивает значения, а оператор -
сравнивает идентификаторы.Вы можете рассматривать x is y
как сокращение для id (x) == id (y)
. Введите в интерактивную оболочку следующее:
>>> spam = ['собаки', 'кошки'] >>> id (спам) 41335048 >>> яйца = спам >>> id (яйца) 41335048 >>> id (спам) == id (яйца) Правда >>> спам - это яйца # спам и яйца - это один и тот же объект Правда >>> спам == яйца # спам и яйца имеют одинаковое значение, естественно Правда >>> spam == spam # Так же, как спам и спам являются одним и тем же объектом и имеют одно и то же значение, естественно Правда >>> бекон = ['собаки', 'кошки'] >>> spam == bacon # spam и bacon имеют одинаковое значение Правда >>> id (бекон) 40654152 >>> id (спам) == id (бекон) Ложь >>> спам - это бекон # спам и бекон - разные объекты Ложь
Два разных объекта могут иметь одно и то же значение, но они никогда не будут иметь одинаковый идентификатор.
Хэшируемость
Согласно глоссарию в официальной документации Python, «Объект является хешируемым, если он имеет хеш-значение, которое никогда не изменяется в течение его времени жизни» , то есть, если объект является неизменяемым. (Есть еще пара требований, касающихся специальных методов __hash __ ()
и __eq __ ()
, но это выходит за рамки данной публикации.)
Хэш — это целое число, которое зависит от значения объекта, а объекты с одинаковым значением всегда имеют одинаковый хэш.(Объекты с разными значениями иногда также будут иметь один и тот же хэш. Это называется конфликтом хэша .) Хотя id ()
вернет целое число на основе идентичности объекта, функция hash ()
вернет целое число. (хэш объекта) на основе значения хешируемого объекта:
>>> hash ('собаки') -4064183437113369969 >>> хеш (Истина) 1 >>> spam = ('привет', 'до свидания') >>> яйца = ('привет', 'до свидания') >>> спам == яйца # спам и яйца имеют одинаковое значение Правда >>> спам - это яйца # спам и яйца - это разные объекты с разными идентификаторами Ложь >>> хеш (спам) 3746884561951861327 >>> хеш (яйца) 3746884561951861327 >>> hash (spam) == hash (egg) # спам и яйца имеют одинаковый хеш Правда
Неизменяемые объекты могут быть хешируемыми, изменяемые объекты не могут быть хешированы. Это важно знать, потому что (по причинам, выходящим за рамки этого сообщения) только хешируемые объекты могут использоваться как ключи в словаре или как элементы в наборе. Поскольку хэши основаны на значениях, и только неизменяемые объекты могут быть хешируемыми, это означает, что хэши никогда не изменятся в течение времени существования объекта.
В интерактивной оболочке попробуйте создать словарь с неизменяемыми объектами для ключей, введя следующее:
>>> spam = {'dogs': 42, True: 'hello', ('a', 'b', 'c'): ['hello']} >>> спам.ключи () dict_keys (['собаки', True, ('a', 'b', 'c')])
Все ключи в спаме
являются неизменяемыми хэшируемыми объектами. Если вы попытаетесь вызвать hash ()
для изменяемого объекта (например, списка) или попытаетесь использовать изменяемый объект для ключа словаря, вы получите сообщение об ошибке:
>>> spam = {['привет', 'мир']: 42} Отслеживание (последний вызов последний): Файл "", строка 1, в TypeError: нехешируемый тип: 'список' >>> d = {'a': 1} >>> spam = {d: 42} Отслеживание (последний вызов последний): Файл " ", строка 1, в TypeError: нехэшируемый тип: 'dict'
Кортежи, являющиеся неизменяемыми объектами, могут использоваться как ключи словаря:
>>> spam = {('a', 'b', 'c'): 'hello'}
…или могут ?:
>>> spam = {('a', 'b', [1, 2, 3]): 'привет'} Отслеживание (последний вызов последний): Файл "", строка 1, в TypeError: нехешируемый тип: 'список'
Кажется, что если кортеж содержит изменяемый объект, его нельзя хешировать. (Раймонд Хеттингер объясняет, с большим количеством контекста, почему неизменяемые кортежи могут содержать изменяемые значения.) Это соответствует тому, что мы знаем: неизменяемые объекты могут быть хешируемыми , но это не обязательно означает, что они всегда могут быть хешированы .И помните, что хеш получается из значения объекта.
Это интересный угловой случай: кортеж (который должен быть неизменным), содержащий изменяемый список, не может быть хеширован. Это связано с тем, что хэш кортежа зависит от значения кортежа, но если значение этого списка может измениться, это означает, что значение кортежа может измениться и, следовательно, хэш может измениться в течение времени существования кортежа.