我觉得我在 Python 中遇到了一种相当奇怪的行为。自己尝试一下:
import inspect
class SomeClass:
def __init__(self):
inspect.getmembers(self, predicate=inspect.ismethod)
def this_is_okay(self):
raise Exception('an error that may be thrown')
@property
def this_is_not_okay(self):
raise Exception('an error that may be thrown')
@property
def but_this_is_okay(self):
if True:
raise Exception('an error that may be thrown')
如果存在用
@property
修饰的方法,则检查类的方法将导致错误,但前提是它在第一个缩进级别引发错误。
怎么会这样?我该如何解决这个问题?
附注我这样检查的原因是我试图按照类中定义的顺序获取类方法(实际可调用对象)的数组。
但是您实际上并没有在类上调用
inspect.getmembers
,因为 self
指的是类的实例。错误会发生,因为它将尝试使用 getattr
getter(您可以从 Traceback
推断出),并且考虑到 SomeClass().this_is_not_okay
将有效地引发异常,这将破坏 inspect.getmembers
。这实际上是一个已知问题,自 2018 年以来一直处于开放状态。此外,您的断言“但仅当它在第一个缩进级别引发错误时”是不正确的,因为inspect.getmembers
只是在早些时候因异常而中止this_is_not_okay
(尽管将条件更改为 if False
会使其起作用,因为它将停止 raise
语句的执行)。
现在,您描述了您的既定目标是获得类中定义事物的顺序,那么,您必须将其传递给类。示例:
import inspect
class SomeClass:
def this_is_okay(self):
raise Exception('an error that may be thrown')
@property
def this_is_not_okay(self):
raise Exception('an error that may be thrown')
@property
def but_this_is_okay(self):
if False:
raise Exception('an error that may be thrown')
some_ins = SomeClass()
print(inspect.getmembers(type(some_ins), predicate=inspect.isfunction))
上面应该产生类似的结果:
[('this_is_okay', <function SomeClass.this_is_okay at 0x7f166ae1a980>)]
inspect.getmembers_static
来代替:
print(inspect.getmembers_static(some_ins, predicate=inspect.isfunction))
这实际上起到了同样的作用。
请注意,我将谓词更改为
inspect.isfunction
,因为类定义通常没有方法,但这些函数通常会成为类实例中的函数,因此区别应该很小。
如果必须使用
inspect.isfunction
谓词,则可能必须获取类实例的每个成员,然后应用所需的过滤。