Python

【Python】クラスの全てのインスタンスをリストで扱う

この記事では、特定のクラスの全インスタンスをリストから扱えるようにする方法を解説します。

クラスのインスタンスをリストで扱えるようにするには、弱参照を使うと簡単です。弱参照とは、元のオブジェクトが削除された場合に消える参照のことを言います。

それでは、クラスのインスタンスをリストで扱う方法を見ていきましょう!

クラスのインスタンスをリストで扱う

クラスのインスタンスをリストとして扱うには、インスタンスへの弱参照を持つリストをクラス変数として保持させ、コンストラクタで弱参照をリストに追加することで実現できます。

import weakref

class C:
    # クラスの参照を保存するリスト
    references = []

    def __init__(self, val) -> None:
        self.val = val

        # リストにインスタンスの弱参照を追加
        C.references.append(weakref.ref(self))

実際に上記クラスをインスタンス化して呼び出してみます。

# インスタンス化
c1 = C(1)
c2 = C(2)
c3 = C(3)

# 呼び出し
for ref in C.references:
    # 参照なので () が必要
    r = ref()
    # クラス名と変数の呼び出し
    print(r.__class__, r.val)

実行結果

<class '__main__.C'> 1
<class '__main__.C'> 2
<class '__main__.C'> 3

これでクラスの全インスタンスの弱参照をリストで扱うことができます。

参照を削除する

インスタンスが削除された場合、弱参照はNoneTypeとして扱われる。

import weakref

class C:
    # クラスの参照を保存するリスト
    references = []

    def __init__(self, val) -> None:
        self.val = val

        # リストにインスタンスの弱参照を追加
        C.references.append(weakref.ref(self))

# インスタンス化
c1 = C(1)
c2 = C(2)
c3 = C(3)

# インスタンスの削除
del c2

# 呼び出し
for ref in C.references:
    r = ref()
    print(r.__class__, r.val)

実行結果

<class '__main__.C'> 1
Traceback (most recent call last):
  File "main.py", line 22, in <module>
    print(r.__class__, r.val)
AttributeError: 'NoneType' object has no attribute 'val'

インスタンスが削除された時にリストから弱参照も削除したい場合は、弱参照を生成する時に以下のようなラムダ式をコールバックとして定義しておくと楽ちん。

weakref.ref(self, lambda ref: C.references.remove(ref))

これで削除されたインスタンスの弱参照は勝手にリストから削除されます。

import weakref

class C:
    # クラスの参照を保存するリスト
    references = []

    def __init__(self, val) -> None:
        self.val = val

        # リストにインスタンスの弱参照を追加
        C.references.append(weakref.ref(self, lambda ref: C.references.remove(ref)))

# インスタンス化
c1 = C(1)
c2 = C(2)
c3 = C(3)

# インスタンスの削除
del c2

# 呼び出し
for ref in C.references:
    r = ref()
    print(r.__class__, r.val)

実行結果

<class '__main__.C'> 1
<class '__main__.C'> 3

まとめ

この記事では、特定のクラスの全インスタンスの弱参照をリストで扱う方法を解説しました。

もし、全クラスのインスタンスをまとめたい場合は、リストをグローバル変数として定義すれば可能ですが、組み込み型の弱参照は生成できないのでいちいちサブクラスを定義する必要があります。

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