As strings de Python não são imutáveis? Então, por que a + “” + b funciona?

109

Meu entendimento era que as strings Python são imutáveis.

Tentei o seguinte código:

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
# !!!

O Python não deveria ter impedido a atribuição? Provavelmente estou perdendo alguma coisa.

Qualquer ideia?

Jason
fonte
55
A string em si é imutável, mas o rótulo pode mudar.
mitch
6
Atribuir um novo valor a uma variável existente é perfeitamente válido. Python não tem constantes. Isso é independente da mutabilidade do tipo de dados.
Felix Kling
14
Você pode querer dar uma olhada na id()função. aterá um id diferente antes e depois da atribuição, indicando que está apontando para objetos diferentes. Da mesma forma com código como b = avocê encontrará ae bterá o mesmo id, indicando que eles estão fazendo referência ao mesmo objeto.
DRH de
O link de delnan é exatamente o que eu estava me referindo.
mitch

Respostas:

180

Primeiro aapontou para a string "Dog". Em seguida, você alterou a variável apara apontar para uma nova string "Dog come trata". Você não alterou a string "Dog". Strings são imutáveis, variáveis ​​podem apontar para o que quiserem.

Bort
fonte
34
É ainda mais convincente tentar algo como x = 'abc'; x [1] = 'x' no Python repl
xpmatteo
1
Se você gostaria de entender o interior um pouco mais, veja minha resposta. stackoverflow.com/a/40702094/117471
Bruno Bronosky
53

Os próprios objetos string são imutáveis.

A variável, aque aponta para a string, é mutável.

Considerar:

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.
Sebastian Paaske Tørholm
fonte
@jason tenta o mesmo tipo de operações com listas (que são mutáveis) para ver a diferença a.append (3) corresponde a a = a + "Foo"
jimifiki
1
@jimifiki a.append(3) não é o mesmo que a = a + 3. Não é uniforme a += 3(adição inplace é equivalente a .extend, não a .append).
@delnan e então, o quê? Para mostrar que strings e listas se comportam de maneira diferente, você pode assumir que a = a + "Foo" é o mesmo que a.append (algo). Em qualquer caso, não é o mesmo. Obviamente. Você ficou mais feliz lendo a.extend ([algo]) em vez de a.append (algo)? Não vejo grande diferença neste contexto. Mas provavelmente estou perdendo alguma coisa. Thruth depende do contexto
Jimifiki
@jimifiki: Do que você está falando? +se comporta da mesma forma para listas e strings - ele concatena criando uma nova cópia e não altera nenhum operando.
6
O ponto realmente importante a tirar de tudo isso é que as strings não têm uma append função porque são imutáveis.
Lily Chung
46

A variável a está apontando para o objeto "Cachorro". É melhor pensar na variável em Python como uma tag. Você pode mover a tag para objetos diferentes, que é o que você fez quando mudou a = "dog"para a = "dog eats treats".

No entanto, a imutabilidade se refere ao objeto, não à tag.


Se você tentasse a[1] = 'z'fazer "dog"em "dzg", obteria o erro:

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

porque as strings não suportam atribuição de itens, portanto, são imutáveis.

crtan
fonte
19

Algo é mutável apenas quando somos capazes de alterar os valores mantidos no local da memória sem alterar o próprio local da memória.

O truque é: se você descobrir que a localização da memória antes e depois da alteração é a mesma, ela é mutável.

Por exemplo, a lista é mutável. Quão?

>> 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.

Uma string é imutável. Como podemos provar isso?

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

Nós temos

TypeError: o objeto 'str' não suporta atribuição de item

Portanto, falhamos na mutação da string. Isso significa que uma string é imutável.

Ao reatribuir, você altera a variável para apontar para um novo local. Aqui você não alterou a string, mas alterou a própria variável. A seguir está o que você está fazendo.

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

idantes e depois da reatribuição é diferente, então isso prova que você não está realmente sofrendo mutação, mas apontando a variável para um novo local. O que não é uma mutação dessa string, mas uma mutação dessa variável.

Harish Kayarohanam
fonte
11

Uma variável é apenas um rótulo apontando para um objeto. O objeto é imutável, mas você pode fazer o rótulo apontar para um objeto completamente diferente, se desejar.

Jcollado
fonte
8

Considerar:

>>> 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>

Observe que a localização da memória hexadecimal não mudou quando armazenei o mesmo valor na variável duas vezes. Ele mudou quando armazenei um valor diferente. A string é imutável. Não por zelo, mas porque você paga a penalidade de desempenho de criar um novo objeto na memória. A variável aé apenas um rótulo apontando para aquele endereço de memória. Ele pode ser alterado para apontar para qualquer coisa.

Bruno Bronosky
fonte
7

A instrução a = a + " " + b + " " + cpode ser dividida com base em ponteiros.

a + " "diz para me dar o que aaponta, o que não pode ser alterado e adicionar" " ao meu conjunto de trabalho atual.

memória:

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

+ bdiz para me dar o que baponta, o que não pode ser alterado, e adicioná-lo ao conjunto de trabalho atual.

memória:

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

+ " " + cdiz adicionar " "ao conjunto atual. Em seguida, dê-me o que caponta, o que não pode ser alterado, e adicione-o ao conjunto de trabalho atual. memória:

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

Por fim, a =diz definir meu ponteiro para apontar para o conjunto resultante.

memória:

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

