Неизменяемые и изменчивые типы

186

Я запутался в том, что такое неизменный тип. Я знаю, что 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__и он не пометил ошибок.

user1027217
источник
Вы также можете проверить назначение List с помощью [:] и python, когда использовать copy.copy, на который я также ответил для получения дополнительной информации об изменчивости.
AGF

Ответы:

232

Какой? Поплавки неизменны? Но я не могу сделать

x = 5.0
x += 7.0
print x # 12.0

Разве это не "мут" х?

Ну, вы согласны, что строки неизменны, верно? Но вы можете сделать то же самое.

s = 'foo'
s += 'bar'
print s # foobar

Значение переменной изменяется, но изменяется, изменяя то, на что ссылается переменная. Изменяемый тип может измениться таким образом, а также может измениться «на месте».

Здесь есть разница.

x = something # immutable type
print x
func(x)
print x # prints the same thing

x = something # mutable type
print x
func(x)
print x # might print something different

x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing

x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different

Конкретные примеры

x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo

x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]

def func(val):
    val += 'bar'

x = 'foo'
print x # foo
func(x)
print x # foo

def func(val):
    val += [3, 2, 1]

x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]
Утренняя звезда
источник
5
То, что вы объясняете, означает для меня: изменяемые переменные передаются по ссылке, неизменные переменные передаются по значению. Это верно ?
Лоренц Мейер
17
Почти, но не совсем. Технически, все переменные передаются по ссылке в Python, но имеют семантику, более похожую на передачу по значению в C. Контрпример к вашей аналогии - если вы это сделаете def f(my_list): my_list = [1, 2, 3]. При передаче по ссылке в C значение аргумента может измениться при вызове этой функции. В Python эта функция ничего не делает. def f(my_list): my_list[:] = [1, 2, 3]сделал бы что-нибудь.
morningstar
6
Изменяемые типы могут быть изменены на месте. Неизменяемые типы не могут меняться на месте. Вот так питон видит мир. Это независимо от того, как переменные передаются в функции.
ychaouche
13
Основное различие между семантикой Python и семантикой передачи по ссылке в C ++ состоит в том, что присваивание не является мутацией в Python, а в C ++. (Но, конечно, это осложняется тем фактом, что расширенное присваивание, как a += bиногда, является мутацией. И тот факт, что присваивание части более крупного объекта иногда означает мутацию этого более крупного объекта, просто никогда не происходит мутацию части, например, a[0] = bне мутирует a[0], но, вероятно, он видоизменяется a... Вот почему может быть лучше не пытаться представить вещи в терминах C ++, а просто описать то, что Python делает в своих собственных терминах ...)
abarnert
2
Я нашел этот ответ вводящим в заблуждение, потому что он не использует id (), который необходим для понимания того, что означает неизменяемый.
pawel_winzig
185

Вы должны понимать, что Python представляет все свои данные как объекты. Некоторые из этих объектов, такие как списки и словари, являются изменяемыми, что означает, что вы можете изменять их содержимое без изменения их идентичности. Другие объекты, такие как целые числа, числа с плавающей запятой, строки и кортежи, являются объектами, которые нельзя изменить. Простой способ понять это, если взглянуть на идентификатор объекта.

Ниже вы видите строку, которая является неизменной. Вы не можете изменить его содержание. Это поднимет, TypeErrorесли вы попытаетесь изменить это. Кроме того, если мы назначаем новое содержимое, вместо изменяемого содержимого создается новый объект.

>>> s = "abc"
>>>id(s)
4702124
>>> s[0] 
'a'
>>> s[0] = "o"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>>id(s)
4800100
>>> s += "uvw"
>>>id(s)
4800500

Вы можете сделать это со списком, и это не изменит идентичность объектов

>>> i = [1,2,3]
>>>id(i)
2146718700
>>> i[0] 
1
>>> i[0] = 7
>>> id(i)
2146718700

