Wie kann ich eine Python-Zeichenfolge kopieren?

87

Ich mache das:

a = 'hello'

Und jetzt möchte ich nur eine unabhängige Kopie von a:

import copy

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

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

Out [3]:

[4365576160, 4365576160, 4365576160, 4365576160, 4365576160]

Warum haben alle dieselbe Speicheradresse und wie kann ich eine Kopie davon erhalten a?

üblich ich
quelle
3
Um eine andere Antwort als die von Martijin zu erhalten (die völlig korrekt ist, aber nicht unbedingt die angegebene Frage beantwortet), möchten Sie möglicherweise mehr Details / Anwendungsfälle bereitstellen, um zu zeigen, warum Sie sie kopieren möchten.
Elmo
4
Wie @elemo impliziert, könnte dies ein XY-Problem sein .
Martineau
2
Ich war daran interessiert, die Speichernutzung eines verschachtelten Wörterbuchs der Form abzuschätzen d[ 'hello' ] = e, wo e[ 'hi' ] = 'again'. Um ein solches verschachteltes Wörterbuch zu generieren, habe ich ein einzelnes eWörterbuch generiert und es mehrmals kopiert. Mir ist aufgefallen, dass der Speicherverbrauch sehr gering war, was hier zu meiner Frage führte. Jetzt verstehe ich, dass keine String-Kopien erstellt wurden, daher der geringe Speicherverbrauch.
Normalerweise ich
1
Wenn Sie beine modifizierte Version von sein möchten , aohne sie zu ändern a, lassen Sie beinfach das Ergebnis einer beliebigen Operation sein. zB b = a[2:-1]setzt bauf 'll'und ableibt ' hello'.
OJFord
Ollie ist richtig. Dies liegt daran, dass str ein unveränderlicher Typ ist. Aufgrund der Verwendung von Singletons durch Python (und wahrscheinlich anderer interner Optimierungen) wird der Speicher beim Kopieren des E-Wörterbuchs nicht wie erwartet erweitert.
FizxMike

Antworten:

133

Sie müssen nicht benötigen eine Python - Zeichenfolge zu kopieren. Sie sind unveränderlich, und das copyModul gibt in solchen Fällen immer das Original zurück, ebenso wie str()das gesamte String-Slice und die Verkettung mit einem leeren String.

Darüber hinaus ist Ihre 'hello'Zeichenfolge interniert ( bestimmte Zeichenfolgen sind ). Python versucht absichtlich, nur eine Kopie zu behalten, da dies die Suche nach Wörterbüchern beschleunigt.

Eine Möglichkeit, dies zu umgehen, besteht darin, eine neue Zeichenfolge zu erstellen und diese Zeichenfolge dann wieder auf den ursprünglichen Inhalt zurückzuschneiden:

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

Aber alles, was Sie jetzt tun, ist Speicherverschwendung. Es ist schließlich nicht so, dass Sie diese Zeichenfolgenobjekte auf irgendeine Weise mutieren können.

Wenn Sie nur wissen möchten, wie viel Speicher ein Python-Objekt benötigt, verwenden Sie sys.getsizeof(); Es gibt Ihnen den Speicherbedarf jedes Python-Objekts.

Bei Containern ist der Inhalt nicht enthalten. Sie müssten in jeden Container zurückgreifen, um eine Gesamtspeichergröße zu berechnen:

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

Sie können dann die id()Verfolgung verwenden, um einen tatsächlichen Speicherbedarf zu ermitteln oder einen maximalen Speicherbedarf zu schätzen, wenn Objekte nicht zwischengespeichert und wiederverwendet wurden.

Martijn Pieters
quelle
4
Es gibt mehr als nur eine Möglichkeit, ein neues Zeichenfolgenobjekt zu erstellen, z b = ''.join(a).
Martineau
@martineau: klar, ich wollte wirklich "one way" sagen.
Martijn Pieters
10
Schwerpunkt auf "Sie müssen keinen Python-String kopieren". Es gibt einen Grund, warum diese Operationen einfach dieselbe Zeichenfolge zurückgeben.
Tcooc
1
In diesem Fall versucht das OP jedoch, Speicher zu verschwenden. Da er wissen möchte, wie viel Speicher von einer bestimmten Anzahl von Zeichenfolgen verwendet wird, ist dies das eigentliche Ziel. Natürlich könnte er eindeutige Zeichenfolgen generieren, aber das ist nur unnötige Arbeit als Problemumgehung.
Gabe
8
+1 für "beiläufig" anhand eines Beispiels, das 42 ausgeben würde .
Bakuriu
9

Sie können eine Zeichenfolge in Python über die Zeichenfolgenformatierung kopieren:

>>> a = 'foo'  
>>> b = '%s' % a  
>>> id(a), id(b)  
(140595444686784, 140595444726400)  
Richard Urban
quelle
4
Nicht wahr in Python 3.6.5. id (a) und id (b) sind identisch. Die Ergebnisse sind nicht anders, auch wenn ich die moderne Version des Formats verwendet habe, nämlichb = '{:s}'.format(a)
Seshadri R
7

Ich fange gerade mit einigen String-Manipulationen an und habe diese Frage gefunden. Ich habe wahrscheinlich versucht, so etwas wie das OP zu machen, "normal ich". Die vorherigen Antworten haben meine Verwirrung nicht geklärt, aber nachdem ich ein wenig darüber nachgedacht hatte, habe ich es endlich "verstanden".

Solange a, b, c, d, und eden gleichen Wert haben , verweisen sie an der gleichen Stelle. Speicher wird gespeichert. Sobald die Variable unterschiedliche Werte aufweist, erhalten sie unterschiedliche Referenzen. Meine Lernerfahrung ergab sich aus diesem 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

Die gedruckte Ausgabe ist:

[4538504992, 4538504992, 4538504992, 4538504992, 4538504992]

hello hello hello hello hello

[6113502048, 4538504992, 4538504992, 4538504992, 5570935808]

goodbye hello hello hello hello something
karl s
quelle
Weitere Details für das Verhalten sind in diesem Beitrag beschrieben. Stackoverflow.com/questions/2123925/…
dlasalle
2

Das Kopieren einer Zeichenfolge kann auf zwei Arten erfolgen: Kopieren Sie entweder die Position a = "a" b = a oder Sie können klonen, was bedeutet, dass b nicht betroffen ist, wenn a geändert wird, was durch a = 'a' b = a [:] erfolgt.

Thomas Youngson
quelle
2

Anders ausgedrückt: "id ()" ist nicht das, was Sie interessiert. Sie möchten wissen, ob der Variablenname geändert werden kann, ohne den Namen der Quellvariablen zu beschädigen.

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

Wenn Sie an C gewöhnt sind, sind diese wie Zeigervariablen, außer dass Sie sie nicht de-referenzieren können, um zu ändern, worauf sie zeigen, aber id () sagt Ihnen, wohin sie aktuell zeigen.

Das Problem für Python-Programmierer tritt auf, wenn Sie tiefere Strukturen wie Listen oder Diktate betrachten:

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

Hier beziehen sich o und x auf dasselbe Diktat o ['a'] und x ['a'], und dieses Diktat ist in dem Sinne "veränderlich", dass Sie den Wert für Schlüssel 'a' ändern können. Deshalb muss "y" eine Kopie sein und y ['a'] kann sich auf etwas anderes beziehen.

Charles Thayer
quelle