Itera sulle sottoclassi di una determinata classe in un determinato modulo

StackOverflow https://stackoverflow.com/questions/44352

  •  09-06-2019
  •  | 
  •  

Domanda

In Python, dato un modulo X e una classe Y, come posso ripetere o generare un elenco di tutte le sottoclassi di Y che esistono nel modulo X?

È stato utile?

Soluzione

Ecco un modo per farlo:

import inspect

def get_subclasses(mod, cls):
    """Yield the classes in module ``mod`` that inherit from ``cls``"""
    for name, obj in inspect.getmembers(mod):
        if hasattr(obj, "__bases__") and cls in obj.__bases__:
            yield obj

Altri suggerimenti

Sebbene il suggerimento di Quamrana funzioni bene, ci sono un paio di possibili miglioramenti che vorrei suggerire per renderlo più pitonico.Si basano sull'utilizzo del modulo di ispezione dalla libreria standard.

  1. Puoi evitare la chiamata getattr utilizzando inspect.getmembers()
  2. Il try/catch può essere evitato utilizzando inspect.isclass()

Con questi, puoi ridurre il tutto a una singola lista di comprensione, se lo desideri:

def find_subclasses(module, clazz):
    return [
        cls
            for name, cls in inspect.getmembers(module)
                if inspect.isclass(cls) and issubclass(cls, clazz)
    ]

Posso suggerire che nessuna delle risposte di Chris AtLee e Zacherates soddisfa i requisiti?Penso che questa modifica alla risposta di zacerates sia migliore:

def find_subclasses(module, clazz):
    for name in dir(module):
        o = getattr(module, name)
        try:
            if (o != clazz) and issubclass(o, clazz):
                yield name, o
        except TypeError: pass

Il motivo per cui non sono d'accordo con le risposte fornite è che la prima non produce classi che siano una sottoclasse distante della classe data, e la seconda include la classe data.

Dato il modulo foo.py

class foo(object): pass
class bar(foo): pass
class baz(foo): pass

class grar(Exception): pass

def find_subclasses(module, clazz):
    for name in dir(module):
        o = getattr(module, name)

        try: 
             if issubclass(o, clazz):
             yield name, o
        except TypeError: pass

>>> import foo
>>> list(foo.find_subclasses(foo, foo.foo))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>)]
>>> list(foo.find_subclasses(foo, object))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>), ('grar', <class 'foo.grar'>)]
>>> list(foo.find_subclasses(foo, Exception))
[('grar', <class 'foo.grar'>)]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top