webdevqa.jp.net

リストを複製またはコピーする方法

Pythonでリストを複製またはコピーするためのオプションは何ですか?

new_list = my_listを使用している間、new_listへのいかなる変更も毎回my_listを変更します。どうしてこれなの?

2084
aF.

new_list = my_listでは、実際には2つのリストがありません。代入は実際のリストではなく、リストへの参照をコピーするだけなので、new_listmy_listは両方とも代入後に同じリストを参照します。

リストを実際にコピーするには、さまざまな方法があります。

  • 組み込みの list.copy() メソッド(Python 3.3以降で利用可能)を使用することができます。

    new_list = old_list.copy()
    
  • あなたはそれをスライスすることができます:

    new_list = old_list[:]
    

    Alex Martelliの 意見(少なくともこれについての 2007年に戻って )は、そのこれは奇妙な構文であり、これを使用するのは意味がありません。;)(彼の意見は、次のものはより読みやすいです)。

  • 組み込みの list() function)を使うことができます。

    new_list = list(old_list)
    
  • 一般的な copy.copy() :を使うことができます。

    import copy
    new_list = copy.copy(old_list)
    

    最初にold_listのデータ型を見つけなければならないので、これはlist()より少し遅いです。

  • リストにオブジェクトが含まれていて、それらもコピーしたい場合は、generic copy.deepcopy() :を使用してください。

    import copy
    new_list = copy.deepcopy(old_list)
    

    明らかに最も遅くて最もメモリを必要とする方法ですが、避けられないこともあります。

例:

import copy

class Foo(object):
    def __init__(self, val):
         self.val = val

    def __repr__(self):
        return str(self.val)

foo = Foo(1)

a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)

# edit orignal list and instance 
a.append('baz')
foo.val = 5

print('original: %r\n list.copy(): %r\n slice: %r\n list(): %r\n copy: %r\n deepcopy: %r'
      % (a, b, c, d, e, f))

結果:

original: ['foo', 5, 'baz']
list.copy(): ['foo', 5]
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]
2795
Felix Kling