"Dog"é recuperado, porque não há mais ponteiros se conectando a seu pedaço de memória. Nunca modificamos a seção de memória "Dog"em que residia, que é o que significa imutável. No entanto, podemos alterar quais rótulos, se houver, apontam para essa seção da memória.

Spencer Rathbun
fonte
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
user744629
fonte
5

Há uma diferença entre os dados e o rótulo ao qual estão associados. Por exemplo, quando você faz

a = "dog"

os dados "dog"são criados e colocados sob o rótulo a. O rótulo pode mudar, mas o que está na memória não. Os dados "dog"ainda existirão na memória (até que o coletor de lixo os exclua) depois que você fizer

a = "cat"

Em seu programa aagora ^ aponta para ^ "cat"mas a string "dog"não mudou.

mitch
fonte
3

As strings Python são imutáveis. No entanto, anão é uma string: é uma variável com um valor de string. Você não pode alterar a string, mas pode alterar o valor da variável para uma nova string.

Michael J. Barber
fonte
2

As variáveis ​​podem apontar para qualquer lugar que desejarem. Um erro será gerado se você fizer o seguinte:

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

Os objetos de string do Python são imutáveis. Exemplo:

>>> 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'

Neste exemplo, podemos ver que quando atribuímos valores diferentes em um, ele não se modifica. Um novo objeto é criado.
E não pode ser modificado. Exemplo:

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

Ocorreu um erro.

Tanim_113
fonte
2

'mutável' significa que podemos alterar o conteúdo da string, 'imutável' significa que não podemos adicionar uma string extra.

clique para prova de foto


fonte
1

>>> a = 'dogs'

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

'dogs eat treats'

>>> print a

'dogs'

Imutável, não é ?!

A parte da mudança variável já foi discutida.

Lohit Bisen
fonte
1
Isso não prova ou refuta a mutabilidade das strings python, apenas que o replace()método retorna uma nova string.
Brent Hronik
1

Considere esta adição ao seu exemplo

 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

Uma das explicações mais precisas que encontrei em um blog é:

Em Python, (quase) tudo é um objeto. O que comumente nos referimos como "variáveis" em Python são mais apropriadamente chamados de nomes. Da mesma forma, "atribuição" é realmente a vinculação de um nome a um objeto. Cada associação possui um escopo que define sua visibilidade, geralmente o bloco em que o nome se origina.

Por exemplo:

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

Quando mais tarde dissermos some_guy = 'George', o objeto string contendo 'Fred' não será afetado. Acabamos de alterar a vinculação do nome some_guy. Não mudamos, entretanto, os objetos string 'Fred' ou 'George'. No que nos diz respeito, eles podem viver indefinidamente.

Link para o blog: https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/

7to4
fonte
1

Adicionando um pouco mais às respostas mencionadas acima.

id de uma variável muda após a reatribuição.

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

O que significa que alteramos a variável apara apontar para uma nova string. Agora existem dois string objetos (str):

'initial_string'com id= 139982120425648

e

'new_string'com id= 139982120425776

Considere o código abaixo:

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

Agora, baponta para 'initial_string'e tem o mesmo idque atinha antes da reatribuição.

Portanto, o 'intial_string'não sofreu mutação.

Rahul Madiwale
fonte
0

Resumindo:

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

Não imutável:

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

Imutável:

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

Este é um erro no Python 3 porque é imutável. E não é um erro no Python 2 porque claramente não é imutável.

pjf
fonte
0

A função id()interna retorna a identidade de um objeto como um inteiro. Este inteiro geralmente corresponde à localização do objeto na memória.

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

139831803293008

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

139831803293120

Inicialmente, 'a' é armazenado no local da memória 139831803293008, pois o objeto string é imutável em python se você tentar modificar e reatribuir a referência será removida e será um ponteiro para um novo local da memória (139831803293120).

learner5060
fonte
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
10xAI
fonte
2
Embora este código possa resolver o problema do OP, é melhor incluir uma explicação de como o seu código aborda o problema do OP. Desta forma, os futuros visitantes podem aprender com sua postagem e aplicá-la ao seu próprio código. SO não é um serviço de codificação, mas um recurso de conhecimento. Além disso, respostas completas e de alta qualidade têm maior probabilidade de serem votadas positivamente. Esses recursos, junto com o requisito de que todas as postagens sejam independentes, são alguns dos pontos fortes do SO como plataforma, que o diferencia dos fóruns. Você pode editar para adicionar informações adicionais e / ou complementar suas explicações com a documentação de origem
SherylHohman
-1

Esta imagem dá a resposta. Por favor, leia.

insira a descrição da imagem aqui

Wen Qi
fonte
-1

Devemos apenas concatenar os dois valores de string. Nunca mudamos o valor de (a). Agora, (a) representa outro bloco de memória que tem o valor "cãozinho". Porque no backend, uma variável nunca representa dois blocos de memória ao mesmo tempo. O valor de (a) antes da concatenação era "cachorro". Mas depois disso (a) representam o "cãozinho", porque agora (a) no representante de backend. o bloco que tem o valor "dogdog". E "cachorro" é representante. por (b) e "cachorro" não é contado como valor de lixo até que (b) represente o "cachorro".

A confusão é que representamos os blocos de memória (que contêm dados ou informações) no backend com o mesmo nome de variável.

dineshmehta
fonte
-2

Você pode tornar uma matriz numpy imutável e usar o primeiro elemento:

numpyarrayname[0] = "write once"

então:

numpyarrayname.setflags(write=False)

ou

numpyarrayname.flags.writeable = False
PauluaP
fonte