3

给定 Python 中某个类的实例,能够确定哪一行源代码定义了每个方法和属性(例如实现1)将很有用。例如,给定一个模块 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

定义一个函数 where(class_, attribute) 返回一个元组,该元组包含定义或子类化的源代码中的文件名、类和行attribute。这意味着在班级主体中的定义,而不是由于过度活跃而导致的最新分配。如果它为某些属性返回“未知”,那很好。

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

我想在自省 Plone 时使用它,其中每个对象都有数百个方法,按类而不是按字母顺序对它们进行排序非常有用。

当然,在 Python 中你不能总是合理地知道,但在大多数静态代码的常见情况下获得好的答案会很好。

4

3 回答 3

3

您正在寻找未记录的功能inspect.classify_class_attrs(cls)。传递给它一个类,它会返回一个元组列表('name', 'kind' e.g. 'method' or 'data', defining class, property)。如果您需要有关特定实例中绝对所有内容的信息,您将不得不做额外的工作。

例子:

>>> 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),
 ...
 ]
于 2009-01-27T22:11:53.177 回答
2

如果没有静态分析,这或多或少是不可能的,即使那样,它也不会总是有效。您可以通过检查其代码对象来获取定义函数的行以及在哪个文件中,但除此之外,您无能为力。该inspect模块可以帮助解决这个问题。所以:

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)

但请考虑:

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

或者更糟:

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

尤其是在后一种情况下,您想要或期望得到什么?

于 2009-01-27T19:56:49.410 回答
1

您正在寻找检查模块,特别是inspect.getsourcefile()inspect.getsourcelines(). 例如

一个.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)

鉴于 Python 的动态特性,在更复杂的情况下这样做可能根本不可能......

于 2009-01-27T19:52:26.937 回答