Robię to:
a = 'hello'
A teraz chcę mieć niezależną kopię a
:
import copy
b = str(a)
c = a[:]
d = a + ''
e = copy.copy(a)
map( id, [ a,b,c,d,e ] )
Na zewnątrz [3]:
[4365576160, 4365576160, 4365576160, 4365576160, 4365576160]
Dlaczego wszystkie mają ten sam adres w pamięci i jak mogę uzyskać kopię a
?
python
string
python-2.7
zwykły ja
źródło
źródło
d[ 'hello' ] = e
, gdziee[ 'hi' ] = 'again'
. Aby wygenerować taki zagnieżdżony słownik, wygenerowałem pojedynczye
słownik i skopiowałem go wiele razy. Zauważyłem, że zużycie pamięci było bardzo niskie, co doprowadziło do mojego pytania. Teraz rozumiem, że nie utworzono żadnych kopii ciągów, stąd niskie zużycie pamięci.b
być zmodyfikowaną wersjąa
bez modyfikowaniaa
, po prostu pozwólb
być wynikiem dowolnej operacji. np.b = a[2:-1]
ustawiab
się'll'
ia
pozostaje ”hello'
.Odpowiedzi:
Nie musisz kopiować ciągu znaków Pythona. Są niezmienne, a
copy
moduł zawsze zwraca oryginał w takich przypadkach, tak jakstr()
cały kawałek ciągu i łącząc go z pustym ciągiem.Co więcej, twój
'hello'
ciąg jest internowany ( niektóre ciągi są ). Python celowo stara się zachować tylko jedną kopię, ponieważ to przyspiesza przeszukiwanie słownika.Jednym ze sposobów obejścia tego problemu jest utworzenie nowego ciągu, a następnie wycięcie go z powrotem do oryginalnej zawartości:
>>> a = 'hello' >>> b = (a + '.')[:-1] >>> id(a), id(b) (4435312528, 4435312432)
Ale wszystko, co teraz robisz, to marnowanie pamięci. W końcu nie jest tak, że można w jakikolwiek sposób mutować te obiekty typu string.
Jeśli wszystko, co chciałeś wiedzieć, to ile pamięci wymaga obiekt Pythona, użyj
sys.getsizeof()
; daje ślad pamięci dowolnego obiektu Pythona.W przypadku pojemników nie obejmuje to zawartości; musiałbyś powtórzyć w każdym kontenerze, aby obliczyć całkowity rozmiar pamięci:
>>> 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
Następnie możesz użyć
id()
śledzenia, aby pobrać rzeczywisty ślad pamięci lub oszacować maksymalny ślad, gdyby obiekty nie były buforowane i ponownie używane.źródło
b = ''.join(a)
.Możesz skopiować ciąg w pythonie poprzez formatowanie ciągu:
>>> a = 'foo' >>> b = '%s' % a >>> id(a), id(b) (140595444686784, 140595444726400)
źródło
b = '{:s}'.format(a)
Właśnie zaczynam manipulować strunami i znalazłem to pytanie. Prawdopodobnie próbowałem zrobić coś takiego jak OP, „zwykły ja”. Poprzednie odpowiedzi nie wyjaśniły mojego zmieszania, ale po zastanowieniu się nad tym w końcu „zrozumiałem”.
Dopóki
a
,b
,c
,d
, ie
mają taką samą wartość, referencję one do tego samego miejsca. Pamięć została zapisana. Gdy tylko zmienna zacznie mieć różne wartości, zaczną mieć różne odniesienia. Moje doświadczenie w nauce pochodzi z tego kodu: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
Wydruk to:
[4538504992, 4538504992, 4538504992, 4538504992, 4538504992] hello hello hello hello hello [6113502048, 4538504992, 4538504992, 4538504992, 5570935808] goodbye hello hello hello hello something
źródło
Kopiowanie łańcucha można wykonać na dwa sposoby: skopiuj lokalizację a = "a" b = a lub możesz sklonować, co oznacza, że b nie zostanie zmieniony, gdy a zostanie zmienione, co jest wykonywane przez a = 'a' b = a [:]
źródło
Inaczej mówiąc, "id ()" nie jest tym, na czym ci zależy. Chcesz wiedzieć, czy nazwę zmiennej można zmodyfikować bez szkody dla nazwy zmiennej źródłowej.
>>> a = 'hello' >>> b = a[:] >>> c = a >>> b += ' world' >>> c += ', bye' >>> a 'hello' >>> b 'hello world' >>> c 'hello, bye'
Jeśli jesteś przyzwyczajony do C, to są one jak zmienne wskaźnikowe, z wyjątkiem tego, że nie możesz ich usunąć, aby zmodyfikować to, na co wskazują, ale id () powie ci, gdzie aktualnie wskazują.
Problem dla programistów Pythona pojawia się, gdy weźmiesz pod uwagę głębsze struktury, takie jak listy lub dykty:
>>> o={'a': 10} >>> x=o >>> y=o.copy() >>> x['a'] = 20 >>> y['a'] = 30 >>> o {'a': 20} >>> x {'a': 20} >>> y {'a': 30}
Tutaj o i x odnoszą się do tego samego dyktu o ['a'] i x ['a'], a ten dykt jest „zmienny” w tym sensie, że można zmienić wartość klucza „a”. Dlatego „y” musi być kopią, a y [„a”] może odnosić się do czegoś innego.
źródło