Mais qui donc hérite de ma classe ? 6


Pas une question que l’on se pose souvent, à moins d’avoir une lib qui expose une classe avec beaucoup d’introspection.

Ceci dit pour la culture G, je me suis dit que ça pourrait intéresser quelques geeks de savoir comment lister les enfants d’une classe, récursivement.

def subclasses(cls, _found=()):
    """ Retourne toutes les classes héritant d'une classe """
 
    # On check que la classe est hérite bien de "object".
    # Utile uniquement pour un code 2.x qui utiliserait
    # des old style classes, qui n'ont pas "__subclasses__".
    if not isinstance(cls, type):
      raise TypeError('subclasses works only with new-style classes'
                            ', not %s' % cls)
 
    # On va stocker les classes rencontrées dans un set
    # pour éviter les doublons car on peut tomber sur
    # un héritage en forme de diamant.
    _found = _found or set()
 
    try:
      subs = cls.__subclasses__()
    except TypeError:  # Erreur levée si cls == type, petits vicieux
      subs = cls.__subclasses__(cls)
 
    for sub in subs:
        if sub not in _found:
            _found.add(sub)
            # Un appel récursif comme on les aimes
            subclasses(sub, _found)
 
    return _found

Pas très compliqué, donc, si on connait les piègeounets : ça ne marche pas sur les old syle classes, et il y a un traitement spécial pour type. Celà dit, qui utilise encore des old styles classes ? Et franchement lister les héritiers de type, à par pour satisfaire sa curiosité…

Aller, juste pour le fun, sur un virtualenv vierge:

for x in subclasses(object):
    print x
## <type 'callable-iterator'>
## <class '_abcoll.Sized'>
## <type 'exceptions.EOFError'>
## <class '_abcoll.Mapping'>
## <type 'exceptions.UnicodeWarning'>
## <type 'exceptions.IOError'>
## <type 'memoryview'>
## <type 'code'>
## <type 'exceptions.ImportWarning'>
## <type 'sys.flags'>
## <type 'iterator'>
## <class 'warnings.catch_warnings'>
## <type 'exceptions.Warning'>
## <type 'exceptions.EnvironmentError'>
## <type 'dict'>
## <class 'encodings.utf_8.IncrementalEncoder'>
## <type 'weakproxy'>
## <class '_abcoll.Iterator'>
## <type 'sys.version_info'>
## <type 'posix.stat_result'>
## <type 'frozenset'>
## <class 'codecs.CodecInfo'>
## <class 'zipimport.ZipImportError'>
## <type 'exceptions.StopIteration'>
## <type 'exceptions.ImportError'>
## <class 'site._Printer'>
## <type 'weakref'>
## <class '_abcoll.Sequence'>
## <type 'property'>
## <class 'encodings.utf_8.IncrementalDecoder'>
## <type 'imp.NullImporter'>
## <type 'exceptions.TypeError'>
## <type 'bytearray'>
## <type 'int'>
## <type 'exceptions.UnicodeTranslateError'>
## <type 'instance'>
## <type 'exceptions.BaseException'>
## <type 'exceptions.SyntaxWarning'>
## <type 'file'>
## <class '_abcoll.MappingView'>
## <class '_weakrefset._IterationGuard'>
## <type 'exceptions.UnicodeDecodeError'>
## <type 'classobj'>
## <type 'exceptions.UnicodeError'>
## <class 'abc.abstractproperty'>
## <type 'exceptions.DeprecationWarning'>
## <type 'complex'>
## <type 'set'>
## <type 'buffer'>
## <type 'generator'>
## <type 'exceptions.Exception'>
## <class 'codecs.IncrementalDecoder'>
## <type 'exceptions.UserWarning'>
## <type 'staticmethod'>
## <type 'exceptions.UnicodeEncodeError'>
## <class 'encodings.CodecRegistryError'>
## <class '_abcoll.MutableSequence'>
## <class '_abcoll.KeysView'>
## <type 'cell'>
## <type 'exceptions.StandardError'>
## <type 'enumerate'>
## <type 'exceptions.KeyboardInterrupt'>
## <type 'exceptions.BufferError'>
## <class 'warnings.WarningMessage'>
## <type 'EncodingMap'>
## <class 'codecs.BufferedIncrementalDecoder'>
## <type 'exceptions.ValueError'>
## <class '_abcoll.Set'>
## <type 'exceptions.MemoryError'>
## <type 'exceptions.SystemExit'>
## <type 'reversed'>
## <class '_abcoll.Hashable'>
## <type 'bool'>
## <type 'classmethod'>
## <type 'exceptions.ReferenceError'>
## <type 'exceptions.GeneratorExit'>
## <class '_abcoll.Container'>
## <class '_abcoll.ItemsView'>
## <type 'xrange'>
## <type 'exceptions.PendingDeprecationWarning'>
## <type 'basestring'>
## <type 'exceptions.SystemError'>
## <type 'exceptions.ZeroDivisionError'>
## <class 'site.Quitter'>
## <type 'long'>
## <type 'NotImplementedType'>
## <type 'super'>
## <type 'fieldnameiterator'>
## <class '_abcoll.Callable'>
## <class '_abcoll.MutableSet'>
## <type 'exceptions.ArithmeticError'>
## <class 'abc.ABCMeta'>
## <type 'exceptions.OverflowError'>
## <type 'exceptions.FutureWarning'>
## <type 'sys.float_info'>
## <type 'formatteriterator'>
## <type 'type'>
## <type 'exceptions.AssertionError'>
## <type 'traceback'>
## <type 'exceptions.FloatingPointError'>
## <type 'function'>
## <type 'instancemethod'>
## <type 'sys.long_info'>
## <type 'builtin_function_or_method'>
## <class 'signal.ItimerError'>
## <class 'site._Helper'>
## <type 'exceptions.LookupError'>
## <type 'wrapper_descriptor'>
## <type 'exceptions.KeyError'>
## <class '_abcoll.ValuesView'>
## <type 'slice'>
## <class '_weakrefset.WeakSet'>
## <type 'list'>
## <type 'exceptions.IndexError'>
## <type 'getset_descriptor'>
## <type 'posix.statvfs_result'>
## <type 'exceptions.SyntaxError'>
## <type 'frame'>
## <class 'codecs.BufferedIncrementalEncoder'>
## <type 'PyCapsule'>
## <type 'exceptions.IndentationError'>
## <type 'NoneType'>
## <type 'zipimport.zipimporter'>
## <type 'member_descriptor'>
## <type 'exceptions.AttributeError'>
## <type 'ellipsis'>
## <type 'exceptions.UnboundLocalError'>
## <type 'unicode'>
## <class '_abcoll.Iterable'>
## <type 'exceptions.TabError'>
## <type 'exceptions.NameError'>
## <type 'tuple'>
## <class 'warnings._OptionError'>
## <type 'exceptions.NotImplementedError'>
## <type 'exceptions.RuntimeWarning'>
## <type 'str'>
## <class '_abcoll.MutableMapping'>
## <type 'exceptions.BytesWarning'>
## <type 'module'>
## <type 'exceptions.RuntimeError'>
## <class 'codecs.IncrementalEncoder'>
## <type 'float'>
## <type 'exceptions.OSError'>
## <type 'dictproxy'>
## <type 'weakcallableproxy'>

Putain, ça c’est du remplissage ! 20minutes serait fier de moi.

6 thoughts on “Mais qui donc hérite de ma classe ?

Leave a comment

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.