Comment copier une chaîne Python?

92

Je fais ça:

a = 'hello'

Et maintenant, je veux juste une copie indépendante de a:

import copy

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

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

Sortie [3]:

[4365576160, 4365576160, 4365576160, 4365576160, 4365576160]

Pourquoi ont-ils tous la même adresse mémoire et comment puis-je en obtenir une copie a?

d'habitude moi
la source
3
Pour obtenir une réponse différente de celle de Martijin (qui est tout à fait correcte, mais ne répond pas nécessairement à la question comme indiqué), vous voudrez peut-être fournir plus de détails / cas d'utilisation pour montrer pourquoi vous voulez qu'elle soit copiée.
elmo
4
Comme @elemo l'indique, cela pourrait être un problème XY .
martineau
2
Je voulais estimer l'utilisation de la mémoire d'un dictionnaire imbriqué de la forme d[ 'hello' ] = e, où e[ 'hi' ] = 'again'. Pour générer un tel dictionnaire imbriqué, j'ai généré un edictionnaire unique et je l'ai copié plusieurs fois. J'ai remarqué que la consommation de mémoire était très faible, ce qui a conduit à ma question ici. Maintenant, je comprends qu'aucune copie de chaîne n'a été créée, d'où la faible consommation de mémoire.
habitude moi
1
Si vous voulez bêtre une version modifiée de asans modifier a, laissez simplement bêtre le résultat de n'importe quelle opération. par exemple des b = a[2:-1]ensembles bà 'll'et areste » hello'.
OJFord
Ollie a raison. Cela est dû au fait que str est un type immuable. En raison de l'utilisation de singletons par python (et probablement d'autres optimisations internes), vous ne verrez pas la mémoire s'étendre comme vous le pensez lors de la copie du dictionnaire e.
FizxMike

Réponses:

137

Vous n'avez pas besoin de copier une chaîne Python. Ils sont immuables et le copymodule renvoie toujours l'original dans de tels cas, comme le font str()la tranche de chaîne entière, et concaténant avec une chaîne vide.

De plus, votre 'hello'chaîne est internée ( certaines chaînes le sont ). Python essaie délibérément de ne conserver qu'une seule copie, car cela accélère les recherches dans le dictionnaire.

Une façon de contourner ce problème est de créer une nouvelle chaîne, puis de la découper dans le contenu d'origine:

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

Mais tout ce que vous faites maintenant, c'est perdre de la mémoire. Ce n'est pas comme si vous pouviez muter ces objets chaîne de quelque manière que ce soit, après tout.

Si tout ce que vous voulez savoir est la quantité de mémoire requise par un objet Python, utilisez sys.getsizeof(); il vous donne l'empreinte mémoire de n'importe quel objet Python.

Pour les conteneurs, cela n'inclut pas le contenu; vous devrez récurer dans chaque conteneur pour calculer une taille de mémoire totale:

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

Vous pouvez ensuite choisir d'utiliser le id()suivi pour prendre une empreinte mémoire réelle ou pour estimer une empreinte maximale si les objets n'ont pas été mis en cache et réutilisés.

Martijn Pieters
la source
4
Il existe plusieurs façons de créer un nouvel objet chaîne, tel que b = ''.join(a).
martineau
@martineau: bien sûr, je voulais vraiment dire «à sens unique».
Martijn Pieters
10
Accent sur "Vous n'avez pas besoin de copier une chaîne Python". Il y a une raison pour laquelle ces opérations renvoient simplement la même chaîne.
tcooc
1
Dans ce cas, cependant, l'OP tente de gaspiller de la mémoire. Puisqu'il veut savoir combien de mémoire sera utilisée par une certaine quantité de chaînes, c'est le but réel. De toute évidence, il pourrait générer des chaînes uniques, mais c'est juste un travail inutile comme solution de contournement.
Gabe
8
+1 pour "nonchalamment" en utilisant un exemple qui produirait 42 .
Bakuriu
11

Vous pouvez copier une chaîne en python via le formatage de chaîne:

>>> a = 'foo'  
>>> b = '%s' % a  
>>> id(a), id(b)  
(140595444686784, 140595444726400)  
Richard Urbain
la source
4
Pas vrai dans Python 3.6.5. id (a) et id (b) sont identiques. Les résultats ne sont pas différents même lorsque j'ai utilisé la version moderne du format, à savoir,b = '{:s}'.format(a)
Seshadri R
7

Je commence juste quelques manipulations de chaînes et j'ai trouvé cette question. J'essayais probablement de faire quelque chose comme l'OP, "d'habitude moi". Les réponses précédentes n'ont pas dissipé ma confusion, mais après y avoir réfléchi un peu, j'ai finalement "compris".

Tant que a, b, c, det eont la même valeur, ils font référence au même endroit. La mémoire est sauvegardée. Dès que la variable commence à avoir des valeurs différentes, elles commencent à avoir des références différentes. Mon expérience d'apprentissage est venue de ce code:

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

La sortie imprimée est:

[4538504992, 4538504992, 4538504992, 4538504992, 4538504992]

hello hello hello hello hello

[6113502048, 4538504992, 4538504992, 4538504992, 5570935808]

goodbye hello hello hello hello something
Karl s
la source
Plus de détails sur le comportement sont décrits dans ce post stackoverflow.com/questions/2123925/…
dlasalle
3

La copie d'une chaîne peut être effectuée de deux manières, soit copier l'emplacement a = "a" b = a ou vous pouvez cloner ce qui signifie que b ne sera pas affecté lorsque a est modifié, ce qui est fait par a = 'a' b = a [:]

Thomas Youngson
la source
2

Pour le dire différemment, "id ()" n'est pas ce qui vous importe. Vous voulez savoir si le nom de la variable peut être modifié sans nuire au nom de la variable source.

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

Si vous êtes habitué à C, alors ce sont comme des variables de pointeur sauf que vous ne pouvez pas les dé-référencer pour modifier ce sur quoi elles pointent, mais id () vous dira où elles pointent actuellement.

Le problème pour les programmeurs python survient lorsque vous considérez des structures plus profondes comme des listes ou des dictionnaires:

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

Ici, o et x font référence au même dict o ['a'] et x ['a'], et ce dict est "mutable" dans le sens où vous pouvez changer la valeur de la clé 'a'. C'est pourquoi "y" doit être une copie et y ['a'] peut faire référence à autre chose.

Charles Thayer
la source