Чтобы узнать больше о модели данных Python, вы можете взглянуть на справочник по языку Python:

SEBS
источник
4
+1 За ссылку на документы по Python. Однако мне потребовалось некоторое время, пока я не понял, что сегодня вам нужно разграничить Python 2 и 3 - я обновил ответ, чтобы подчеркнуть это.
Бенджамин
107

Общий неизменяемый тип:

  1. номера: int(), float(),complex()
  2. неизменные последовательности: str(), tuple(), frozenset(),bytes()

Обычный изменяемый тип (почти все остальное):

  1. изменяемые последовательности: list(),bytearray()
  2. установить тип: set()
  3. тип отображения: dict()
  4. классы, экземпляры классов
  5. и т.п.

Один из способов быстро проверить, является ли тип изменчивым или нет, это использовать id() встроенной функции.

Примеры, использующие на целое число,

>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)

используя в списке,

>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
спектральный
источник
11
Хорошо объяснил. Понравилась концепция проверки id(). +1.
Параг Тяги
4
На самом деле использование id()здесь вводит в заблуждение. Данный объект всегда будет иметь один и тот же идентификатор в течение своего времени жизни, но разные объекты, которые существуют в разное время, могут иметь один и тот же идентификатор из-за сборки мусора.
Авгурар
37

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

ints и floats неизменны . Если я сделаю

a = 1
a += 5

Он указывает имя aна 1где - то в памяти на первой линии. Во второй строке он смотрит, что 1, добавляет 5, получает 6, затем указывает aна это 6в памяти - это никак не изменило на 1a 6. Та же логика применима к следующим примерам, использующим другие неизменяемые типы:

b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')

Для изменяемых типов я могу сделать что-то, что фактически изменит значение, где оно хранится в памяти . С участием:

d = [1, 2, 3]

Я создал список местоположений 1, 2и 3в памяти. Если я тогда сделаю

e = d

Я просто указываю eна те же самыеlist d точки в. Тогда я могу сделать:

e += [4, 5]

И список, как eи dточки на будут обновлены также местоположения 4и 5в памяти.

Если я вернусь к неизменяемому типу и сделаю это с tuple:

f = (1, 2, 3)
g = f
g += (4, 5)

Тогда fвсе еще только указывает на оригиналtuple - вы указали gна совершенно новоеtuple .

Теперь, с вашим примером

class SortedKeyDict(dict):
    def __new__(cls, val):
        return dict.__new__(cls, val.clear())

Где вы проходите

d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))

(который является tupleиз tuples) , как val, вы получаете сообщение об ошибке , потому что tupleей нет .clear()метода - вы должны пройти , dict(d)как valдля него , чтобы работать, в этом случае вы получите пустой SortedKeyDictв результате.

AGF
источник
2
Это очень хорошее объяснение. Очень понравился этот вопрос и много интересных (новых) перспектив, чтобы объяснить это.
Неудачный ученый
25

Если вы переходите на Python с другого языка (кроме того, который очень похож на Python, например, Ruby), и настаиваете на том, чтобы понимать его с точки зрения этого другого языка, то здесь люди обычно путаются:

>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!

В Python присваивание не является мутацией в Python.

В C ++, если вы пишете a = 2, вы звоните a.operator=(2), что приведет к изменению объекта, хранящегося в a. (И если в нем не было сохранено ни одного объекта a, это ошибка.)

В Python a = 2ничего не делает с тем, что было сохранено в a; это просто означает, что 2теперь хранится в a. (А если не было ни одного объекта хранится в a, это хорошо.)


В конечном счете, это является частью еще более глубокого различия.

Переменная в языке, подобном C ++, является типизированным местом в памяти. Если ais int, это означает, что это где-то 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 на их собственных терминах.