Felixはすでにすばらしい答えを提供してくれました、しかし私は私がいろいろな方法のスピード比較をすることになると思いました:

  1. 10.59秒(105.9us/itn) - copy.deepcopy(old_list)
  2. 10.16秒(101.6us/itn) - deepcopyでクラスをコピーする純粋なpythonのCopy()メソッド
  3. 1.488 sec(14.88us/itn) - 純粋なpythonのCopy()メソッドがクラスをコピーしない(辞書、リスト、タプルのみ)
  4. 0.325秒(3.25us/itn) - for item in old_list: new_list.append(item)
  5. 0.217秒(2.17us/itn) - [i for i in old_list](a リスト内包表記
  6. 0.186秒(1.86us/itn) - copy.copy(old_list)
  7. 0.075秒(0.75us/itn) - list(old_list)
  8. 0.053秒(0.53us/itn) - new_list = []; new_list.extend(old_list)
  9. 0.039秒(0.39us/itn) - old_list[:]リストスライス

最速はリストスライスです。 copy.copy()やpython版とは異なり、list(list)list[:]copy.deepcopy()はリスト内のリスト、辞書、クラスインスタンスをコピーしないので、オリジナルが変更された場合、コピーされたリスト内でも変更されます。

(誰かが興味を持っている、または何か問題を提起したい場合は、これがスクリプトです。)

from copy import deepcopy

class old_class:
    def __init__(self):
        self.blah = 'blah'

class new_class(object):
    def __init__(self):
        self.blah = 'blah'

dignore = {str: None, unicode: None, int: None, type(None): None}

def Copy(obj, use_deepcopy=True):
    t = type(obj)

    if t in (list, Tuple):
        if t == Tuple:
            # Convert to a list if a Tuple to 
            # allow assigning to when copying
            is_Tuple = True
            obj = list(obj)
        else: 
            # Otherwise just do a quick slice copy
            obj = obj[:]
            is_Tuple = False

        # Copy each item recursively
        for x in xrange(len(obj)):
            if type(obj[x]) in dignore:
                continue
            obj[x] = Copy(obj[x], use_deepcopy)

        if is_Tuple: 
            # Convert back into a Tuple again
            obj = Tuple(obj)

    Elif t == dict: 
        # Use the fast shallow dict copy() method and copy any 
        # values which aren't immutable (like lists, dicts etc)
        obj = obj.copy()
        for k in obj:
            if type(obj[k]) in dignore:
                continue
            obj[k] = Copy(obj[k], use_deepcopy)

    Elif t in dignore: 
        # Numeric or string/unicode? 
        # It's immutable, so ignore it!
        pass 

    Elif use_deepcopy: 
        obj = deepcopy(obj)
    return obj

if __== '__main__':
    import copy
    from time import time

    num_times = 100000
    L = [None, 'blah', 1, 543.4532, 
         ['foo'], ('bar',), {'blah': 'blah'},
         old_class(), new_class()]

    t = time()
    for i in xrange(num_times):
        Copy(L)
    print 'Custom Copy:', time()-t

    t = time()
    for i in xrange(num_times):
        Copy(L, use_deepcopy=False)
    print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t

    t = time()
    for i in xrange(num_times):
        copy.copy(L)
    print 'copy.copy:', time()-t

    t = time()
    for i in xrange(num_times):
        copy.deepcopy(L)
    print 'copy.deepcopy:', time()-t

    t = time()
    for i in xrange(num_times):
        L[:]
    print 'list slicing [:]:', time()-t

    t = time()
    for i in xrange(num_times):
        list(L)
    print 'list(L):', time()-t

    t = time()
    for i in xrange(num_times):
        [i for i in L]
    print 'list expression(L):', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(L)
    print 'list extend:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        for y in L:
            a.append(y)
    print 'list append:', time()-t

    t = time()
    for i in xrange(num_times):
        a = []
        a.extend(i for i in L)
    print 'generator expression extend:', time()-t
521
cryo

私は と言われました - Python 3.3+ list.copy() メソッドを追加しました。これはスライスと同じくらい速いはずです:

newlist = old_list.copy()

131

Pythonでリストを複製またはコピーするためのオプションは何ですか?

Python 3では、以下のようにして浅いコピーを作ることができます。

a_copy = a_list.copy()

Python 2と3では、あなたはオリジナルの完全なスライスで浅いコピーを得ることができます:

a_copy = a_list[:]

説明

リストをコピーする方法は2つあります。シャローコピーは同じオブジェクトの新しいリストを作成し、ディープコピーは新しい同等のオブジェクトを含む新しいリストを作成します。

浅いリストのコピー

シャローコピーは、リスト自体のみをコピーします。これは、リスト内のオブジェクトへの参照のコンテナです。自分自身に含まれているオブジェクトが変更可能で、一方が変更されている場合、その変更は両方のリストに反映されます。

Python 2と3でこれを行うにはさまざまな方法があります。Python2の方法はPython 3でも機能します。

Python 2

Python 2では、リストの浅いコピーを作成する慣用的な方法は、オリジナルの完全なスライスを使うことです。

a_copy = a_list[:]

リストをリストコンストラクタに渡すことによっても同じことができます。

a_copy = list(a_list)

しかし、コンストラクタを使用することは効率的ではありません。

>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844

Python 3

Python 3では、リストはlist.copyメソッドを取得します。

a_copy = a_list.copy()

Python 3.5の場合:

>>> import timeit
>>> l = list(range(20))
>>> min(timeit.repeat(lambda: l[:]))
0.38448613602668047
>>> min(timeit.repeat(lambda: list(l)))
0.6309100328944623
>>> min(timeit.repeat(lambda: l.copy()))
0.38122922903858125

別のポインタを作成するとnotがコピーされます

new_list = my_listを使用すると、my_listが変更されるたびにnew_listが変更されます。どうしてこれなの?

my_listは、メモリ内の実際のリストを指す単なる名前です。 new_list = my_listと言っても、コピーを作成しているのではない場合は、メモリ内の元のリストを指す別の名前を追加するだけです。リストのコピーを作成するときにも同様の問題が発生する可能性があります。

>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]

