【Python】append関数を使うと値が上書きされる原因と対処法

Pythonでリストに要素を追加する際によく使われるappend関数ですが、時々値が上書きされるという問題に遭遇することがあります。

この記事では、その原因と対処法を解説します。

目次から探す

値が上書きされる原因

Pythonでappend関数を使ってリストに要素を追加する際、値が上書きされる原因は主に以下の2つです。

参照渡しによる上書き

参照渡しとは

Pythonでは、リストや辞書などのオブジェクトは参照渡しで扱われます。

これは、オブジェクトの実体ではなく、オブジェクトへの参照(アドレス)が渡されることを意味します。

そのため、関数にリストを渡したり、リストを別のリストに代入すると、元のリストと新しいリストが同じオブジェクトを参照することになります。

参照渡しによる上書きの例

以下のコードは、参照渡しによって値が上書きされる例です。


def add_element(list1, element):
    list1.append(element)

list_a = [1, 2, 3]
list_b = list_a
add_element(list_a, 4)
print(list_a)  # [1, 2, 3, 4]
print(list_b)  # [1, 2, 3, 4]

list_alist_bは同じオブジェクトを参照しているため、list_aに要素を追加すると、list_bの内容も変更されます。

ループ内でのappend関数の使用

ループ内での上書きの例

ループ内でappend関数を使用する際にも、値が上書きされることがあります。

以下のコードは、ループ内でリストに要素を追加する例です。


list1 = [1, 2, 3]
list2 = []
for i in list1:
    list2.append(i)
print(list2)  # [1, 2, 3]

この例では、list1の要素が正しくlist2に追加されています。

しかし、リストのリストを扱う場合には、参照渡しの影響で値が上書きされることがあります。

ループ内での参照渡しの影響

以下のコードは、ループ内でリストのリストに要素を追加する例です。


list1 = [[0] * 3] * 3
list1[0][0] = 1
print(list1)  # [[1, 0, 0], [1, 0, 0], [1, 0, 0]]

この例では、list1の最初の要素だけを変更しようとしていますが、他の要素も変更されてしまいます。

これは、[[0] * 3] * 3の部分で、同じリストオブジェクトへの参照が3回繰り返されるためです。

この問題を解決するには、リスト内包表記を使ってリストを生成することができます。


list1 = [[0] * 3 for _ in range(3)]
list1[0][0] = 1
print(list1)  # [[1, 0, 0], [0, 0, 0], [0, 0, 0]]

このように、参照渡しによる上書きを避けるためには、リストの生成方法やappend関数の使用方法に注意が必要です。

対処法

値が上書きされる問題を解決するためには、以下の3つの対処法があります。

値渡しを利用する

値渡しとは

値渡しは、変数の値を直接渡す方法です。

これにより、参照先のオブジェクトが変更されても、元の変数の値は影響を受けません。

値渡しを使った対処法の例


original_list = [1, 2, 3]
new_list = []
for item in original_list:
    new_list.append(item)
    new_list[0] = 99
print(original_list)  # [1, 2, 3]
print(new_list)  # [99, 2, 3]

この例では、original_listの各要素をnew_listに追加しています。

new_listの要素を変更しても、original_listには影響がありません。

リスト内包表記を使う

リスト内包表記の概要

リスト内包表記は、リストを簡潔に生成するためのPythonの機能です。

リスト内包表記を使うことで、ループ内でのappend関数の使用を避けることができます。

リスト内包表記を使った対処法の例


original_list = [1, 2, 3]
new_list = [item for item in original_list]
new_list[0] = 99
print(original_list)  # [1, 2, 3]
print(new_list)  # [99, 2, 3]

この例では、リスト内包表記を使ってoriginal_listの要素をnew_listにコピーしています。

new_listの要素を変更しても、original_listには影響がありません。

deepcopyを利用する

deepcopyの概要

deepcopyは、Pythonのcopyモジュールにある関数で、オブジェクトの完全なコピーを作成します。

これにより、ネストされたリストや辞書などの複雑なデータ構造も正確にコピーすることができます。

deepcopyを使った対処法の例


from copy import deepcopy
original_list = [[1, 2], [3, 4]]
new_list = deepcopy(original_list)
new_list[0][0] = 99
print(original_list)  # [[1, 2], [3, 4]]
print(new_list)  # [[99, 2], [3, 4]]

この例では、deepcopyを使ってoriginal_listの完全なコピーをnew_listに作成しています。

new_listの要素を変更しても、original_listには影響がありません。

目次から探す