Хіба струни Python не змінюються? Тоді чому функція + "" + b працює?


109

Я розумів, що струни 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 перешкодити цьому призначенню? Мені, певно, щось не вистачає.

Будь-яка ідея?


55
Сама рядок є незмінною, але мітка може змінюватися.
міт

6
Призначення нового значення існуючій змінній цілком справедливо. У Python немає констант. Це не залежить від зміни даних.
Фелікс Клінг

14
Ви можете поглянути на id()функцію. aматиме інший ідентифікатор до та після призначення, що вказує на те, що він вказує на різні об'єкти. Так само і з кодом, як b = aви знайдете, aі він bбуде мати той самий ідентифікатор, що вказує на те, що вони посилаються на той самий об'єкт
DRH


Посилання від delnan - саме те, про що я задумався.
міт

Відповіді:


180

Першим aвказав на рядок "Собака". Потім ви змінили змінну, aщоб вказати на новий рядок "Собака їсть частування". Ви насправді не мутували рядок "Собака". Рядки незмінні, змінні можуть вказувати на все, що вони хочуть.


34
Ще переконливіше спробувати щось на кшталт x = 'abc'; x [1] = 'x' у відповіді Python
xpmatteo

1
Якщо ви хочете трохи більше розібратися в роботі, дивіться мою відповідь. stackoverflow.com/a/40702094/117471
Бруно Bronosky

53

Самі струнні об'єкти незмінні.

Змінна, 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.

@jason спробуйте такі ж операції зі списками (які можна змінити), щоб побачити різницю a.append (3) відповідає a = a + "Foo"
jimifiki

1
@jimifiki a.append(3) - не те саме, що a = a + 3. Це навіть не a += 3(додаток на місці еквівалентний .extend, не .append).

@delnan і так, що? Для того, щоб показати, що рядки та списки ведуть себе по-різному, ви можете припустити, що a = a + "Foo" - це те саме, що a.append (щось). У будь-якому випадку це не те саме. Очевидно. Чи були ви щасливішими, читаючи a.extend ([щось]) замість a.append (щось)? Я не бачу такої великої різниці в цьому контексті. Але, напевно, мені чогось не вистачає. Істина залежить від контексту
jimifiki

@jimifiki: Про що ти говориш? +поводиться так само для списків і рядків - він об'єднує, створюючи нову копію, не мутуючи жоден операнд.

6
По-справжньому важливим моментом, що потрібно позбавити від усього цього, є те, що струни не мають append функції, оскільки вони незмінні.
Лілі Чунг

46

Змінна a вказує на об'єкт "Dog". Найкраще думати про змінну в Python як тег. Ви можете перемістити позначку різних об'єктів, є те , що ви зробили , коли ви змінили a = "dog"в a = "dog eats treats".

Однак незмінність відноситься до об'єкта, а не до мітки.


Якщо ви намагалися a[1] = 'z'зробити "dog"в "dzg", ви отримаєте помилку:

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

оскільки рядки не підтримують призначення елементів, тому вони незмінні.


19

Щось можна змінити лише тоді, коли ми зможемо змінити значення, які зберігаються в пам'яті, не змінюючи самого місця пам'яті.

Хитрість полягає в тому, що якщо ви виявите, що розташування пам'яті до і після зміни однакове, воно змінюється.

Наприклад, список змінюється. Як?

>> 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до і після переназначення відрізняється, тому це доводить, що ви насправді не мутуєте, а вказуєте змінну на нове місце. Що не мутує цей рядок, а мутує цю змінну.


11

Змінна - це лише мітка, що вказує на об'єкт. Об'єкт є незмінним, але ви можете зробити точку мітки зовсім іншим об'єктом, якщо цього хочете.


8

Поміркуйте:

>>> 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- це лише мітка, яка вказує на цю адресу пам'яті. Це можна змінити, щоб вказати на що завгодно.


7

Заява 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"в якому мешкали, що означає незмінне. Однак ми можемо змінити, які мітки, якщо такі є, вказують на цей розділ пам'яті.


6
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

5

Існує різниця між даними та міткою, з якою вона пов’язана. Наприклад, коли ви робите

a = "dog"

дані "dog"створюються і ставляться під мітку a. Мітка може змінюватися, але те, що є в пам'яті, не буде. Дані "dog"залишатимуться в пам'яті (доки смітник не видалить її) після цього

a = "cat"

aЗараз у вашій програмі ^ вказує на ^, "cat"але рядок "dog"не змінився.


3

Струни Python незмінні. Однак aце не рядок: це змінна зі значенням рядка. Ви не можете змінити рядок, але можете змінити значення змінної на нову.


2

Змінні можуть вказувати куди завгодно. Помилка буде видана, якщо ви зробите наступне:

a = "dog"
print a                   #dog
a[1] = "g"                #ERROR!!!!!! STRINGS ARE IMMUTABLE

2

Об'єкти рядка 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[0] = 'c'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    **TypeError**: 'str' object does not support item assignment

Виникає помилка.


2

"mutable" означає, що ми можемо змінити вміст рядка, "незмінний" означає, що ми не можемо додати додаткову рядок.

натисніть для підтвердження фотографії


1

>>> a = 'dogs'

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

'dogs eat treats'

>>> print a

'dogs'

Незмінний, чи не так ?!

Частина змін змінної вже обговорювалася.


1
Це не доводить чи не спростовує змінність струн python, лише те, що replace()метод повертає нову рядок.
Brent Hronik

1

Розглянемо це додаток до свого прикладу

 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/


1

Додайте трохи більше до вищезгаданих відповідей.

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'файл не було вимкнено.


0

Підсумовуючи:

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, тому що, очевидно, вона непорушна.


0

Вбудована функція id()повертає ідентичність об'єкта як ціле число. Це ціле число зазвичай відповідає розташуванню об'єкта в пам'яті.

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

139831803293008

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

139831803293120

Спочатку "a" зберігається в пам'яті 139831803293008, оскільки об'єкт рядка незмінний в python, якщо ви спробуєте змінити і передати новий посилання, буде видалено і буде вказівником на нове місце пам'яті (139831803293120).


0
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

2
Хоча цей код може вирішити проблему ОП, краще включити пояснення щодо того, як ваш код вирішує проблему ОП. Таким чином майбутні відвідувачі можуть дізнатисясь із вашої публікації та застосувати її до власного коду. ТАК - це не програма кодування, а ресурс для знань. Крім того, швидше за все буде сприйнято високу якість, повні відповіді. Ці функції, поряд з вимогою, що всі повідомлення є автономними, є деякою сильною стороною SO як платформи, що відрізняє її від форумів. Ви можете редагувати, щоб додати додаткову інформацію та / або доповнити свої пояснення джерельною документацією
SherylHohman


-1

Ми просто об'єднаємо два значення рядка. Ми ніколи не змінюємо значення (a). Щойно (a) представляють ще один блок пам'яті, який має значення "dogdog". Оскільки в бекенді одна змінна ніколи не представляє два блоки пам'яті одночасно. Значення (a) перед конкатенацією було "собакою". Але після цього (а) представляють "собаку", тому що зараз (а) в бекенд-реп. блок, який має значення "собачий собака". І "собака" є респ. по (b) і "dog" не зараховується як значення сміття, поки (b) не представляє "dog".

Плутанина полягає в тому, що ми представляємо блоки пам'яті (які містять дані або інформацію.) У бекенді з однаковою назвою змінної.


-2

Ви можете зробити масивний масив незмінним і використовувати перший елемент:

numpyarrayname[0] = "write once"

тоді:

numpyarrayname.setflags(write=False)

або

numpyarrayname.flags.writeable = False
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.