1. ホーム
  2. python

[解決済み] 割り当て後にリストが予期せず変更されました。その理由と防止策を教えてください。

2022-03-15 21:31:30

質問

を使いながら new_list = my_list を変更した場合、その変更は new_list 変更 my_list を毎回使用します。これはなぜですか?また、これを防ぐにはリストをクローンまたはコピーすればよいのですか?

解決方法は?

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

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

  • 内蔵の list.copy() メソッド (Python 3.3 以降で利用可能) を使用します。

    new_list = old_list.copy()
    
    
  • スライスすることができます。

    new_list = old_list[:]
    
    

    アレックス・マルテッリ氏の の意見(少なくとも 2007年当時 ということです。 は奇妙な構文であり、これを使用することは意味がありません。 . ;) (彼の意見では、次のものの方が読みやすいそうです)。

  • 内蔵の list() 関数を使用します。

    new_list = list(old_list)
    
    
  • を使用することができます。 copy.copy() :

    import copy
    new_list = copy.copy(old_list)
    
    

    よりも少し遅いです。 list() のデータ型を調べなければならないからです。 old_list を先に指定します。

  • リストにオブジェクトが含まれていて、それらもコピーしたい場合は、汎用的な 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 'Foo({!r})'.format(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\nlist.copy(): %r\nslice: %r\nlist(): %r\ncopy: %r\ndeepcopy: %r'
      % (a, b, c, d, e, f))

結果

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