リストは単にコンテンツへのポインタの配列なので、浅いコピーは単にポインタをコピーするだけなので、2つの異なるリストがありますが、それらのコンテンツは同じです。内容のコピーを作成するには、あなたはディープコピーが必要です。

ディープコピー

リストの ディープコピーを作成するには、Python 2または3では、deepcopyモジュールでcopyを使用します

import copy
a_deep_copy = copy.deepcopy(a_list)

これにより、どのようにして新しいサブリストを作成できるかを説明します。

>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]

そして、私たちはディープコピーされたリストがオリジナルと全く異なるリストであることを見ます。あなたはあなた自身の機能をロールすることができます - しかし、しないでください。標準ライブラリのdeepcopy関数を使って、そうでなければ起こらないであろうバグを作成する可能性があります。

evalを使わない

これはディープコピーの方法として使われていると思うかもしれませんが、しないでください。

problematic_deep_copy = eval(repr(a_list))
  1. あなたが信頼していない情報源から何かを評価している場合は特に危険です。
  2. コピーしているサブ要素が、同等の要素を再現するために評価できる表現を持っていない場合、それは信頼できません。
  3. パフォーマンスも劣ります。

64ビットPython 2.7の場合:

>>> import timeit
>>> import copy
>>> l = range(10)
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
27.55826997756958
>>> min(timeit.repeat(lambda: eval(repr(l))))
29.04534101486206

64ビットPython 3.5の場合:

>>> import timeit
>>> import copy
>>> l = list(range(10))
>>> min(timeit.repeat(lambda: copy.deepcopy(l)))
16.84255409205798
>>> min(timeit.repeat(lambda: eval(repr(l))))
34.813894678023644
112
Aaron Hall

どのようにして適切なコピーを作成するかをあなたに教える多くの答えがすでにありますが、あなたのオリジナルの「コピー」がなぜ失敗したのかを言う人はいません。

Pythonは変数に値を格納しません。名前をオブジェクトにバインドします。元の割り当てでは、my_listで参照されるオブジェクトを受け取り、それをnew_listにもバインドしました。どの名前を使用しても、リストは1つだけなので、my_listとして参照しているときに行った変更は、new_listとして参照しているときにも維持されます。この質問に対する他の答えはそれぞれ、new_listにバインドするための新しいオブジェクトを作成するさまざまな方法を示します。

リストの各要素は名前のように機能し、各要素はオブジェクトに非排他的にバインドします。シャローコピーは、要素が以前と同じオブジェクトにバインドされた新しいリストを作成します。

new_list = list(my_list)  # or my_list[:], but I prefer this syntax
# is simply a shorter way of:
new_list = [element for element in my_list]

あなたのリストをさらに一歩コピーするには、あなたのリストが参照するそれぞれのオブジェクトをコピーし、それらの要素のコピーを新しいリストにバインドします。

import copy  
# each element must have __copy__ defined for this...
new_list = [copy.copy(element) for element in my_list]

リストがその要素に結び付けられているように、リストの各要素は他のオブジェクトを参照することがあるので、これはまだディープコピーではありません。リスト内のすべての要素を再帰的にコピーしてから、各要素によって参照されている他の各オブジェクトなどをコピーするには、以下の手順を実行します。

import copy
# each element must have __deepcopy__ defined for this...
new_list = copy.deepcopy(my_list)

コピーの際のコーナーケースについての詳細は ドキュメント を参照してください。

49
jack

thing[:]を使う

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 
31
Paul Tarjan

これを行うためのPythonの慣用句はnewList = oldList[:]です。

30
erisco

他のすべての貢献者が great answerを与えました。これは単一次元(レベル付き)のリストがある場合に機能しますが、これまで述べた方法のうち、copy.deepcopy()だけがリストの複製/コピーに機能し、意味がありません。多次元のネストされたリスト(リストのリスト)を扱うときは、ネストされたlistオブジェクトにアクセスします。 Felix Kling が彼の答えでそれを参照している間、問題へのもう少しそしておそらくdeepcopyへのより速い代替を証明するかもしれないビルトインを使用する回避策があります。

new_list = old_list[:]copy.copy(old_list)'、Py3k old_list.copy()は単一レベルリストでも機能しますが、old_listnew_list内にネストされたlistオブジェクトを指すことに戻り、一方のlistオブジェクトへの変更は他方で永続化されます。