abarnert
источник
2
Скажи = привет. a [0] = 'f' будет 'print' 'распечатывать' fi '(я прав до сих пор?), поэтому, когда вы говорите, что он не мутирует [0], а a, что это значит? ? Есть ли у [n] также свое собственное место, и изменение его значения указывает на другое значение?
Дэниел Спрингер,
19

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

Пользовательские типы (то есть классы) обычно являются изменяемыми. Есть некоторые исключения, такие как простые подклассы неизменяемого типа. Другие неизменные типы включают в себя некоторые встроенные типы , такие как int, float, tupleиstr , а также некоторые классы Python реализованы в C.

Общее объяснение из главы «Модель данных» в Справочнике по языку Python » :

Стоимость некоторых объектов может измениться. Объекты, чье значение может измениться, называются непостоянными; объекты, чье значение не изменяется после создания, называются неизменяемыми.

(Значение неизменяемого объекта-контейнера, содержащего ссылку на изменяемый объект, может измениться при изменении значения последнего; однако контейнер по-прежнему считается неизменным, поскольку коллекция объектов, которую он содержит, не может быть изменена. Таким образом, неизменность не является строго то же самое, что иметь неизменяемое значение, оно более тонкое.)

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

taleinat
источник
+1 Обратите внимание, что только некоторые типы расширений (вы можете пересмотреть свое определение этого, все встроенные типы Python реализованы в C) являются неизменяемыми. Другие (большинство, я бы даже сказал) совершенно изменчивы.
@delnan Что вы называете "типами расширений" ?
eyquem
@eyquem: я неправильно использовал термин «типы расширений» в своем ответе, и Делнан имел в виду это. После его комментария я пересмотрел свой ответ и избегал использования этого термина.
taleinat
19

Разница между изменяемыми и неизменяемыми объектами

Определения

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

В python, если вы измените значение неизменяемого объекта, он создаст новый объект.

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

Вот объекты в Python, которые имеют изменяемый тип:

  1. list
  2. Dictionary
  3. Set
  4. bytearray
  5. user defined classes

Неизменные объекты

Вот объекты в Python, которые имеют неизменный тип:

  1. int
  2. float
  3. decimal
  4. complex
  5. bool
  6. string
  7. tuple
  8. range
  9. frozenset
  10. bytes

Некоторые неотвеченные вопросы

Вопросы : Является ли строка неизменным типом?
Ответ : да , но вы можете объяснить это: Доказательство 1 :

a = "Hello"
a +=" World"
print a

Вывод

"Hello World"

В приведенном выше примере строка была создана как «Hello», а затем изменена на «Hello World». Это означает, что строка имеет изменяемый тип. Но это не так, когда мы проверяем его идентичность, чтобы увидеть, имеет ли он изменчивый тип или нет.

a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
    print "String is Immutable"

Вывод

String is Immutable

Доказательство 2 :

a = "Hello World"
a[0] = "M"

Вывод

TypeError 'str' object does not support item assignment

Вопросы : Является ли Tuple неизменным типом?
Ответ : да , это так. Доказательство 1 :

tuple_a = (1,)
tuple_a[0] = (2,)
print a

Вывод

'tuple' object does not support item assignment
ананд трипати
источник
В [46]: a = "Hello" В [47]: id (a) Out [47]: 140071263880128 В [48]: a = a.replace ("H", "g") В [49]: a Out [49]: «gello» In [50]: id (a) Out [50]: 140071263881040
Аргус
не могли бы вы доказать проблему с назначением предмета в моем приведенном выше примере
Argus Malware
назначение предметов не является проблемой в неизменяемых типах. В вашем случае вы меняете строку a, но в памяти ее присваиваете новую переменную. Назначение элемента в моем случае не изменит память переменной, как в случае списка или словаря. если вы делаете замену, вы создаете новую переменную, не изменяя существующую переменную
anand tripathi
@ArgusMalware в вашем случае, два идентификатора равны из-за первого, переработанного GC, так что второй повторно использует память.
Cologler
11

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

