Domanda

Data un'istanza di qualche classe in Python, sarebbe utile poter determinare quale riga del codice sorgente definito ogni metodo e proprietà (ad esempio per implementare 1 ). Ad esempio, dato un modulo 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

definisce una funzione dove (classe_, attributo) restituisce una tupla contenente il nome file, la classe e la linea nel codice sorgente che ha definito o sottoclassato attribute. Ciò significa che la definizione nel corpo della classe, non l'ultimo incarico a causa di un dinamismo eccessivo. Va bene se restituisce "sconosciuto" per alcuni attributi.

>>> 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")

Voglio usarlo mentre introspettivo Plone, dove ogni oggetto ha centinaia di metodi e sarebbe davvero utile ordinarli in ordine di classe e non solo in ordine alfabetico.

Ovviamente, in Python non puoi sempre ragionevolmente sapere, ma sarebbe bello avere buone risposte nel caso comune di codice prevalentemente statico.

È stato utile?

Soluzione 2

Stai cercando la funzione non documentata inspect.classify_class_attrs(cls). Passa una classe e restituirà un elenco di tuple ('name', 'kind' e.g. 'method' or 'data', defining class, property). Se hai bisogno di informazioni su tutto in una specifica istanza, dovrai fare un lavoro aggiuntivo.

Esempio:

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

Altri suggerimenti

Questo è più o meno impossibile senza analisi statiche e anche in questo caso non funzionerà sempre. Puoi ottenere la riga in cui è stata definita una funzione e in quale file esaminando il suo oggetto codice, ma oltre a ciò, non c'è molto che puoi fare. Il modulo inspect può aiutarti in questo. Quindi:

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)

Ma considera:

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

O peggio:

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

Soprattutto in quest'ultimo caso, cosa vuoi o ti aspetti di ottenere?

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...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top