Introspección de Python: ¿Cómo obtener una lista 'no ordenada' de atributos de objeto?
-
11-07-2019 - |
Pregunta
El siguiente código
import types
class A:
class D:
pass
class C:
pass
for d in dir(A):
if type(eval('A.'+d)) is types.ClassType:
print d
salidas
C
D
¿Cómo consigo que salga en el orden en que se definieron estas clases en el código? Es decir,
D
C
¿Hay alguna otra forma que no sea usar inspect.getsource (A) y analizar eso?
Solución
El módulo inspeccionar
también tiene la función findource
. Devuelve una tupla de líneas de origen y número de línea donde se define el objeto.
>>> import inspect
>>> import StringIO
>>> inspect.findsource(StringIO.StringIO)[1]
41
>>>
La función findource
realmente busca a través del archivo fuente y busca posibles candidatos si se le da un objeto de clase.
Dado un método, función, rastreo, marco u objeto de código, simplemente mira el atributo co_firstlineno
del objeto de código (contenido).
Otros consejos
Tenga en cuenta que el análisis ya está hecho para usted en la inspección: eche un vistazo a inspect.findsource
, que busca en el módulo la definición de clase y devuelve el origen y el número de línea. Ordenar por ese número de línea (también puede necesitar dividir las clases definidas en módulos separados) debería dar el orden correcto.
Sin embargo, esta función no parece estar documentada, y solo está usando una expresión regular para encontrar la línea, por lo que puede no ser demasiado confiable.
Otra opción es usar metaclases, o alguna otra forma de ordenar información implícita o explícitamente al objeto. Por ejemplo:
import itertools, operator
next_id = itertools.count().next
class OrderedMeta(type):
def __init__(cls, name, bases, dct):
super(OrderedMeta, cls).__init__(name, bases, dct)
cls._order = next_id()
# Set the default metaclass
__metaclass__ = OrderedMeta
class A:
class D:
pass
class C:
pass
print sorted([cls for cls in [getattr(A, name) for name in dir(A)]
if isinstance(cls, OrderedMeta)], key=operator.attrgetter("_order"))
Sin embargo, este es un cambio bastante intrusivo (requiere establecer la metaclase de cualquier clase que le interese en OrderedMeta)
No, no puede obtener esos atributos en el orden que está buscando. Los atributos de Python se almacenan en un dict (léase: hashmap), que no tiene conocimiento del orden de inserción.
Además, evitaría el uso de eval simplemente diciendo
if type(getattr(A, d)) is types.ClassType:
print d
en tu bucle. Tenga en cuenta que también puede iterar a través de pares clave / valor en A.__dict__
AFAIK, no, no hay *. Esto se debe a que todos los atributos de una clase se almacenan en un diccionario (que, como saben, no está ordenado).
*: en realidad podría ser posible, pero eso requeriría decoradores o posiblemente pirateo de metaclases. ¿Alguno de esos te interesa?
No estoy tratando de ser simplista aquí, pero ¿sería factible organizar las clases en su fuente alfabéticamente? Me parece que cuando hay muchas clases en un archivo, esto puede ser útil por derecho propio.