Разве строки Python не являются неизменяемыми? Тогда почему + " " + b работает?

Насколько я понимаю, строки Python неизменны.

Я попробовал следующий код:

a = "Dog"
b = "eats"
c = "treats"

print a, b, c
# Dog eats treats

print a + " " + b + " " + c
# Dog eats treats

print a
# Dog

a = a + " " + b + " " + c
print a
# Dog eats treats
# !!!

Разве Python не должен был помешать назначению? Я, наверное, что-то упустил.

Любая идея?

18 ответов

Решение

Первый a указал на строку "Собака". Затем вы изменили переменную a указать на новую строку "Собака ест угощение". Вы на самом деле не мутировали строку "Собака". Строки являются неизменяемыми, переменные могут указывать на то, что они хотят.

Сами строковые объекты неизменны.

Переменная, a, который указывает на строку, является изменчивым.

Рассматривать:

a = "Foo"
# a now points to "Foo"
b = a
# b points to the same "Foo" that a points to
a = a + a
# a points to the new string "FooFoo", but b still points to the old "Foo"

print a
print b
# Outputs:

# FooFoo
# Foo

# Observe that b hasn't changed, even though a has.

Переменная a указывает на объект "Собака". Лучше думать о переменной в Python как о теге. Вы можете переместить тег на разные объекты, что вы и сделали, когда изменили a = "dog" в a = "dog eats treats",

Однако неизменность относится к объекту, а не к тегу.


Если вы пытались a[1] = 'z' делать "dog" в "dzg", вы получите ошибку:

TypeError: 'str' object does not support item assignment" 

потому что строки не поддерживают назначение элементов, поэтому они неизменны.

Что-то изменчиво только тогда, когда мы можем изменить значения, хранящиеся в ячейке памяти, без изменения самой ячейки памяти.

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

Например, список изменчив. Как?

>> a = ['hello']
>> id(a)
139767295067632

# Now let's modify
#1
>> a[0] = "hello new"
>> a
['hello new']
Now that we have changed "a", let's see the location of a
>> id(a)
139767295067632
so it is the same as before. So we mutated a. So list is mutable.

Строка неизменна. Как мы это докажем?

> a = "hello"
> a[0]
'h'
# Now let's modify it
> a[0] = 'n'
----------------------------------------------------------------------

мы получаем

TypeError: объект 'str' не поддерживает назначение элемента

Таким образом, мы не смогли изменить строку. Это означает, что строка неизменна.

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

>> a = "hello"
>> id(a)
139767308749440
>> a ="world"
>> id(a)
139767293625808

id до и после переназначения отличается, так что это доказывает, что вы на самом деле не мутируете, а указываете переменную на новое место. Который не мутирует эту строку, а мутирует эту переменную.

Рассматривать:

>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='asdf'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x1091aab90>
>>> a='qwer'
>>> a.__repr__
<method-wrapper '__repr__' of str object at 0x109198490>

Обратите внимание, что шестнадцатеричное расположение в памяти не изменилось, когда я дважды сохранял одно и то же значение в переменной. Это изменилось, когда я сохранил другое значение. Строка неизменна. Не из-за фанатизма, а потому, что вы платите за производительность создания нового объекта в памяти. Переменная a это просто метка, указывающая на этот адрес памяти. Это может быть изменено, чтобы указать на что-либо.

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

Заявление a = a + " " + b + " " + c может быть разбит на основе указателей.

a + " " говорит, дай мне что a указывает на, который нельзя изменить, и добавить " " на мой текущий рабочий набор.

объем памяти:

working_set = "Dog "
a = "Dog" 
b = "eats"
c = "treats"

+ b говорит, дай мне что b указывает на, который нельзя изменить, и добавьте его в текущий рабочий набор.

объем памяти:

working_set = "Dog eats"
a = "Dog" 
b = "eats"
c = "treats"

+ " " + c говорит добавить " " к текущему набору. Тогда дай мне что c указывает на, который нельзя изменить, и добавьте его в текущий рабочий набор. объем памяти:

working_set = "Dog eats treats"
a = "Dog" 
b = "eats"
c = "treats"

В заключение, a = говорит установить мой указатель, чтобы указать на результирующий набор.

объем памяти:

a = "Dog eats treats"
b = "eats"
c = "treats"

"Dog" исправлено, потому что больше не указатели подключаются к его части памяти. Мы никогда не изменяли раздел памяти "Dog" проживал в том, что подразумевается под неизменным. Тем не менее, мы можем изменить, какие метки, если таковые имеются, указывают на этот раздел памяти.

Существует разница между данными и меткой, с которой они связаны. Например, когда вы делаете

a = "dog"

данные "dog" создан и помещен под этикеткой a, Метка может измениться, но то, что находится в памяти, не изменится. Данные "dog" будет оставаться в памяти (пока сборщик мусора не удалит его) после того, как вы

a = "cat"

В вашей программе a теперь ^ указывает на ^ "cat" но строка "dog" не изменился