編集:新たな情報が明るみに出た

Aaron Hall および PM 2Ring の両方で指摘されているように、eval()を使用することは悪い考えであるだけでなく、copy.deepcopy()よりもはるかに遅くなります。

つまり、多次元リストの場合、唯一のオプションはcopy.deepcopy()です。そうは言っても、中程度のサイズの多次元配列で使用しようとするとパフォーマンスが低下するため、実際にはオプションではありません。私は42x42の配列を使ってtimeitを試みましたが、バイオインフォマティクスのアプリケーションではこれまでにないほどの大きさ、あるいはそれ以上の大きさでさえありませんでした。

その場合、唯一の現実的な選択肢は、複数のリストを初期化してそれらを個別に処理することです。多次元リストのコピーを処理する方法について他に何か提案があれば、それをいただければ幸いです。

他の人が述べているように、重要ですcopyモジュールとcopy.deepcopy多次元リストの場合を使ったパフォーマンスの問題があります。

18
AMR

始めから始めて、少し深めに探そう。

2つのリストがあるとします。

list_1=['01','98']
list_2=[['01','98']]

そして、最初のリストから始めて、両方のリストをコピーする必要があります。

まずは一般的なコピー方法で試してみましょう。

copy=list_1

あなたがコピーしたlist_1をコピーしたと思っているのであれば、あなたは間違っているかもしれません、それをチェックしましょう:

The id() function shows us that both variables point to the same list object, i.e. they share this object.
print(id(copy))
print(id(list_1))

出力:

4329485320
4329485320

びっくり? Ok調べてみましょう。

Pythonは変数には何も格納しませんので、変数はオブジェクトを参照しているだけで、オブジェクトはその値を格納します。ここでobjectはlistですが、同じオブジェクトへの2つの参照を2つの異なる変数名で作成しました。したがって、両方の変数は同じオブジェクトを指しています。

それであなたがcopy=list_1をするとき、実際にそれがしていること:

enter image description here

これは、list_1とcopyの2つの変数名ですが、両方の変数のオブジェクトはlistです。

そのため、コピーしたリストを修正しようとすると、元のリストも修正されます。リストはそこに1つしかないため、コピーしたリストや元のリストから変更しても、そのリストは修正されます。

copy[0]="modify"

print(copy)
print(list_1)

出力:

['modify', '98']
['modify', '98']

それで、それはオリジナルのリストを修正しました:

それでは解決策は何ですか?

解決策:

それでは、リストをコピーする2番目のPythonicの方法に移りましょう。

copy_1=list_1[:]

今度はこの方法で最初の問題で直面していたことを修正してみましょう。

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

私たちの両方のリストが異なるidを持っているのを見ることができるように、そしてそれは両方の変数が異なるオブジェクトを指していることを意味するのでここで実際に起こっていることは以下の通りです:

enter image description here

それでは、リストを修正して、以前の問題に直面しているかどうかを確認しましょう。

copy_1[0]="modify"

print(list_1)
print(copy_1)

出力:

['01', '98']
['modify', '98']

元のリストを変更していないことがわかるように、コピーしたリストを変更しただけなので、問題ありません。

だから今私たちは終わったと思う? 2番目の入れ子リストもコピーする必要があるので、Pythonicの方法で試してみましょう。

copy_2=list_2[:]

それでlist_2はlist_2のコピーである別のオブジェクトを参照するはずです:

print(id((list_2)),id(copy_2))

出力が得られます。

4330403592 4330403528

今、私たちは両方のリストが異なるオブジェクトを指していると仮定することができるので、それではそれを修正しようとしましょうそしてそれが我々が欲しいものを与えているのを見ましょう:

だから私たちがしようとすると:

copy_2[0][1]="modify"

print(list_2,copy_2)

それは私達に出力を与える:

[['01', 'modify']] [['01', 'modify']]

さて、これは私たちがPythonicの方法を使ったことを少し混乱させています、それでも、私たちは同じ問題に直面しています。

理解しましょう。

だから私たちがするとき:

copy_2=list_2[:]

