Як я можу скопіювати рядок Python?


92

Я роблю це:

a = 'hello'

А тепер я просто хочу незалежну копію a:

import copy

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

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

Вихід [3]:

[4365576160, 4365576160, 4365576160, 4365576160, 4365576160]

Чому всі вони мають однакову адресу пам'яті та як я можу отримати копію a?


3
Щоб отримати відповідь, відмінну від відповіді Мартіджана (що є цілком коректним, хоча не обов’язково відповідає на запитання, як зазначено), ви можете надати більше деталей / випадків використання, щоб показати, чому ви хочете його скопіювати.
elmo

4
Як припускає @elemo, це може бути проблемою XY .
martineau

2
Мене зацікавило оцінити використання пам'яті вкладеного словника форми d[ 'hello' ] = e, де e[ 'hi' ] = 'again'. Щоб створити такий вкладений словник, я створив один eсловник і скопіював його кілька разів. Я помітив, що споживання пам'яті було дуже низьким, що призвело до мого запитання тут. Тепер я розумію, що не було створено копій рядків, отже, низьке споживання пам'яті.
звичайний я

1
Якщо ви хочете bбути модифікованою версією aбез модифікації a, просто нехай це bбуде результатом будь-якої операції. наприклад , b = a[2:-1]набори bдля 'll'і aзалишається " hello'.
OJFord

Оллі прав. Це тому, що str є незмінним типом. Через використання одиночних піктонів (і, можливо, інших внутрішніх оптимізацій), ви не побачите пам’яті, яка розширюється так, як ви очікували при копіюванні електронного словника.
FizxMike

Відповіді:


137

Вам не потрібно копіювати рядок Python. Вони незмінні, і copyмодуль завжди повертає оригінал у таких випадках, як це робиться str(), весь фрагмент рядка та конкатенація з порожнім рядком.

Більше того, ваш 'hello'рядок інтернований ( певні рядки є ). Python навмисно намагається зберегти лише одну копію, оскільки це пришвидшує пошук словника.

Один із способів обійти це - створити новий рядок, а потім зрізати цей рядок до вихідного вмісту:

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

Але все, що ви зараз робите, це марнотратити пам’ять. Зрештою, ви не можете будь-яким чином мутувати ці рядкові об’єкти.

Якщо все, що ви хотіли знати, це те, скільки пам'яті вимагає об’єкт Python, використовуйте sys.getsizeof(); це дає вам розмір пам'яті будь-якого об'єкта Python.

Для контейнерів це не включає вміст; вам доведеться повторити в кожен контейнер, щоб розрахувати загальний обсяг пам'яті:

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

Потім ви можете використовувати id()відстеження для взяття фактичного розміру пам'яті або для оцінки максимального розміру, якщо об’єкти не були кешовані та використані повторно.


4
Існує більше ніж один спосіб створення нового рядкового об'єкта, наприклад b = ''.join(a).
мартіно

@martineau: звичайно, я справді хотів сказати "в один бік".
Мартін Пітерс

10
Акцент на "Вам не потрібно копіювати рядок Python". Існує причина, чому ці операції просто повертають той самий рядок.
tcooc

1
У цьому випадку, однак, OP намагається витратити пам'ять. Оскільки він хоче знати, скільки пам'яті буде використано певною кількістю рядків, це справжня мета. Очевидно, що він міг генерувати унікальні рядки, але це просто непотрібна робота в якості обхідного шляху.
Гейб,

8
+1 для "випадково" на прикладі, який видасть 42 .
Бакуріу

11

Ви можете скопіювати рядок у python за допомогою форматування рядків:

>>> a = 'foo'  
>>> b = '%s' % a  
>>> id(a), id(b)  
(140595444686784, 140595444726400)  

4
Неправда в Python 3.6.5. id (a) та id (b) ідентичні. Результати нічим не відрізняються, навіть коли я використовував сучасну версію формату, а саме:b = '{:s}'.format(a)
Seshadri R

7

Я тільки розпочинаю деякі маніпуляції зі рядками і знайшов це питання. Я, мабуть, намагався зробити щось на зразок ОП, "звичайний я". Попередні відповіді не прояснили моєї плутанини, але трохи подумавши, я нарешті "зрозумів".

До тих пір , як a, b, c, dі eмають таке ж значення, вони посилаються на те ж місце. Пам'ять збережена. Як тільки змінна починає мати різні значення, вони починають мати різні посилання. Мій досвід навчання походить із цього коду:

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

Друкована продукція:

[4538504992, 4538504992, 4538504992, 4538504992, 4538504992]

hello hello hello hello hello

[6113502048, 4538504992, 4538504992, 4538504992, 5570935808]

goodbye hello hello hello hello something

Детальніше для дій розглядаються у цій записи stackoverflow.com/questions/2123925 / ...
dlasalle

3

Копіювання рядка можна виконати двома способами, або скопіювати розташування a = "a" b = a, або ви можете клонувати, що означає, що b не буде зачіпатись при зміні a, що робиться a = 'a' b = a [:]


2

Іншими словами, "id ()" - це не те, що вас турбує. Ви хочете знати, чи можна змінити ім’я змінної, не завдаючи шкоди імені змінної джерела.

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

Якщо ви звикли до C, це схожі на змінні покажчика, за винятком того, що ви не можете зняти посилання на них, щоб змінити те, на що вони вказують, але id () покаже вам, куди вони вказують в даний момент.

Проблема для програмістів на python виникає, коли ви розглядаєте більш глибокі структури, такі як списки або дикти:

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

Тут o та x посилаються на один і той же dict o ['a'] та x ['a'], і цей дикт є "змінним" у тому сенсі, що ви можете змінити значення ключа "a". Ось чому "y" має бути копією, а y ['a'] може посилатися на щось інше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.