Como posso copiar uma string Python?

92

Eu faço isso:

a = 'hello'

E agora eu só quero uma cópia independente de a:

import copy

b = str(a)
c = a[:]
d = a + ''
e = copy.copy(a)

map( id, [ a,b,c,d,e ] )

Fora [3]:

[4365576160, 4365576160, 4365576160, 4365576160, 4365576160]

Por que todos eles têm o mesmo endereço de memória e como posso obter uma cópia dele a?

sempre eu
fonte
3
Para obter uma resposta diferente da de Martijin (que é totalmente correta, embora não responda necessariamente à pergunta conforme declarado), você pode fornecer mais detalhes / caso de uso para mostrar por que deseja que seja copiado.
elmo
4
Como @elemo sugere, isso pode ser um problema XY .
martineau de
2
Eu estava interessado em estimar o uso de memória de um dicionário aninhado do formulário d[ 'hello' ] = e, onde e[ 'hi' ] = 'again'. Para gerar esse dicionário aninhado, gerei um único edicionário e copiei-o várias vezes. Percebi que o consumo de memória estava muito baixo, o que me levou à minha dúvida aqui. Agora eu entendo que nenhuma cópia de string foi criada, daí o baixo consumo de memória.
normalmente me
1
Se você quer bser uma versão amodificada sem modificar a, deixe bser o resultado de qualquer operação. por exemplo, b = a[2:-1]define bpara 'll'e apermanece ' hello'.
OJFord
Ollie está correto. Isso ocorre porque str é um tipo imutável. Devido ao uso de singletons do python (e provavelmente outras otimizações internas), você não verá a memória expandir como esperava ao copiar o dicionário e.
FizxMike de

Respostas:

137

Você não precisa copiar uma string Python. Eles são imutáveis, e o copymódulo sempre retorna o original em tais casos, assim como str()toda a fatia da string e concatenando com uma string vazia.

Além disso, sua 'hello'string está internada ( algumas strings estão ). Python tenta deliberadamente manter apenas uma cópia, pois isso torna as pesquisas no dicionário mais rápidas.

Uma maneira de contornar isso é criar uma nova string e, em seguida, fatiar essa string de volta ao conteúdo original:

>>> a = 'hello'
>>> b = (a + '.')[:-1]
>>> id(a), id(b)
(4435312528, 4435312432)

Mas tudo o que você está fazendo agora é desperdiçar memória. Afinal, não é como se você pudesse transformar esses objetos string de qualquer maneira.

Se tudo que você deseja saber é quanta memória um objeto Python requer, use sys.getsizeof(); ele fornece a pegada de memória de qualquer objeto Python.

Para contêineres, isso não inclui o conteúdo; você teria que recurse em cada contêiner para calcular o tamanho total da memória:

>>> import sys
>>> a = 'hello'
>>> sys.getsizeof(a)
42
>>> b = {'foo': 'bar'}
>>> sys.getsizeof(b)
280
>>> sys.getsizeof(b) + sum(sys.getsizeof(k) + sys.getsizeof(v) for k, v in b.items())
360

Você pode escolher usar o id()rastreamento para obter uma pegada de memória real ou para estimar uma pegada máxima se os objetos não foram armazenados em cache e reutilizados.

Martijn Pieters
fonte
4
Há mais de uma maneira de criar um novo objeto de string, como b = ''.join(a).
martineau de
@martineau: claro, eu realmente queria dizer 'mão única'.
Martijn Pieters
10
Ênfase em "Você não precisa copiar uma string Python". Há um motivo pelo qual essas operações simplesmente retornam a mesma string.
tcooc
1
Nesse caso, porém, o OP está tentando desperdiçar memória. Já que ele quer saber quanta memória será usada por uma certa quantidade de cordas, esse é o objetivo real. Obviamente, ele poderia gerar strings exclusivas, mas isso é apenas um trabalho desnecessário como solução alternativa.
Gabe
8
+1 para "casualmente" usando um exemplo que geraria 42 .
Bakuriu
11

Você pode copiar uma string em Python por meio da formatação de string:

