Классы нового стиля (то есть подклассы из 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'>
Обратите внимание, есливам нужны подклассы, вы должны будете набрать:
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 являются первоклассными объектами, вам не нужно использовать строку с именем класса вместо класса или что-то подобное.Вы можете просто использовать класс напрямую, и вам, вероятно, следует.
Если у вас есть строка, представляющая имя класса, и вы хотите найти подклассы этого класса, тогда есть два шага: найти данный классего имя, а затем найдите подклассы с __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__()
выдаст список его подклассов.