ネストしたリストではなく、実際には外側のリストだけをコピーしているので、ネストしたリストは両方のリストに対して同じオブジェクトです。

print(id(copy_2[0]))
print(id(list_2[0]))

出力:

4329485832
4329485832

実際にcopy_2=list_2[:]を実行すると、これが起こります。

enter image description here

これはリストのコピーを作成し、ネストリストのコピーは作成せず、外部リストのコピーのみを作成します。ネストリストは両方の変数で同じです。ネストしたリスト.

それでは解決策は何ですか?

解決策はdeep copyです

from copy import deepcopy
deep=deepcopy(list_2)

それでは今それを確認しましょう:

print(id((list_2)),id(deep))

出力:

4322146056 4322148040

両方のIDが異なるので、ネストされたリストIDを確認しましょう。

print(id(deep[0]))
print(id(list_2[0]))

出力:

4322145992
4322145800

ご覧のとおり、両方のidが異なっているので、両方のネストされたリストは現在異なるオブジェクトを指していると想定できます。

deep=deepcopy(list_2)を実行すると、実際にはどうなりますか。

enter image description here

そのため、両方の入れ子リストは異なるオブジェクトを指しており、現在は別々の入れ子リストのコピーがあります。

それでは、ネストしたリストを修正して、前の問題が解決したかどうかを確認しましょう。

そうすれば:

deep[0][1]="modify"
print(list_2,deep)

出力:

[['01', '98']] [['01', 'modify']]

そのため、元のネストされたリストは変更されていないことがわかりますが、コピーされたリストだけが変更されています。

あなたが私の詳細な答えが好きなら、それを支持して私に知らせてください。あなたがこの答えに疑問を抱いているのであれば、コメントアウトしてください:)

18
Aaditya Ura

Python 3.6のタイミング

これはPython 3.6.8を使ったタイミング結果です。これらの時間は絶対的なものではなく、相対的なものです。

私は浅いコピーだけをすることに固執し、そしてまたlist.copy()(Python3 スライス相当 )と リストアンパッキングの2つの形式*new_list, = listnew_list = [*list])のようなPython2では不可能な新しい方法を加えました。 :

METHOD                  TIME TAKEN
b = [*a]                2.75180600000021
b = a * 1               3.50215399999990
b = a[:]                3.78278899999986  # Python2 winner (see above)
b = a.copy()            4.20556500000020  # Python3 "slice equivalent" (see above)
b = []; b.extend(a)     4.68069800000012
b = a[0:len(a)]         6.84498999999959
*b, = a                 7.54031799999984
b = list(a)             7.75815899999997
b = [i for i in a]      18.4886440000000
b = copy.copy(a)        18.8254879999999
b = []
for item in a:
  b.append(item)        35.4729199999997

私たちはPython2の勝者がまだうまくいっているのを見ることができますが、特に後者の優れた読みやすさを考慮すると、Python3のlist.copy()を大いに見逃すことはありません。

ダークホースは解凍と再解凍の方法(b = [*a])で、生のスライスより約25%速く、他の解凍方法(*b, = a)より2倍以上速いです。

b = a * 1も驚くほどうまくいっています。

これらのメソッドはリスト以外の入力に対して同等の結果をnot出力しません。 これらはすべてスライス可能なオブジェクトに対して動作し、いくつかは反復可能オブジェクトに対して動作しますが、より一般的なPythonオブジェクトに対してはcopy.copy()のみが動作します。


これは利害関係者のためのテストコードです( ここからのテンプレート ):

import timeit

COUNT = 50000000
print("Array duplicating. Tests run", COUNT, "times")
setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'

print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
print("b = copy.copy(a)\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
print("b = a[0:len(a)]\t\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t\t\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
print("b = []; for item in a: b.append(item)\t", timeit.timeit(stmt='b = []\nfor item in a:  b.append(item)', setup=setup, number=COUNT))
print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))
print("b = [*a]\t\t", timeit.timeit(stmt='b = [*a]', setup=setup, number=COUNT))
print("b = a * 1\t\t", timeit.timeit(stmt='b = a * 1', setup=setup, number=COUNT))
17
River