l = [1,2,3]
print id(l)
l.append(4)
print id(l) #object l is the same

a = "dog"
print id(a)
a = "cat"
print id(a) #object a is a new object, previous one is deleted

Строковые объекты Python являются неизменяемыми. Пример:

>>> a = 'tanim'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281536'
>>> a = 'ahmed'
>>> 'Address of a is:{}'.format(id(a))
'Address of a is:64281600'

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

  >>> a[0] = 'c'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    **TypeError**: 'str' object does not support item assignment

Произошла ошибка.

Строки Python являются неизменяемыми. Тем не мение, a это не строка: это переменная со строковым значением. Вы не можете изменить строку, но можете изменить значение переменной на новую строку.

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

нажмите для фото доказательства

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

a = "dog"
print a                   #dog
a[1] = "g"                #ERROR!!!!!! STRINGS ARE IMMUTABLE
a = 'dog'
address = id(a)
print(id(a))

a = a + 'cat'
print(id(a))      #Address changes

import ctypes
ctypes.cast(address, ctypes.py_object).value    #value at old address is intact

Встроенная функция id()возвращает идентификатор объекта как целое число. Это целое число обычно соответствует расположению объекта в памяти.

\>>a='dog'
\>>print(id(a))

139831803293008

\>>a=a+'cat'
\>>print(id(a))

139831803293120

Первоначально 'a' хранится в ячейке памяти 139831803293008, поскольку строковый объект является неизменным в python, если вы попытаетесь изменить и переназначить ссылку, будет удалена и будет указателем на новую ячейку памяти (139831803293120).

>>> a = 'dogs'

>>> a.replace('dogs', 'dogs eat treats')

'dogs eat treats'

>>> print a

'dogs'

Неизменный, не так ли?

Часть изменения переменной уже обсуждалась.

Рассмотрим это дополнение к вашему примеру

 a = "Dog"
 b = "eats"
 c = "treats"
 print (a,b,c)
 #Dog eats treats
 d = a + " " + b + " " + c
 print (a)
 #Dog
 print (d)
 #Dog eats treats

Одно из более точных объяснений, которое я нашел в блоге:

В Python (почти) все является объектом. То, что мы обычно называем "переменными" в Python, более правильно называется именами. Аналогично, "назначение" - это действительно привязка имени к объекту. У каждой привязки есть область, которая определяет ее видимость, обычно блок, в котором происходит имя.

Например:

some_guy = 'Fred'
# ...
some_guy = 'George'

Когда мы позже скажем some_guy = 'George', строковый объект, содержащий 'Fred', не затронут. Мы только что изменили привязку имени some_guy. Однако мы не изменили ни строковые объекты 'Fred', ни 'George'. Насколько нам известно, они могут жить бесконечно долго.

Ссылка на блог: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/

Добавив немного больше к вышеупомянутым ответам.

id переменной изменяется при переназначении.

>>> a = 'initial_string'
>>> id(a)
139982120425648
>>> a = 'new_string'
>>> id(a)
139982120425776

Это означает, что мы мутировали переменную a указать на новую строку. Сейчас существует два string(str) объекты:

'initial_string' с id = 139982120425648

а также

'new_string' с id = 139982120425776

Рассмотрим следующий код:

>>> b = 'intitial_string'
>>> id(b)
139982120425648

Сейчас, b указывает на 'initial_string' и имеет то же самое id как a имел до переназначения.

Таким образом 'intial_string' не был мутирован.

Подводя итог:

a = 3
b = a
a = 3+2
print b
# 5

Не неизменный:

a = 'OOP'
b = a
a = 'p'+a
print b
# OOP

Неизменный:

a = [1,2,3]
b = range(len(a))
for i in range(len(a)):
    b[i] = a[i]+1

Это ошибка в Python 3, потому что она неизменна. И не ошибка в Python 2, потому что ясно, что он не является неизменным.

Мы просто объединяем два строковых значения. Мы никогда не меняем значение (а). Только что (а) представляют другой блок памяти, который имеет значение "dogdog". Потому что в бэкэнде одна переменная никогда не представляет два блока памяти одновременно. Значение (а) перед конкатенацией было "собака". Но после этого (а) представляют "собаку", потому что теперь (а) в backend rep. блок со значением "dogdog". А "собака" - это респ. by (b) и "собака" не считается значением мусора, пока (b) не представляет "собаку".

Путаница в том, что мы представляем блоки памяти (содержащие данные или информацию) в бэкэнде с тем же именем переменной.

Это изображение дает ответ. Пожалуйста, прочитайте это.

https://stackru.com/images/22fe a0c9e35bd88d0de00b15e8662d9fe3793dad.png

Вы можете сделать неизменным массив numpy и использовать первый элемент:

numpyarrayname[0] = "write once"

затем:

numpyarrayname.setflags(write=False)

или же

numpyarrayname.flags.writeable = False
Другие вопросы по тегам