在 IPython 中,我可以通过简单地定义 Cython 类的属性然后调用它来看到它是一个生成器:
%%cython
cdef class SomeCls:
property x:
def __get__(self):
yield 1
调用看起来像
SomeCls().x
# prints <generator at 0x102f61ee8>
我在测试该属性是否是生成器时遇到问题:
import types
print(isinstance(SomeCls().x, types.GeneratorType))
# prints False
import inspect
print(inspect.isgeneratorfunction(SomeCls.x))
# prints False
如何确定 Cython 类的属性是否是生成器?
最佳答案
为什么通常的方法不起作用?
首先,您可能已经知道,inspect.isgeneratorfunction(...)
和 isinstance(..., types.GeneratorType)
之间没有区别 -检查模块只是 calls isinstance(..., types.GeneratorType)
.
另一方面,types.GeneratorType
是 defined as
def _g():
yield 1
GeneratorType = type(_g())
CPython 使用 PyGenObject ( here code 、 here documentation )作为生成器,对于某些 ABC 类没有花哨的比较逻辑,因此 isinstance
将归结为比较 C -对象类型。
但是,Cython 返回 __pyx_CoroutineObject
对于生成器(只需检查 cythonized 代码即可查看)
typedef PyObject *(*__pyx_coroutine_body_t)(PyObject *, PyThreadState *, PyObject *);
typedef struct {
PyObject_HEAD
__pyx_coroutine_body_t body;
PyObject *closure;
...
int resume_label;
char is_running;
} __pyx_CoroutineObject;
就 isinstance
而言,与 PyGenObject
无关 - 它并不真正关心 generator
是否在名称中类型(但对于我们人类来说,这确实令人费解,因为 type(obj)
表示“生成器”)。
因此,您必须推出自己的 isgenerator
版本,其中还考虑了 Cython-“生成器”。方法有很多,例如
%%cython
def _f():
yield 1
CyGeneratorType = type(_f())
def iscygenerator(o):
return isinstance(o, CyGeneratorType)
现在:
import inspect
def isgenerator(o):
return inspect.isgenerator(o) or iscygenerator(o)
isgenerator(SomeCls().x) # True
iscygenerator(SomeCls().x) # True
inspect.isgenerator(SomeCls().x) # False
关于python - 如何测试 Cython 属性是否为生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53420354/