1. ホーム
  2. パイソン

[解決済み】名前が与えられたクラスのすべてのサブクラスを見つけるには?

2022-05-03 11:28:11

質問

私はPythonでベースクラスから継承されたすべてのクラスを取得するための作業アプローチが必要です。

どのように解決するのですか?

新スタイルのクラス(すなわち object これは Python 3 のデフォルトです)。 __subclasses__ メソッドがあり、サブクラスを返します。

class Foo(object): pass
class Bar(Foo): pass
class Baz(Foo): pass
class Bing(Bar): pass

以下は、サブクラスの名前です。

print([cls.__name__ for cls in Foo.__subclasses__()])
# ['Bar', 'Baz']

以下はサブクラスそのものです。

print(Foo.__subclasses__())
# [<class '__main__.Bar'>, <class '__main__.Baz'>]

サブクラスが実際にリストアップされていることを確認する Foo をベースとしています。

for cls in Foo.__subclasses__():
    print(cls.__base__)
# <class '__main__.Foo'>
# <class '__main__.Foo'>

サブクラスが必要な場合は、recurseする必要があることに注意してください。

def all_subclasses(cls):
    return set(cls.__subclasses__()).union(
        [s for c in cls.__subclasses__() for s in all_subclasses(c)])

print(all_subclasses(Foo))
# {<class '__main__.Bar'>, <class '__main__.Baz'>, <class '__main__.Bing'>}

サブクラスのクラス定義がまだ実行されていない場合 (たとえば、サブクラスのモジュールがまだインポートされていない場合) は、そのサブクラスはまだ存在しないことに注意してください。 __subclasses__ はそれを見つけることができません。


名前がついている」ということですが、これはどういう意味ですか?Pythonのクラスはファーストクラスのオブジェクトなので、クラスの名前を文字列で代用したりする必要はありません。クラスを直接使用することができますし、おそらくそうすべきです。

クラスの名前を表す文字列があり、そのクラスのサブクラスを見つけたい場合は、2つのステップを踏みます:クラス名からクラスを見つけ、次に __subclasses__ と同じです。

名前からどのようにクラスを見つけるかは、どこでクラスを見つけようと思っているかによります。もし、クラスを見つけようとしているコードと同じモジュールで見つけようと思っているのなら

cls = globals()[name]

を使えばいいし、万が一、ローカルで見つかることを期待しているのであれば

cls = locals()[name]

クラスがどのモジュールにも含まれる場合、名前の文字列は完全修飾名を含む必要があります - 以下のようなものです。 'pkg.module.Foo' ではなく、単に 'Foo' . 使用方法 importlib を使用してクラスのモジュールをロードし、対応する属性を取得します。

import importlib
modname, _, clsname = name.rpartition('.')
mod = importlib.import_module(modname)
cls = getattr(mod, clsname)

どのようにクラスを見つけるか。 cls.__subclasses__() は、そのサブクラスのリストを返します。