Python: 派生クラスをすべて取得できるクラス
公開:
更新:
メタクラスを使う方法
メタクラスでクラス定義時の挙動をカスタマイズすることで、派生したクラスをすべて追跡するクラスを定義できます。自身を除いた TrackableBase
のサブクラスが tracked_classes
に、クラス定義時に追加されます。
class TrackableMeta(type):
tracked_classes = []
def __new__(meta, name, bases, attributes, **kwargs):
cls = super().__new__(meta, name, bases, attributes, **kwargs)
# TrackableBase 自体は追跡しない
try:
TrackableBase
except NameError:
pass
else:
TrackableMeta.tracked_classes.append(cls)
return cls
class TrackableBase(metaclass=TrackableMeta):
def __new__(cls, *args, **kwargs):
if cls is TrackableBase:
raise RuntimeError()
return super().__new__(cls, *args, **kwargs)
class A(TrackableBase):
pass
class B(A):
pass
class C(TrackableBase):
pass
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>]
print(TrackableMeta.tracked_classes)
__init_subclass__
を使う方法
Python 3.6 以降は __init_subclass__
特殊メソッドを使うことで、同様のことをメタクラスなしに実現できます。
class TrackableBase:
tracked_classes = []
def __new__(cls, *args, **kwargs):
if cls is TrackableBase:
raise RuntimeError()
return super().__new__(cls, *args, **kwargs)
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
TrackableBase.tracked_classes.append(cls)
class A(TrackableBase):
pass
class B(A):
pass
class C(TrackableBase):
pass
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>]
print(TrackableBase.tracked_classes)