Existe-t-il un moyen en python d'interroger un espace de noms pour les classes qui héritent d'une classe particulière ? Étant donné une classe widget
j'aimerais pouvoir appeler quelque chose comme inheritors(widget)
pour obtenir une liste de tous mes différents types de widgets.
Réponses
Trop de publicités?Vous souhaitez utiliser Widget.__subclasses__()
pour obtenir une liste de toutes les sous-classes. Il ne recherche que les sous-classes directes, donc si vous les voulez toutes, vous devrez faire un peu plus de travail :
def inheritors(klass):
subclasses = set()
work = [klass]
while work:
parent = work.pop()
for child in parent.__subclasses__():
if child not in subclasses:
subclasses.add(child)
work.append(child)
return subclasses
NB Si vous utilisez Python 2.x, cela ne fonctionne que pour les classes de nouveau style.
Vous pouvez suivre l'héritage avec votre propre métaclasse
import collections
class A(object):
class __metaclass__(type):
__inheritors__ = defaultdict(list)
def __new__(meta, name, bases, dct):
klass = type.__new__(meta, name, bases, dct)
for base in klass.mro()[1:-1]:
meta.__inheritors__[base].append(klass)
return klass
class B(A):
pass
class C(B):
pass
>>> A.__inheritors__
defaultdict(<type 'list'>, {<class '__main__.A'>: [<class '__main__.B'>, <class '__main__.C'>], <class '__main__.B'>: [<class '__main__.C'>]})
Tout ce qui est hérité de A
ou de ses classes dérivées sera suivi. Vous obtiendrez une carte d'héritage complète lorsque tous les modules de votre application seront chargés.
# return list of tuples (objclass, name) containing all subclasses in callers' module
def FindAllSubclasses(classType):
import sys, inspect
subclasses = []
callers_module = sys._getframe(1).f_globals['__name__']
classes = inspect.getmembers(sys.modules[callers_module], inspect.isclass)
for name, obj in classes:
if (obj is not classType) and (classType in inspect.getmro(obj)):
subclasses.append((obj, name))
return subclasses