Pythonでクラスのインスタンスをリストに格納し、後で削除する際、「同じインスタンスを複数回追加する場合」と「毎回異なるインスタンスを作成する場合」 では削除時の挙動が変わります。
この違いを理解していないと、意図せずすべてのオブジェクトが削除されてしまう ことがあります。
本記事では、具体的なコードを使ってこの違いを解説します。
同じインスタンスを追加すると削除時にすべて消える
まず、次のコードを考えてみましょう。
ここでは、Person
クラスのオブジェクト p1
をリストに3回追加しています。
class Person:
def __init__(self, name):
self.name = name
p1 = Person("Alice")
people = []
for _ in range(3):
people.append(p1) # 🔴 同じ `Person` インスタンスを3回追加
print(len(people)) # 出力: 3
# 1つだけ削除したい
people = [p for p in people if p != p1]
print(len(people)) # 出力: 0 (すべて削除されてしまう!)
なぜすべて削除されるのか?
-
p1
は 同じオブジェクト なので、リストに追加された3つの要素はすべて 同じメモリアドレスを指している。 -
!= p1
の条件でリストをフィルタリングすると、すべてのp1
が一致するため、すべて削除される。
異なるインスタンスを作成すると1つずつ削除される
次に、Person("Alice")
を毎回新しく作成してリストに追加する場合の動作を見てみましょう。
class Person:
def __init__(self, name):
self.name = name
people = []
for _ in range(3):
people.append(Person("Alice")) # ✅ 毎回新しいインスタンスを作成
print(len(people)) # 出力: 3
p_to_remove = people[0] # 1つだけ削除したい
people = [p for p in people if p != p_to_remove]
print(len(people)) # 出力: 2 (正しく1つだけ削除された!)
なぜ意図した動作になるのか?
-
Person("Alice")
を毎回新しく作成するので、リストの各要素は 異なるオブジェクト(異なるメモリアドレス)。 -
!= p_to_remove
の条件でリストをフィルタリングすると、最初に一致した1つだけが削除され、他のインスタンスは残る。
del
を使ったより明確な削除方法
リスト内包表記で !=
を使う方法ではなく、del
を使うと、リストの最初に見つかった1つだけを削除 できます。
for i, person in enumerate(people):
if person.name == "Alice":
del people[i] # 最初の1つだけ削除
break
print(len(people)) # 出力: 2
del
のメリット
- 最初に見つかった1つだけ削除できる ので、意図しない削除を防げる。
- リストのサイズが大きい場合も効率的。
まとめ
インスタンスの追加方法 | 削除時の動作 |
---|---|
同じインスタンスを複数回追加 (append(p1) ) |
!= の比較で すべて削除 される ⚠️ |
毎回新しいインスタンスを作成 (append(Person("Alice")) ) |
!= の比較で 最初に一致したものだけ削除 ✅ |
del を使う方法 |
最初に見つかった1つだけ削除できる ✅ |