Я запутался в том, что такое неизменный тип. Я знаю, что float
объект считается неизменным, на примере такого типа из моей книги:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Считается ли это неизменным из-за структуры / иерархии классов? Значение float
находится на вершине класса и является его собственным вызовом метода. Похож на этот тип примера (хотя моя книга говоритdict
он изменчив):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Принимая во внимание, что что-то непостоянное имеет методы внутри класса, с примером такого типа:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Кроме того, для последнего class(SortedKeyDict_a)
, если я передам этот тип набора к нему:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
без вызова example
метода он возвращает словарь. SortedKeyDict
С __new__
флагами это ошибкой. Я попытался передать целые числа в RoundFloat
класс, __new__
и он не пометил ошибок.
python
immutability
mutable
user1027217
источник
источник
Ответы:
Какой? Поплавки неизменны? Но я не могу сделать
Разве это не "мут" х?
Ну, вы согласны, что строки неизменны, верно? Но вы можете сделать то же самое.
Значение переменной изменяется, но изменяется, изменяя то, на что ссылается переменная. Изменяемый тип может измениться таким образом, а также может измениться «на месте».
Здесь есть разница.
Конкретные примеры
источник
def f(my_list): my_list = [1, 2, 3]
. При передаче по ссылке в C значение аргумента может измениться при вызове этой функции. В Python эта функция ничего не делает.def f(my_list): my_list[:] = [1, 2, 3]
сделал бы что-нибудь.a += b
иногда, является мутацией. И тот факт, что присваивание части более крупного объекта иногда означает мутацию этого более крупного объекта, просто никогда не происходит мутацию части, например,a[0] = b
не мутируетa[0]
, но, вероятно, он видоизменяетсяa
... Вот почему может быть лучше не пытаться представить вещи в терминах C ++, а просто описать то, что Python делает в своих собственных терминах ...)Вы должны понимать, что Python представляет все свои данные как объекты. Некоторые из этих объектов, такие как списки и словари, являются изменяемыми, что означает, что вы можете изменять их содержимое без изменения их идентичности. Другие объекты, такие как целые числа, числа с плавающей запятой, строки и кортежи, являются объектами, которые нельзя изменить. Простой способ понять это, если взглянуть на идентификатор объекта.
Ниже вы видите строку, которая является неизменной. Вы не можете изменить его содержание. Это поднимет,
TypeError
если вы попытаетесь изменить это. Кроме того, если мы назначаем новое содержимое, вместо изменяемого содержимого создается новый объект.Вы можете сделать это со списком, и это не изменит идентичность объектов
Чтобы узнать больше о модели данных Python, вы можете взглянуть на справочник по языку Python:
источник
Общий неизменяемый тип:
int()
,float()
,complex()
str()
,tuple()
,frozenset()
,bytes()
Обычный изменяемый тип (почти все остальное):
list()
,bytearray()
set()
dict()
Один из способов быстро проверить, является ли тип изменчивым или нет, это использовать
id()
встроенной функции.Примеры, использующие на целое число,
используя в списке,
источник
id()
. +1.id()
здесь вводит в заблуждение. Данный объект всегда будет иметь один и тот же идентификатор в течение своего времени жизни, но разные объекты, которые существуют в разное время, могут иметь один и тот же идентификатор из-за сборки мусора.Прежде всего, имеет ли класс методы или какова его классовая структура, не имеет ничего общего с изменчивостью.
int
s иfloat
s неизменны . Если я сделаюОн указывает имя
a
на1
где - то в памяти на первой линии. Во второй строке он смотрит, что1
, добавляет5
, получает6
, затем указываетa
на это6
в памяти - это никак не изменило на1
a6
. Та же логика применима к следующим примерам, использующим другие неизменяемые типы:Для изменяемых типов я могу сделать что-то, что фактически изменит значение, где оно хранится в памяти . С участием:
Я создал список местоположений
1
,2
и3
в памяти. Если я тогда сделаюЯ просто указываю
e
на те же самыеlist
d
точки в. Тогда я могу сделать:И список, как
e
иd
точки на будут обновлены также местоположения4
и5
в памяти.Если я вернусь к неизменяемому типу и сделаю это с
tuple
:Тогда
f
все еще только указывает на оригиналtuple
- вы указалиg
на совершенно новоеtuple
.Теперь, с вашим примером
Где вы проходите
(который является
tuple
изtuples
) , какval
, вы получаете сообщение об ошибке , потому чтоtuple
ей нет.clear()
метода - вы должны пройти ,dict(d)
какval
для него , чтобы работать, в этом случае вы получите пустойSortedKeyDict
в результате.источник
Если вы переходите на Python с другого языка (кроме того, который очень похож на Python, например, Ruby), и настаиваете на том, чтобы понимать его с точки зрения этого другого языка, то здесь люди обычно путаются:
В Python присваивание не является мутацией в Python.
В C ++, если вы пишете
a = 2
, вы звонитеa.operator=(2)
, что приведет к изменению объекта, хранящегося вa
. (И если в нем не было сохранено ни одного объектаa
, это ошибка.)В Python
a = 2
ничего не делает с тем, что было сохранено вa
; это просто означает, что2
теперь хранится вa
. (А если не было ни одного объекта хранится вa
, это хорошо.)В конечном счете, это является частью еще более глубокого различия.
Переменная в языке, подобном C ++, является типизированным местом в памяти. Если
a
isint
, это означает, что это где-то 4 байта, которые, как знает компилятор, должны быть интерпретированы какint
. Поэтому, когда вы это делаетеa = 2
, он меняет то, что хранится в этих 4 байтах памяти,0, 0, 0, 1
на0, 0, 0, 2
. Если где-то есть другая переменная типа int, она имеет свои 4 байта.Переменная в языке, подобном Python, - это имя объекта, у которого есть собственная жизнь. Есть объект для числа
1
, и другой объект для числа2
. Иa
не 4 байта памяти, которые представлены какint
, это просто имя, которое указывает на1
объект. Не имеет смыслаa = 2
превращать число 1 в число 2 (что дало бы любому программисту на Python слишком много возможностей для изменения фундаментальной работы вселенной); вместо этого он просто заставляетa
забыть1
объект и указывает на2
него.Итак, если назначение не является мутацией, что такое мутация?
a.append(b)
. (Обратите внимание, что эти методы почти всегда возвращаютсяNone
). Неизменяемые типы не имеют таких методов, как обычно, изменяемые типы.a.spam = b
илиa[0] = b
. Неизменяемые типы не позволяют присваивать атрибуты или элементы, изменяемые типы обычно разрешают один или другой.a += b
, иногда нет. Изменчивые типы обычно изменяют значение; неизменяемые типы никогда не делают, и вместо этого дают вам копию (они вычисляютa + b
, а затем присваивают результатa
).Но если присваивание не является мутацией, как присваивается часть мутации объекта? Вот где это становится сложно.
a[0] = b
делает не мутируютa[0]
(опять - таки, в отличие от C ++), но он делает мутироватьa
( в отличие от C ++, за исключением косвенно).Все это - то, почему, вероятно, лучше не пытаться представить семантику Python в терминах языка, к которому вы привыкли, а вместо этого изучать семантику Python на их собственных терминах.
источник
Является ли объект изменчивым или нет, зависит от его типа. Это не зависит от того, есть ли у него определенные методы или от структуры иерархии классов.
Пользовательские типы (то есть классы) обычно являются изменяемыми. Есть некоторые исключения, такие как простые подклассы неизменяемого типа. Другие неизменные типы включают в себя некоторые встроенные типы , такие как
int
,float
,tuple
иstr
, а также некоторые классы Python реализованы в C.Общее объяснение из главы «Модель данных» в Справочнике по языку Python » :
источник
Разница между изменяемыми и неизменяемыми объектами
Определения
Изменяемый объект : объект, который можно изменить после его создания.
Неизменяемый объект : объект, который нельзя изменить после его создания.
В python, если вы измените значение неизменяемого объекта, он создаст новый объект.
Изменчивые объекты
Вот объекты в Python, которые имеют изменяемый тип:
list
Dictionary
Set
bytearray
user defined classes
Неизменные объекты
Вот объекты в Python, которые имеют неизменный тип:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Некоторые неотвеченные вопросы
Вопросы : Является ли строка неизменным типом?
Ответ : да , но вы можете объяснить это: Доказательство 1 :
Вывод
В приведенном выше примере строка была создана как «Hello», а затем изменена на «Hello World». Это означает, что строка имеет изменяемый тип. Но это не так, когда мы проверяем его идентичность, чтобы увидеть, имеет ли он изменчивый тип или нет.
Вывод
Доказательство 2 :
Вывод
Вопросы : Является ли Tuple неизменным типом?
Ответ : да , это так. Доказательство 1 :
Вывод
источник
Изменяемый объект должен иметь как минимум метод, способный изменять объект. Например, у
list
объекта естьappend
метод, который фактически будет мутировать объект:но у класса
float
нет метода для изменения объекта с плавающей точкой. Ты можешь сделать:но
=
операнд это не метод. Он просто устанавливает связь между переменной и тем, что находится справа от нее, и ничего больше. Он никогда не меняет и не создает объекты. Это объявление того, на что будет указывать переменная, начиная с этого момента.Когда вы операнд связывает переменный новый поплавок, которым создаются с тэ результатом .
b = b + 0.1
=
5 + 0.1
Когда вы присваиваете переменную существующему объекту, изменяемому или нет,
=
операнд связывает переменную с этим объектом. И больше ничего не происходитВ любом случае,
=
просто сделайте привязку. Он не меняет и не создает объекты.Когда вы это делаете
a = 1.0
,=
операнд не создает поплавок, а1.0
часть строки. На самом деле, когда вы пишете,1.0
это сокращение дляfloat(1.0)
вызова конструктора, возвращающего объект с плавающей точкой. (По этой причине, если вы наберете1.0
и нажмете Enter, вы получите «echo»,1.0
напечатанное ниже; это возвращаемое значение функции конструктора, которую вы вызвали)Теперь, если
b
это float, и вы присваиваетеa = b
, обе переменные указывают на один и тот же объект, но на самом деле переменные не могут соединяться между собой, потому что объект неизменен, и если вы это сделаетеb += 1
, теперьb
укажите на новый объект, иa
это все еще указывает на старика и не может знать, на чтоb
указывает.но если
c
, скажем, alist
, и вы назначаетеa = c
, теперьa
иc
можете «общаться», потому чтоlist
оно изменчиво, и если вы это делаетеc.append('msg')
, то просто проверяетеa
, получаете ли вы сообщение.(Между прочим, у каждого объекта есть уникальный идентификационный номер, с которым вы можете связаться
id(x)
. Таким образом, вы можете проверить, является ли объект тем же или нет, проверяя, изменился ли его уникальный идентификатор.)источник
Другими словами, измените все значение этой переменной
(name)
или оставьте ее в покое.Пример:
вы ожидали, что это сработает, и выведите hello world, но это приведет к следующей ошибке:
Переводчик говорит: я не могу изменить первый символ этой строки
вам нужно будет изменить целое
string
, чтобы оно заработало:проверьте эту таблицу:
источник
источник
my_string = 'h' + my_string[1:]
. Это создаст новую строку с именем my_string, а исходная строка my_string исчезнет (напечатайте,id(my_string)
чтобы увидеть это). Конечно, это не очень гибко, для более общего случая вы можете преобразовать в список и обратно:l = list(my_string)
l[0] = 'h'
my_string = ''.join(l)
Мне кажется, что вы боретесь с вопросом, что на самом деле означает изменчивое / неизменяемое . Итак, вот простое объяснение:
Сначала нам нужен фундамент, на котором можно основывать объяснение.
Поэтому думайте обо всем, что вы программируете как виртуальный объект, что-то, что сохраняется в памяти компьютера как последовательность двоичных чисел. (Однако не пытайтесь представить это слишком сложно. ^^) Теперь на большинстве компьютерных языков вы не будете работать с этими двоичными числами напрямую, а скорее будете использовать интерпретацию двоичных чисел.
Например, вы не думаете о числах, таких как 0x110, 0xaf0278297319 или аналогичных, но вместо этого вы думаете о числах, таких как 6, или о строках, таких как «Hello, world». Тем не менее тезисные числа или строки являются интерпретацией двоичного числа в памяти компьютера. То же самое верно для любого значения переменной.
Вкратце: мы программируем не с фактическими значениями, а с интерпретациями реальных двоичных значений.
Теперь у нас есть интерпретации, которые не должны быть изменены ради логики и других «изящных вещей», в то время как есть интерпретации, которые вполне могут быть изменены. Например, подумайте о симуляции города, другими словами, о программе, в которой много виртуальных объектов, а некоторые из них - дома. Теперь можно ли изменить эти виртуальные объекты (дома) и можно ли считать их одними и теми же домами? Ну, конечно, они могут. Таким образом, они изменчивы: их можно изменить, не став «совершенно» другим объектом.
Теперь подумайте о целых числах: это также виртуальные объекты (последовательности двоичных чисел в памяти компьютера). Так что если мы изменим один из них, например, увеличив значение шесть на одно, это все равно шесть? Ну, конечно, нет. Таким образом, любое целое число является неизменным.
Итак: если какое-либо изменение в виртуальном объекте означает, что оно фактически становится другим виртуальным объектом, то оно называется неизменным.
Заключительные замечания:
(1) Никогда не путайте свой реальный опыт изменчивости и неизменности с программированием на определенном языке:
Каждый язык программирования имеет свое собственное определение того, какие объекты могут быть отключены, а какие нет.
Таким образом, хотя вы теперь можете понимать разницу в значении, вам все равно придется изучать фактическую реализацию для каждого языка программирования. ... Действительно, может быть цель языка, где 6 может быть приглушен, чтобы стать 7. С другой стороны, это будет довольно сумасшедший или интересный материал, например симуляции параллельных вселенных. ^^
(2) Это объяснение, конечно, не научное, оно призвано помочь вам понять разницу между изменчивым и неизменным.
источник
Цель этого ответа - создать единое место, где можно найти все хорошие идеи о том, как определить, имеете ли вы дело с мутирующим / не мутирующим (неизменяемым / изменяемым) и где это возможно, что с этим делать? Бывают случаи, когда мутация нежелательна, и поведение python в этом отношении может показаться нелогичным для кодеров, входящих в нее с других языков.
Согласно полезному сообщению @ mina-gabriel:
Анализируя вышеизложенное и объединяя w / a post @ arrakëën:
Что не может неожиданно измениться?
Что может?
под «неожиданно» я подразумеваю, что программисты из других языков могут не ожидать такого поведения (за исключением Ruby и, возможно, нескольких других «похожих на Python») языков.
Добавление к этому обсуждению:
Такое поведение является преимуществом, когда оно предотвращает случайное заполнение вашего кода множественными копиями больших объемов данных, потребляющих память. Но когда это нежелательно, как мы можем обойти это?
С помощью списков простое решение - создать новый, например:
list2 = список (list1)
с другими структурами ... решение может быть сложнее. Одним из способов является циклическое перемещение элементов и добавление их в новую пустую структуру данных (того же типа).
функции могут изменять оригинал, когда вы передаете изменяемые структуры. Как сказать?
Нестандартные подходы (в случае необходимости): Обнаружено это на github, опубликованном под лицензией MIT:
Для пользовательских классов @semicolon предлагает проверить, есть ли
__hash__
функция, потому что изменяемые объекты обычно не должны иметь__hash__()
функцию.Это все, что я накопил на эту тему на данный момент. Другие идеи, исправления и т. Д. Приветствуются. Спасибо.
источник
Один способ думать о разнице:
Назначения неизменяемых объектов в python можно рассматривать как глубокие копии, тогда как назначения изменяемым объектам невелики
источник
Самый простой ответ:
Изменяемая переменная - это переменная, значение которой может измениться на месте, тогда как в неизменяемой переменной изменение значения не произойдет. Изменение неизменяемой переменной перестроит ту же самую переменную.
Пример:
Создаст значение 5, на которое ссылается х
х -> 5
Это утверждение заставит вас сослаться на 5 из х
x -------------> 5 <----------- y
Поскольку x является целым числом (неизменный тип), оно было перестроено.
В этом выражении выражение RHS приведет к значению 10, а когда оно будет присвоено LHS (x), x перестроится в 10. Итак, теперь
х ---------> 10
у ---------> 5
источник
Я не прочитал все ответы, но выбранный ответ не является правильным, и я думаю, что у автора есть идея, что возможность переназначения переменной означает, что любой тип данных является изменяемым. Это не относится к делу. Изменчивость связана с передачей по ссылке, а не передачей по значению.
Допустим, вы создали список
Если бы вы сказали:
Даже если вы переназначили значение для B, оно также переназначит значение для a. Это потому, что когда вы назначаете "b = a". Вы передаете «Ссылку» объекту, а не копию значения. Это не относится к строкам, числам с плавающей точкой и т. Д. Это делает изменяемым список, словари и подобные записи, но логические, числа с плавающей точкой и т. Д. Неизменяемыми.
источник
Например, для неизменяемых объектов присваивание создает новую копию значений.
Для изменяемых объектов присваивание не создает другую копию значений. Например,
источник
x=10
это просто другое назначение , при этомx[2] = 5
вызывается метод мутатора.int
объектам просто не хватает методов-мутаторов , но семантика присваивания Python не зависит от типаВ Python есть простой способ узнать:
Неизменный:
Mutable:
И:
Поэтому я думаю, что встроенная функция также неизменна в Python.
Но я действительно не понимаю, как работает float:
Это так странно.
источник
x = (1, 2)
а затем попробуйтеx
изменить его, это невозможно. Один способ, который я нашел, чтобы проверить на изменчивостьhash
, это, по крайней мере, он работает для встроенных объектов.hash(1)
hash('a')
hash((1, 2))
hash(True)
все работают, иhash([])
hash({})
hash({1, 2})
все не работают.hash()
будет работать, если объект определяет__hash__()
метод, даже если пользовательские классы обычно изменчивы.hash
метод все еще довольно хороший, потому что изменяемые объекты, как правило, не должны иметь__hash__()
метода, поскольку делать их ключами в словаре просто опасно.