>>> a = 'foo'  
>>> b = '%s' % a  
>>> id(a), id(b)  
(140595444686784, 140595444726400)  
Richard Urban
fonte
4
Não é verdade no Python 3.6.5. id (a) e id (b) são idênticos. Os resultados não são diferentes, mesmo quando usei a versão moderna do formato, viz.,b = '{:s}'.format(a)
Seshadri R
7

Estou apenas começando algumas manipulações de string e encontrei esta questão. Eu provavelmente estava tentando fazer algo como o OP, "sempre eu". As respostas anteriores não esclareceram minha confusão, mas depois de pensar um pouco sobre isso, finalmente "entendi".

Enquanto a, b, c, d, e etêm o mesmo valor, eles fazem referência ao mesmo lugar. A memória é salva. Assim que as variáveis ​​passam a ter valores diferentes, elas passam a ter referências diferentes. Minha experiência de aprendizado veio deste código:

import copy
a = 'hello'
b = str(a)
c = a[:]
d = a + ''
e = copy.copy(a)

print map( id, [ a,b,c,d,e ] )

print a, b, c, d, e

e = a + 'something'
a = 'goodbye'
print map( id, [ a,b,c,d,e ] )
print a, b, c, d, e

A saída impressa é:

[4538504992, 4538504992, 4538504992, 4538504992, 4538504992]

hello hello hello hello hello

[6113502048, 4538504992, 4538504992, 4538504992, 5570935808]

goodbye hello hello hello hello something
karl s
fonte
Mais detalhes sobre o comportamento estão descritos nesta postagem stackoverflow.com/questions/2123925/…
dlasalle
3

Copiar uma string pode ser feito de duas maneiras: copie o local a = "a" b = a ou você pode clonar, o que significa que b não será afetado quando a for alterado, o que é feito por a = 'a' b = a [:]

Thomas Youngson
fonte
2

Em outras palavras, "id ()" não é o que importa. Você deseja saber se o nome da variável pode ser modificado sem prejudicar o nome da variável de origem.

>>> a = 'hello'                                                                                                                                                                                                                                                                                        
>>> b = a[:]                                                                                                                                                                                                                                                                                           
>>> c = a                                                                                                                                                                                                                                                                                              
>>> b += ' world'                                                                                                                                                                                                                                                                                      
>>> c += ', bye'                                                                                                                                                                                                                                                                                       
>>> a                                                                                                                                                                                                                                                                                                  
'hello'                                                                                                                                                                                                                                                                                                
>>> b                                                                                                                                                                                                                                                                                                  
'hello world'                                                                                                                                                                                                                                                                                          
>>> c                                                                                                                                                                                                                                                                                                  
'hello, bye'                                                                                                                                                                                                                                                                                           

Se você está acostumado com C, então elas são como variáveis ​​de ponteiro, exceto que você não pode desreferenciá-las para modificar para onde elas apontam, mas id () lhe dirá para onde elas apontam atualmente.

O problema para os programadores Python surge quando você considera estruturas mais profundas, como listas ou dictes:

>>> o={'a': 10}                                                                                                                                                                                                                                                                                        
>>> x=o                                                                                                                                                                                                                                                                                                
>>> y=o.copy()                                                                                                                                                                                                                                                                                         
>>> x['a'] = 20                                                                                                                                                                                                                                                                                        
>>> y['a'] = 30                                                                                                                                                                                                                                                                                        
>>> o                                                                                                                                                                                                                                                                                                  
{'a': 20}                                                                                                                                                                                                                                                                                              
>>> x                                                                                                                                                                                                                                                                                                  
{'a': 20}                                                                                                                                                                                                                                                                                              
>>> y                                                                                                                                                                                                                                                                                                  
{'a': 30}                                                                                                                                                                                                                                                                                              

Aqui, o e x referem-se ao mesmo dict o ['a'] e x ['a'], e esse dict é "mutável" no sentido de que você pode alterar o valor da chave 'a'. É por isso que "y" precisa ser uma cópia e y ['a'] pode se referir a outra coisa.

Charles Thayer
fonte