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
Martijinの回答とは異なる回答を得るには(完全に正しいですが、必ずしも述べられているように質問に回答するとは限りません)、コピーする理由を示すために、より詳細な/ユースケースを提供することをお勧めします。
elmo 2014

4
@elemoが示すように、これはXY問題である可能性があります。
martineau 2014

2
の形式のネストされた辞書のメモリ使用量を見積もることに興味がd[ 'hello' ] = eありましたe[ 'hi' ] = 'again'。ここで、。このようなネストされた辞書を生成するために、1つのe辞書を生成し、それを複数回コピーしました。メモリ消費量が非常に少ないことに気づいたので、ここで質問しました。文字列のコピーが作成されなかったため、メモリ消費量が少ないことがわかりました。
いつもの私

1
あなたがしたい場合bの修正版であることをa修正することなくa、単に聞かせてb何でも演算の結果です。例:にb = a[2:-1]設定b'll'a'のままにしhello'ます。
OJFord 2014

Ollieは正しいです。これは、strが不変型であるためです。Pythonではシングルトン(およびおそらく他の内部最適化)を使用しているため、eディクショナリをコピーするときに期待するようにメモリが拡張されることはありません。
fizxMike 2016

回答:


137

Python文字列をコピーする必要ありません。それらは不変であり、copyモジュールは、そのような場合、str()文字列スライス全体を返し、空の文字列と連結して、常に元の文字列を返します。

さらに、'hello'文字列はインターンされます(特定の文字列はインターンされます)。Pythonは、辞書の検索を高速化するため、意図的に1つのコピーだけを保持しようとします。

これを回避する1つの方法は、実際に新しい文字列を作成し、その文字列をスライスして元のコンテンツに戻すことです。

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

@martineau:確かに、私は本当に「一方通行」と言うつもりでした。
MartijnPieters

10
「Python文字列をコピーする必要はありません」に重点を置いています。これらの操作が単に同じ文字列を返すのには理由があります。
tcooc 2014

1
ただし、この場合、OPはメモリを浪費しようとしています。彼は特定の量の文字列によってどれだけのメモリが使用されるかを知りたいので、それが実際の目標です。明らかに、彼は一意の文字列を生成できましたが、それは回避策としての不要な作業です。
Gabe 2014

8
42を出力する例を使用して、「カジュアルに」+1します。
バクリウ2014

11

文字列のフォーマットを介してPythonで文字列をコピーできます:

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

4
Python3.6.5では当てはまりません。id(a)とid(b)は同じです。最新バージョンのフォーマットを使用した場合でも、結果に違いはありません。つまり、b = '{:s}'.format(a)
Seshadri R 2018

7

文字列の操作を始めたばかりで、この質問が見つかりました。私はおそらくOPのような何かをしようとしていました、「いつもの私」。以前の答えは私の混乱を解消しませんでしたが、それについて少し考えた後、私はついに「それを手に入れました」。

限りabcd、と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をコピーするか、クローンを作成するかの2つの方法で実行できます。つまり、a = 'a' b = a [:]によって行われるaが変更されてもbは影響を受けません。


2

別の言い方をすれば、「id()」はあなたが気にすることではありません。ソース変数名を損なうことなく変数名を変更できるかどうかを知りたい。

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

Cに慣れている場合、これらはポインタ変数に似ていますが、参照を解除してポイントするものを変更することはできませんが、id()は現在ポイントしている場所を示します。

Pythonプログラマーにとっての問題は、リストやdictなどのより深い構造を検討するときに発生します。

>>> 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']を参照し、そのdictは、キー 'a'の値を変更できるという意味で「可変」です。そのため、「y」はコピーである必要があり、y ['a']は他の何かを参照できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.