これがまだ言及されていないことに驚きました。完全を期すために...

あなたは "splat operator":*でリストの展開を実行することができます。これはあなたのリストの要素もコピーします。

old_list = [1, 2, 3]

new_list = [*old_list]

new_list.append(4)
old_list == [1, 2, 3]
new_list == [1, 2, 3, 4]

この方法の明らかな欠点は、Python 3.5以降でしか利用できないことです。

しかしタイミングに関しては、これは他の一般的な方法よりもパフォーマンスが良いようです。

x = [random.random() for _ in range(1000)]

%timeit a = list(x)
%timeit a = x.copy()
%timeit a = x[:]

%timeit a = [*x]

#: 2.47 µs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.47 µs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
#: 2.39 µs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

#: 2.22 µs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
10
SCB

もしあなたがあなた自身のカスタムクラスを定義していて、そしてあなたが属性を保ちたいなら、あなたは代わりに代わりにcopy.copy()またはcopy.deepcopy()を使うべきである場合があることに注意してください、例えばPython 3:

import copy

class MyList(list):
    pass

lst = MyList([1,2,3])

lst.name = 'custom list'

d = {
'original': lst,
'slicecopy' : lst[:],
'lstcopy' : lst.copy(),
'copycopy': copy.copy(lst),
'deepcopy': copy.deepcopy(lst)
}


for k,v in d.items():
    print('lst: {}'.format(k), end=', ')
    try:
        name = v.name
    except AttributeError:
        name = 'NA'
    print('name: {}'.format(name))

出力:

lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
5
Chris_Rands

Pythonのバージョンから独立した非常に単純なアプローチは、あなたがほとんどの場合に使用できる(少なくとも私はしている)すでに与えられた答えにはありませんでした。

new_list = my_list * 1       #Solution 1 when you are not using nested lists

ただし、my_listに他のコンテナ(ネストしたリストなど)が含まれている場合は、コピーライブラリから上記の回答で提案されているようにdeepcopyを使用する必要があります。例えば:

import copy
new_list = copy.deepcopy(my_list)   #Solution 2 when you are using nested lists

.ボーナス :要素をコピーしたくない場合は(シャローコピーともいう):

new_list = my_list[:]

解決策1と解決策2の違いを理解しましょう

>>> a = range(5)
>>> b = a*1
>>> a,b
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
>>> a[2] = 55 
>>> a,b
([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])

ご覧のとおり、ネストされたリストを使用していないときは解決策1は完璧に機能していました。解決策1を入れ子リストに適用するとどうなるかを確認しましょう。

>>> from copy import deepcopy
>>> a = [range(i,i+4) for i in range(3)]
>>> a
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> b = a*1
>>> c = deepcopy(a)
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
>>> a[2].append('99')
>>> for i in (a, b, c): print i   
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]   #Solution#1 didn't work in nested list
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]       #Solution #2 - DeepCopy worked in nested list
5
jainashish
new_list = my_list[:]

new_list = my_listこれを理解してみてください。 my_listがXのヒープメモリにあるとしましょう。つまり、my_listはXを指しています。今度はnew_list = my_listを割り当てることによって、new_listにXを指してもらうことになります。これはシャローコピーとして知られています。

new_list = my_list[:]を代入すると、my_listの各オブジェクトをnew_listにコピーするだけになります。これはディープコピーとして知られています。

あなたがこれを行うことができる他の方法は、次のとおりです。

  • new_list = list(old_list)
  • import copy new_list = copy.deepcopy(old_list)
3
Ravi Shankar

あなたが変数に値を定義し、あなたが別の変数にその変数を再割り当てした場合、Pythonでは、

2番目の変数はコピーされた値ではなく参照のみを持ちます。

>>> l = [1,2,3]
>>> k = l
>>> l[0] = 10
>>> l
[10, 2, 3]
>>> k
[10, 2, 3]

そのため、l&kで何かを変更した場合、両方に反映されます。

あなたが代入をしたならば、元の文句を使わないように[::]を使ってコピーしてください。

>>> k = l[::]
>>> k
[10, 2, 3]
>>> l[0] = 100
>>> l
[100, 2, 3]
>>> k
[10, 2, 3]
0