您如何确定Python类的每个属性和方法的定义?

时间:2022-04-14 14:26:48

Given an instance of some class in Python, it would be useful to be able to determine which line of source code defined each method and property (e.g. to implement 1). For example, given a module ab.py

给定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

define a function whither(class_, attribute) returning a tuple containing the filename, class, and line in the source code that defined or subclassed attribute. This means the definition in the class body, not the latest assignment due to overeager dynamism. It's fine if it returns 'unknown' for some attributes.

定义一个函数(class_,attribute)返回一个元组,该元组包含定义或子类属性的源代码中的文件名,类和行。这意味着类体中的定义,而不是由于过于活跃的动态而导致的最新任务。如果它为某些属性返回'unknown'则没问题。

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

I want to use this while introspecting Plone, where every object has hundreds of methods and it would be really useful to sort through them organized by class and not just alphabetically.

我想在反省Plone的同时使用它,其中每个对象都有数百种方法,按类组织排序它们非常有用,而不仅仅是按字母顺序排列。

Of course, in Python you can't always reasonably know, but it would be nice to get good answers in the common case of mostly-static code.

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

3 个解决方案

#1


This is more-or-less impossible without static analysis, and even then, it won't always work. You can get the line where a function was defined and in which file by examining its code object, but beyond that, there's not much you can do. The inspect module can help with this. So:

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

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)

But consider:

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

Or worse:

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

Especially in the latter case, what do you want or expect to get?

特别是在后一种情况下,您想要或期望获得什么?

#2


You are looking for the undocumented function inspect.classify_class_attrs(cls). Pass it a class and it will return a list of tuples ('name', 'kind' e.g. 'method' or 'data', defining class, property). If you need information on absolutely everything in a specific instance you'll have to do additional work.

您正在寻找未记录的函数inspect.classify_class_attrs(cls)。将它传递给一个类,它将返回一个元组列表('name','kind',例如'method'或'data',定义class,property)。如果您需要有关特定实例中绝对所有内容的信息,则必须执行其他工作。

Example:

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

#3


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

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

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

鉴于Python的动态特性,在更复杂的情况下执行此操作可能根本不可能......

#1


This is more-or-less impossible without static analysis, and even then, it won't always work. You can get the line where a function was defined and in which file by examining its code object, but beyond that, there's not much you can do. The inspect module can help with this. So:

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

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)

But consider:

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

Or worse:

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

Especially in the latter case, what do you want or expect to get?

特别是在后一种情况下,您想要或期望获得什么?

#2


You are looking for the undocumented function inspect.classify_class_attrs(cls). Pass it a class and it will return a list of tuples ('name', 'kind' e.g. 'method' or 'data', defining class, property). If you need information on absolutely everything in a specific instance you'll have to do additional work.

您正在寻找未记录的函数inspect.classify_class_attrs(cls)。将它传递给一个类,它将返回一个元组列表('name','kind',例如'method'或'data',定义class,property)。如果您需要有关特定实例中绝对所有内容的信息,则必须执行其他工作。

Example:

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

#3


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

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

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

鉴于Python的动态特性,在更复杂的情况下执行此操作可能根本不可能......