2010-11-04 13 views
5

Me gustaría poder iterar sobre todas las clases base, tanto directas como indirectas, de una clase dada, incluida la clase misma. Esto es útil en el caso en que tenga una metaclase que examine una clase de Opciones interna de todas sus bases.¿Hay una función estándar para iterar sobre las clases base?

Para ello, escribí lo siguiente:

def bases(cls): 
    yield cls 
    for direct_base in cls.__bases__: 
     for base in bases(direct_base): 
      yield base 

¿Hay una función estándar de hacer esto por mí?

Respuesta

12

Hay un método que puede devolverlos a todos, en Orden de resolución de método (MRO): inspect.getmro. Ver aquí:

http://docs.python.org/library/inspect.html#inspect.getmro

Se les vuelve como una tupla, que luego se puede iterar sobre en un solo bucle de sí mismo:

import inspect 
for base_class in inspect.getmro(foo): 
    # do something 

Esto tiene el beneficio adicional de sólo el rendimiento de cada clase base una vez , incluso si tienes una herencia con un patrón de diamantes.

0

No sé exactamente si es lo que estás buscando, pero echar un vistazo a someclass.__mro__, siendo MRO Resolución método de pedido

http://docs.python.org/library/stdtypes.html?highlight=mro#class.__mro__

+1

Esto tiene la (discutible) desventaja de no trabajar con clases antiguas. 'inspect.getmro' devuelve' cls .__ mro__' si está presente (que está en nuevas clases de estilo) y realiza una búsqueda personalizada si no lo está. (Dato curioso: puede generar un error de recursión creando una jerarquía de clase de estilo anterior con más clases que la profundidad máxima de recursión y llamando a 'getmro' en ella) – aaronasterling

1

ámbar tiene la respuesta correcta para el mundo real, pero voy a mostrar una forma correcta de hacer esto. Su solución incluirá algunas clases dos veces si dos clases base heredan de la misma clase base.

def bases(cls): 
    classes = [cls] 
    i = 0 
    while 1: 
     try: 
      cls = classes[i] 
     except IndexError: 
      return classes 
     i += 1 
     classes[i:i] = [base for base in cls.__bases__ if base not in classes] 

La única parte un poco complicada es donde usamos la porción. Eso es necesario para realizar este tipo de búsqueda de profundidad en primer lugar sin usar recursividad. Todo lo que hace es tomar las clases base de la clase que se está examinando e insertarlas inmediatamente después para que la primera clase base sea la siguiente clase examinada. Una solución muy legible (que tiene su propia fealdad) está disponible en la implementación de inspect.getmro en la biblioteca estándar.

+0

Gracias. Me di cuenta después de publicar que la mina puede golpear la misma clase dos veces, pero en mi caso no importó. –

Cuestiones relacionadas