python3 リストのコピー

ミュータブルな型であるリスト型の変数を代入した時に参照が渡されてしまう様子を示します。また、リストの参照ではなく、値を変数に渡す方法を紹介します。

リストを代入すると参照が渡される

リストはミュータブルなので、変数bにリスト型変数aを代入すると参照が渡されます。そのため、bの内容を変更するとaの内容も同様に変更されてしまいます。

a = [1, 2, 3, 4, 5]
b = a
print(id(a), a)
print(id(b), b)
"""
下記、出力です。bはaの参照が渡されているので、aとbのidは同じです。
140525489086656 [1, 2, 3, 4, 5]
140525489086656 [1, 2, 3, 4, 5]
"""

a.append(6)
b.append(7)
print(id(a), a)
print(id(b), b)
"""
下記、出力です。listはミュータブルなので、新しいオブジェクトが作成されることなく、リストの内容が変更されます。
140525489086656 [1, 2, 3, 4, 5, 6, 7]
140525489086656 [1, 2, 3, 4, 5, 6, 7]
"""

リストのコピーを渡す方法

リストのコピーを渡す方法は下記があります。下記を用いることで、リストのコピーを別の変数に渡すことが出来ます。下記方法は、浅いコピーと呼ばれるものです。
浅いコピーについては、Shallow vs Deep Copying of Python Objects – Real Pythonが参考になります。

  • 方法1:リストのcopy()関数
  • 方法2:list()変換関数
  • 方法3:リストスライス[:]
a = ["a", "x", ["y", "z"]]

#方法1:リストのcopy()関数
b = a.copy()

#方法2:list()変換関数
c = list(a)

#方法3:リストスライス[:]
d = a[:]

print(a, b, c, d)
print(id(a), id(b), id(c), id(d))
'''
出力は下記です。
a, b, c, dのidがそれぞれ異なり別のオブジェクトであることがわかります。
['a', 'x', ['y', 'z']] ['a', 'x', ['y', 'z']] ['a', 'x', ['y', 'z']] ['a', 'x', ['y', 'z']]
140253893164864 140253893177664 140253893228992 140253893164800
'''

b.append(["bb", "bbb"])
c.append(["cc", "ccc"])
d.append(["dd", "ddd"])

print(a, b, c, d)
print(id(a), id(b), id(c), id(d))
'''
出力は下記です。
浅いコピーは、コピー前のリスト(a)に存在するネストされたリスト(リストの中のリスト)は参照を渡しますが、
それ以外は値を渡します。
b, c, dの内容を変更していますが、ネストされたリストの変更をしていないので、bの変更はbにしか反映されていません。
c,dも同様であり、他のオブジェクトに影響を与えていないことがわかります。
['a', 'x', ['y', 'z']] ['a', 'x', ['y', 'z'], ['bb', 'bbb']] ['a', 'x', ['y', 'z'], ['cc', 'ccc']] ['a', 'x', ['y', 'z'], ['dd', 'ddd']]
140253893164864 140253893177664 140253893228992 140253893164800
'''
a[0] = "a0"
b[1] = "b1"
c[1] = "c1"
d[3][0] = "d30"
a[2][1] = "a21"
print(a)
print(b)
print(c)
print(d)
""" 
出力は下記です。
コピー前のリスト(a)に存在するネストされたリストa[2][1]を変更すると他のリストb, c, dにも変更が反映されます。
しかし、aに存在していなかったネストされたリストd[3][0]を変更しても他のリストに影響はありません。
['a0', 'x', ['y', 'a21']]
['a', 'b1', ['y', 'a21'], ['bb', 'bbb']]
['a', 'c1', ['y', 'a21'], ['cc', 'ccc']]
['a', 'x', ['y', 'a21'], ['d30', 'ddd']]
 """

#参考にidを表示します。
print("id a :", id(a), id(a[0]), id(a[1]), id(a[2]), id(a[2][0]),id(a[2][1]))
print("id b :", id(b), id(b[0]), id(b[1]), id(b[2]), id(b[2][0]),id(b[2][1]),id(b[3]))
print("id c :", id(c), id(c[0]), id(c[1]), id(c[2]), id(c[2][0]),id(c[2][1]),id(c[3]))
print("id d :", id(d), id(d[0]), id(d[1]), id(d[2]), id(d[2][0]),id(d[2][1]),id(d[3])) 
"""
id a : 140038425018048 140038425081584 140038426857136 140038425942336 140038425081200 140038425081840
id b : 140038425034944 140038426178992 140038425081648 140038425942336 140038425081200 140038425081840 140038425082176
id c : 140038425082240 140038426178992 140038425081712 140038425942336 140038425081200 140038425081840 140038425082368
id d : 140038425017984 140038426178992 140038426857136 140038425942336 140038425081200 140038425081840 140038425082496
"""

【補足】

方法1:リストのcopy()関数
浅いコピーをします。

方法2:list()変換関数
list([iterable])の形で使用します。list(list型変数)とした場合は、iterable[:]と同様にリストのコピーが作られて返されます。詳しくは下記参照。
組み込み型 — Python 3.9.2 ドキュメント

方法3:リストスライス[:]
[:]は先頭から末尾までのシーケンス全体のコピーが渡されます。b=a[:]としても、aそのものに変化はありません。

コメント

タイトルとURLをコピーしました