Question

Étant donné une instance d'une classe en Python, il serait utile de pouvoir déterminer quelle ligne de code source définit chaque méthode et propriété (par exemple, pour implémenter 1 ). Par exemple, étant donné un module 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

définit une fonction (class_, attribut) renvoyant un tuple contenant le nom du fichier, la classe et la ligne dans le code source défini ou sous-classé attribute. Cela signifie la définition dans le corps de la classe, pas la dernière affectation due à un dynamisme excessif. Cela ne pose pas de problème si le résultat est inconnu pour certains attributs.

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

Je veux utiliser ce tout en effectuant une introspection dans Plone, où chaque objet possède des centaines de méthodes et il serait vraiment utile de les trier par classe, et pas seulement par ordre alphabétique.

Bien sûr, en Python, vous ne pouvez pas toujours savoir raisonnablement, mais il serait bien d’obtenir de bonnes réponses dans le cas habituel du code essentiellement statique.

Était-ce utile?

La solution 2

Vous recherchez la fonction non documentée inspect.classify_class_attrs(cls). Passez-le à une classe et il retournera une liste de tuples ('name', 'kind' e.g. 'method' or 'data', defining class, property). Si vous avez besoin d'informations sur absolument tout dans une instance spécifique, vous devrez effectuer un travail supplémentaire.

Exemple:

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

Autres conseils

C’est plus ou moins impossible sans analyse statique, et même dans ce cas, cela ne fonctionnera pas toujours. Vous pouvez obtenir la ligne dans laquelle une fonction a été définie et dans quel fichier en examinant son objet de code, mais au-delà, vous ne pouvez rien faire de plus. Le module inspect peut vous aider. Donc:

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)

Mais considérez:

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

Ou pire:

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

Surtout dans ce dernier cas, que voulez-vous ou espérez-vous obtenir?

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top