sec02 - tupleのコピー
スポンサーリンク

Pythonのtupleをコピーする方法と注意点

tupleは内部データを変更できないため、次のコードのように同じデータを参照したとしても、listのコピーで発生するような問題は基本的に起きません。

num_tuple1 = (1, 2, 3)
num_tuple2 = num_tuple1
print(num_tuple1, type(num_tuple1), id(num_tuple1))  # (1, 2, 3) <class 'tuple'> 2324937423040
print(num_tuple2, type(num_tuple2), id(num_tuple2))  # (1, 2, 3) <class 'tuple'> 2324937423040

上記の理由から、tupleの全範囲スライス([:])でコピーをした場合、Pythonは新しいtupleを生成せずに、元のタプルを参照する動作をします。(tupleにはcopy()メソッドも存在しません。)

num_tuple1 = (1, 2, 3)
num_tuple2 = num_tuple1[:]
print(num_tuple1, type(num_tuple1), id(num_tuple1))  # (1, 2, 3) <class 'tuple'> 2413960870208
print(num_tuple2, type(num_tuple2), id(num_tuple2))  # (1, 2, 3) <class 'tuple'> 2413960870208

tupleのコピーで問題が発生するケース(可変オブジェクトを含む場合)

これまで説明してきたように、tupleの要素が数値や文字列の場合には、tupleの『不変』の性質により問題は起こりません。しかし、tupleにlistのような変更可能なオブジェクトが含まれる場合、問題が発生する可能性があります。

num_tuple1 = ([1, 2, 3],)
num_tuple2 = num_tuple1[:]
num_tuple2[0][0] = 99

print(num_tuple1, type(num_tuple1), id(num_tuple1))  # ([99, 2, 3],) <class 'tuple'> 2173609641440
print(num_tuple2, type(num_tuple2), id(num_tuple2))  # ([99, 2, 3],) <class 'tuple'> 2173609641440
print(num_tuple1[0], type(num_tuple1[0]), id(num_tuple1[0]))  # [99, 2, 3] <class 'list'> 1822000033408
print(num_tuple2[0], type(num_tuple2[0]), id(num_tuple2[0]))  # [99, 2, 3] <class 'list'> 1822000033408

上記コードは、tupleの最初の要素であるlist([1, 2, 3])の最初の要素を変更した例です。変数"num_tuple1", "num_tuple2"の双方とも同じデータを参照しているので、listの要素が変更されると、printの出力結果は同じように変更されることになります。

スポンサーリンク

copy.deepcopy()による安全なtupleのコピー

listオブジェクトに対する変更にも対応するには、copy.deepcopy()関数を使用します。copy.deepcopy()は、tupleも含めて全てのデータを複製します。

import copy
num_tuple1 = ([1, 2, 3],)
num_tuple2 = copy.deepcopy(num_tuple1)
num_tuple2[0][0] = 99

print(num_tuple1, type(num_tuple1), id(num_tuple1))  # ([1, 2, 3],) <class 'tuple'> 2289153017312
print(num_tuple2, type(num_tuple2), id(num_tuple2))  # ([99, 2, 3],) <class 'tuple'> 2289153017600
print(num_tuple1[0], type(num_tuple1[0]), id(num_tuple1[0]))  # [1, 2, 3] <class 'list'> 2289153063296
print(num_tuple2[0], type(num_tuple2[0]), id(num_tuple2[0]))  # [99, 2, 3] <class 'list'> 2289152960704

上記コードの実行結果を確認すると、全てのオブジェクトのid番号が違っており、listへの変更が元のデータに影響を与えていないことを確認できます。

スポンサーリンク