>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']

но у класса floatнет метода для изменения объекта с плавающей точкой. Ты можешь сделать:

>>> b = 5.0 
>>> b = b + 0.1
>>> b
5.1

но =операнд это не метод. Он просто устанавливает связь между переменной и тем, что находится справа от нее, и ничего больше. Он никогда не меняет и не создает объекты. Это объявление того, на что будет указывать переменная, начиная с этого момента.

Когда вы операнд связывает переменный новый поплавок, которым создаются с тэ результатом .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, скажем, a list, и вы назначаете a = c, теперь aи cможете «общаться», потому что listоно изменчиво, и если вы это делаете c.append('msg'), то просто проверяете a, получаете ли вы сообщение.

(Между прочим, у каждого объекта есть уникальный идентификационный номер, с которым вы можете связаться id(x). Таким образом, вы можете проверить, является ли объект тем же или нет, проверяя, изменился ли его уникальный идентификатор.)

nadapez
источник
6

Класс является неизменным, если каждый объект этого класса имеет фиксированное значение при создании экземпляра, которое не может быть ПОСЛЕДОВАТЕЛЬНО изменено

Другими словами, измените все значение этой переменной (name)или оставьте ее в покое.

Пример:

my_string = "Hello world" 
my_string[0] = "h"
print my_string 

вы ожидали, что это сработает, и выведите hello world, но это приведет к следующей ошибке:

Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment

Переводчик говорит: я не могу изменить первый символ этой строки

вам нужно будет изменить целое string, чтобы оно заработало:

my_string = "Hello World" 
my_string = "hello world"
print my_string #hello world

проверьте эту таблицу:

введите описание изображения здесь

источник

Мина Габриэль
источник
Как можно изменить компоненты строки Python более кратким способом, чем показано выше?
Люк Дэвис
@ LukeDavis Вы могли бы сделать my_string = 'h' + my_string[1:]. Это создаст новую строку с именем my_string, а исходная строка my_string исчезнет (напечатайте, id(my_string)чтобы увидеть это). Конечно, это не очень гибко, для более общего случая вы можете преобразовать в список и обратно:l = list(my_string) l[0] = 'h' my_string = ''.join(l)
Данио
5

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

Сначала нам нужен фундамент, на котором можно основывать объяснение.

Поэтому думайте обо всем, что вы программируете как виртуальный объект, что-то, что сохраняется в памяти компьютера как последовательность двоичных чисел. (Однако не пытайтесь представить это слишком сложно. ^^) Теперь на большинстве компьютерных языков вы не будете работать с этими двоичными числами напрямую, а скорее будете использовать интерпретацию двоичных чисел.

Например, вы не думаете о числах, таких как 0x110, 0xaf0278297319 или аналогичных, но вместо этого вы думаете о числах, таких как 6, или о строках, таких как «Hello, world». Тем не менее тезисные числа или строки являются интерпретацией двоичного числа в памяти компьютера. То же самое верно для любого значения переменной.

Вкратце: мы программируем не с фактическими значениями, а с интерпретациями реальных двоичных значений.

Теперь у нас есть интерпретации, которые не должны быть изменены ради логики и других «изящных вещей», в то время как есть интерпретации, которые вполне могут быть изменены. Например, подумайте о симуляции города, другими словами, о программе, в которой много виртуальных объектов, а некоторые из них - дома. Теперь можно ли изменить эти виртуальные объекты (дома) и можно ли считать их одними и теми же домами? Ну, конечно, они могут. Таким образом, они изменчивы: их можно изменить, не став «совершенно» другим объектом.

Теперь подумайте о целых числах: это также виртуальные объекты (последовательности двоичных чисел в памяти компьютера). Так что если мы изменим один из них, например, увеличив значение шесть на одно, это все равно шесть? Ну, конечно, нет. Таким образом, любое целое число является неизменным.

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

Заключительные замечания:

