Pregunta

Dada una instancia de alguna clase en Python, sería útil poder determinar qué línea de código fuente definió cada método y propiedad (por ejemplo, implementar 1 ). Por ejemplo, dado un módulo ab.py

class A(object):
    z = 1
    q = 2
    def y(self): pass
    def x(self): pass

class B(A):
    q = 4
    def x(self): pass
    def w(self): pass

define una función donde (clase_, atributo) devuelve una tupla que contiene el nombre de archivo, la clase y la línea en el código fuente que definió o subclasificó attribute. Esto significa la definición en el cuerpo de la clase, no la última tarea debido al exceso de dinamismo. Está bien si devuelve 'desconocido' para algunos atributos.

>>> a = A()
>>> b = B()
>>> b.spigot = 'brass'
>>> whither(a, 'z')
("ab.py", <class 'a.A'>, [line] 2)
>>> whither(b,  'q')
("ab.py", <class 'a.B'>, 8)
>>> whither(b, 'x')
("ab.py", <class 'a.B'>, 9)
>>> whither(b, 'spigot')
("Attribute 'spigot' is a data attribute")

Quiero usar esto al introspectar Plone, donde cada objeto tiene cientos de métodos y sería realmente útil clasificarlos organizados por clase y no solo alfabéticamente.

Por supuesto, en Python no siempre se puede saber razonablemente, pero sería bueno obtener buenas respuestas en el caso común de código mayormente estático.

¿Fue útil?

Solución 2

Está buscando la función no documentada inspect.classify_class_attrs(cls). Pásalo una clase y devolverá una lista de tuplas ('name', 'kind' e.g. 'method' or 'data', defining class, property). Si necesita información sobre absolutamente todo en una instancia específica, tendrá que hacer un trabajo adicional.

Ejemplo:

>>> import inspect
>>> import pprint
>>> import calendar
>>> 
>>> hc = calendar.HTMLCalendar()
>>> hc.__class__.pathos = None
>>> calendar.Calendar.phobos = None
>>> pprint.pprint(inspect.classify_class_attrs(hc.__class__))
[...
 ('__doc__',
  'data',
  <class 'calendar.HTMLCalendar'>,
  '\n    This calendar returns complete HTML pages.\n    '),
 ...
 ('__new__',
  'data',
  <type 'object'>,
  <built-in method __new__ of type object at 0x814fac0>),
 ...
 ('cssclasses',
  'data',
  <class 'calendar.HTMLCalendar'>,
  ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']),
 ('firstweekday',
  'property',
  <class 'calendar.Calendar'>,
  <property object at 0x98b8c34>),
 ('formatday',
  'method',
  <class 'calendar.HTMLCalendar'>,
  <function formatday at 0x98b7bc4>),
 ...
 ('pathos', 'data', <class 'calendar.HTMLCalendar'>, None),
 ('phobos', 'data', <class 'calendar.Calendar'>, None),
 ...
 ]

Otros consejos

Esto es más o menos imposible sin un análisis estático, e incluso así, no siempre funcionará. Puede obtener la línea donde se definió una función y en qué archivo examinando su objeto de código, pero más allá de eso, no hay mucho que pueda hacer. El módulo inspect puede ayudar con esto. Entonces:

import ab
a = ab.A()
meth = a.x
# So, now we have the method.
func = meth.im_func
# And the function from the method.
code = func.func_code
# And the code from the function!
print code.co_firstlineno, code.co_filename

# Or:
import inspect
print inspect.getsource(meth), inspect.getfile(meth)

Pero considere:

def some_method(self):
    pass
ab.A.some_method = some_method
ab.A.some_class_attribute = None

O peor:

some_cls = ab.A
some_string_var = 'another_instance_attribute'
setattr(some_cls, some_string_var, None)

Especialmente en el último caso, ¿qué quieres o esperas obtener?

You are looking for the inspect module, specifically inspect.getsourcefile() and inspect.getsourcelines(). For example

a.py:

class Hello(object):
    def say(self):
       print 1

>>> from a import Hello
>>> hi = Hello()
>>> inspect.getsourcefile(hi.say)
a.py
>>> inspect.getsourcelines(A, foo)
(['   def say(self):\n        print 1\n'], 2)

Given the dynamic nature of Python, doing this for more complicated situations may simply not be possible...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top