Pergunta

Dada uma instância de alguma classe em Python, que seria útil para ser capaz de determinar qual linha de código fonte definido cada método e propriedade (por exemplo, para implementar 1 ). Por exemplo, dado um 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

definir uma função para onde (class_, atributo) retornando uma tupla contendo o nome do ficheiro, a classe, e a linha no código de fonte que definido ou subclasse attribute. Isto significa que a definição no corpo da classe, e não a última missão devido ao dinamismo overeager. É bom se ele retorna 'desconhecido' para alguns 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")

Eu quero usar isso enquanto introspecção Plone, onde cada objeto tem centenas de métodos e seria realmente útil para classificar através deles organizados por classe e não apenas em ordem alfabética.

Claro que, em Python você pode nem sempre razoavelmente sei, mas seria bom para obter boas respostas no caso comum de código principalmente-estático.

Foi útil?

Solução 2

Você está procurando o inspect.classify_class_attrs(cls) função não documentada. Passá-lo uma classe e ele irá retornar uma lista de tuplas ('name', 'kind' e.g. 'method' or 'data', defining class, property). Se você precisar de informações sobre absolutamente tudo em uma instância específica que você terá que fazer um trabalho adicional.

Exemplo:

>>> 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),
 ...
 ]

Outras dicas

Este é mais ou menos impossível sem uma análise estática, e mesmo assim, nem sempre vai funcionar. Você pode obter a linha onde a função foi definida e em que arquivo, examinando o seu objeto de código, mas além disso, não há muito que você pode fazer. O módulo inspect pode ajudar com isso. Assim:

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)

Mas considere:

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

Ou pior:

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

Especialmente neste último caso, o que você quer ou espera receber?

Você está procurando o inspecionar módulo, especificamente inspect.getsourcefile() e inspect.getsourcelines(). Por exemplo

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)

Dada a natureza dinâmica do Python, fazendo isso para situações mais complicadas pode simplesmente não ser possível ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top