2012-02-01 8 views
62

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

Я попытался следующий код:

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 предотвратил задание? Я, вероятно, что-то пропустил.

Есть идеи?

+34

Сама строка неизменна, но ярлык может меняться. – mitch

+4

Назначение нового значения для существующей переменной вполне допустимо. У Python нет констант. Это не зависит от изменчивости типа данных. –

+5

Возможно, вы захотите взглянуть на функцию 'id()'. 'a' будет иметь другой идентификатор до и после назначения, указывая, что он указывает на разные объекты. Аналогично с кодом, подобным 'b = a', вы обнаружите, что' a' и 'b' будут иметь одинаковый идентификатор, указывая, что они ссылаются на один и тот же объект. – DRH

ответ

118

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

+12

Еще более убедительно попробовать что-то вроде x = 'abc'; x [1] = 'x' в Python repl – xpmatteo

+0

Если вы хотите понять внутренности немного больше, см. мой ответ. https://stackoverflow.com/a/40702094/117471 –

38

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

Переменная, 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. 
+0

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

+1

@jimifiki 'a.append (3)' ** is not ** то же, что и 'a = a + 3'. Это даже не 'a + = 3' (дополнение inplace эквивалентно' .extend', а не '.append'). – delnan

+0

@ delnan и так, что? Чтобы показать, что строки и списки ведут себя по-разному, вы можете предположить, что a = a + "Foo" совпадает с a.append (что-то). В любом случае это не одно и то же. Очевидно. Вы счастливее читали a.extend ([something]) вместо a.append (что-то)? Я не вижу в этом контексте большой разницы. Но, наверное, я что-то упустил. Thruth зависит от контекста – jimifiki

11

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

3

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

5

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

a = "dog" 

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

a = "cat" 

В вашей программе a Теперь^указывает на^"cat" но строка "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 = 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", в котором находится неизменное. Однако мы можем изменить, какие метки, если таковые имеются, указывают на этот раздел памяти.

23

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

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


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

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

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

+0

Это более ясно по сравнению с другими! –

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, потому что явно она не является неизменной.

11

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

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

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

>> 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' object does not support item assignment

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

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

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

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

1

>>> a = 'dogs'

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

'dogs eat treats'

>>> print a

'dogs'

Неизменное, не так ли ?!

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

+0

Это не доказывает или не опровергает изменчивость строк python, так как метод 'replace()' возвращает новую строку. –

4

Рассмотрим:

>>> 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 - это всего лишь метка, указывающая на адрес этой памяти. Его можно изменить, чтобы указать на что угодно.

2

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

a = "dog" 
print a     #dog 
a[1] = "g"    #ERROR!!!!!! STRINGS ARE IMMUTABLE 
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 

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

In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates.

Eg:

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

When we later say some_guy = 'George', the string object containing 'Fred' is unaffected. We've just changed the binding of the name some_guy. We haven't, however, changed either the 'Fred' or 'George' string objects. As far as we're concerned, they may live on indefinitely.

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

0

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

numpyarrayname[0] = "write once" 

затем:

numpyarrayname.setflags(write=False) 

или

numpyarrayname.flags.writeable = False