(1) Никогда не путайте свой реальный опыт изменчивости и неизменности с программированием на определенном языке:

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

Таким образом, хотя вы теперь можете понимать разницу в значении, вам все равно придется изучать фактическую реализацию для каждого языка программирования. ... Действительно, может быть цель языка, где 6 может быть приглушен, чтобы стать 7. С другой стороны, это будет довольно сумасшедший или интересный материал, например симуляции параллельных вселенных. ^^

(2) Это объяснение, конечно, не научное, оно призвано помочь вам понять разницу между изменчивым и неизменным.

Маркус Альперс
источник
5

Цель этого ответа - создать единое место, где можно найти все хорошие идеи о том, как определить, имеете ли вы дело с мутирующим / не мутирующим (неизменяемым / изменяемым) и где это возможно, что с этим делать? Бывают случаи, когда мутация нежелательна, и поведение python в этом отношении может показаться нелогичным для кодеров, входящих в нее с других языков.

Согласно полезному сообщению @ mina-gabriel:

Анализируя вышеизложенное и объединяя w / a post @ arrakëën:

Что не может неожиданно измениться?

  • скаляры (типы переменных, хранящие одно значение) не изменяются неожиданно
    • числовые примеры: int (), float (), complex ()
  • Есть несколько «изменяемых последовательностей»:
    • str (), tuple (), frozenset (), bytes ()

Что может?

  • список как объекты (списки, словари, наборы, bytearray ())
  • пост здесь также говорит о классах и экземплярах классов, но это может зависеть от того, от чего наследуется класс и / или как он построен.

под «неожиданно» я подразумеваю, что программисты из других языков могут не ожидать такого поведения (за исключением Ruby и, возможно, нескольких других «похожих на Python») языков.

Добавление к этому обсуждению:

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

С помощью списков простое решение - создать новый, например:

list2 = список (list1)

с другими структурами ... решение может быть сложнее. Одним из способов является циклическое перемещение элементов и добавление их в новую пустую структуру данных (того же типа).

функции могут изменять оригинал, когда вы передаете изменяемые структуры. Как сказать?

  • Есть несколько тестов для других комментариев в этой теме, но есть комментарии, указывающие, что эти тесты не являются полным доказательством
  • object.function () - это метод исходного объекта, но только некоторые из них видоизменяются. Если они ничего не возвращают, они, вероятно, делают. Можно было бы ожидать, что .append () будет видоизменяться без проверки его имени. .union () возвращает объединение set1.union (set2) и не мутирует. В случае сомнений функцию можно проверить на возвращаемое значение. Если return = None, он не видоизменяется.
  • sorted () может быть обходным решением в некоторых случаях. Поскольку он возвращает отсортированную версию оригинала, он может позволить вам сохранить немутатную копию, прежде чем вы начнете работать с оригиналом другими способами. Тем не менее, эта опция предполагает, что вы не заботитесь о порядке исходных элементов (если вы это делаете, вам нужно найти другой путь). В отличие от .sort () мутирует оригинал (как и следовало ожидать).

Нестандартные подходы (в случае необходимости): Обнаружено это на github, опубликованном под лицензией MIT:

  • хранилище github под: tobgu с именем: pyrsistent
  • Что это такое: код постоянной структуры данных Python, написанный для использования вместо основных структур данных, когда мутация нежелательна

Для пользовательских классов @semicolon предлагает проверить, есть ли __hash__функция, потому что изменяемые объекты обычно не должны иметь __hash__()функцию.

Это все, что я накопил на эту тему на данный момент. Другие идеи, исправления и т. Д. Приветствуются. Спасибо.

TMWP
источник
3

Один способ думать о разнице:

Назначения неизменяемых объектов в python можно рассматривать как глубокие копии, тогда как назначения изменяемым объектам невелики

Адитья Сихаг
источник
1
Это неверно Все назначения в Python приведены по ссылке. Там нет копирования, участвующих.
Авгурар
3

Самый простой ответ:

Изменяемая переменная - это переменная, значение которой может измениться на месте, тогда как в неизменяемой переменной изменение значения не произойдет. Изменение неизменяемой переменной перестроит ту же самую переменную.

Пример:

>>>x = 5

Создаст значение 5, на которое ссылается х

х -> 5

>>>y = x

Это утверждение заставит вас сослаться на 5 из х

x -------------> 5 <----------- y

>>>x = x + y

Поскольку x является целым числом (неизменный тип), оно было перестроено.

В этом выражении выражение RHS приведет к значению 10, а когда оно будет присвоено LHS (x), x перестроится в 10. Итак, теперь

х ---------> 10

у ---------> 5

Амит Упадхяй
источник
-1

Я не прочитал все ответы, но выбранный ответ не является правильным, и я думаю, что у автора есть идея, что возможность переназначения переменной означает, что любой тип данных является изменяемым. Это не относится к делу. Изменчивость связана с передачей по ссылке, а не передачей по значению.

Допустим, вы создали список

a = [1,2]

Если бы вы сказали:

b = a
b[1] = 3

Даже если вы переназначили значение для B, оно также переназначит значение для a. Это потому, что когда вы назначаете "b = a". Вы передаете «Ссылку» объекту, а не копию значения. Это не относится к строкам, числам с плавающей точкой и т. Д. Это делает изменяемым список, словари и подобные записи, но логические, числа с плавающей точкой и т. Д. Неизменяемыми.

Скотт
источник
-1

Например, для неизменяемых объектов присваивание создает новую копию значений.

x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot 
#effect the value of y
print(x,y)

Для изменяемых объектов присваивание не создает другую копию значений. Например,

x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy 
x[2]=5
print(x,y) # both x&y holds the same list
Рави Гурнатхам
источник
1
Абсолютно неверно. Назначение никогда не создает копию . Пожалуйста, прочтите nedbatchelder.com/text/names.html В первом случае x=10это просто другое назначение , при этом x[2] = 5вызывается метод мутатора. intобъектам просто не хватает методов-мутаторов , но семантика присваивания Python не зависит от типа
juanpa.arrivillaga
-2

В Python есть простой способ узнать:

Неизменный:

    >>> s='asd'
    >>> s is 'asd'
    True
    >>> s=None
    >>> s is None
    True
    >>> s=123
    >>> s is 123
    True

Mutable:

>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False

И:

>>> s=abs
>>> s is abs
True

Поэтому я думаю, что встроенная функция также неизменна в Python.

Но я действительно не понимаю, как работает float:

>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256

Это так странно.

Джейсон Ян
источник
Но это явно не верно. Потому что кортежи неизменны. Введите, x = (1, 2)а затем попробуйте xизменить его, это невозможно. Один способ, который я нашел, чтобы проверить на изменчивость hash, это, по крайней мере, он работает для встроенных объектов. hash(1) hash('a') hash((1, 2)) hash(True)все работают, и hash([]) hash({}) hash({1, 2})все не работают.
точка с запятой
@semicolon Для пользовательских классов hash()будет работать, если объект определяет __hash__()метод, даже если пользовательские классы обычно изменчивы.
Авгурар
1
@augurar Я имею в виду да, но ничто в Python ничего не гарантирует, потому что у Python нет реальной статической типизации или формальных гарантий. Но hashметод все еще довольно хороший, потому что изменяемые объекты, как правило, не должны иметь __hash__()метода, поскольку делать их ключами в словаре просто опасно.
точка с запятой
1
@augurar и точка с запятой (или другие, если они знают это): __hash __ () решение ... должен ли создатель пользовательского класса добавить его, чтобы он был там? Если так, то правило, если существует, объект должен быть неизменным; если он не существует, мы не можем сказать, так как создатель, возможно, просто ушел, если выключен.
TMWP