如何测试 Cython 属性 是否为生成器?
How to test if Cython property is generator?
在IPython中,我可以看到一个Cython class的属性是一个生成器,只需定义它然后调用:
%%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 class 的 属性 是否是生成器?
为什么通常的方法不起作用?
首先,您可能已经知道,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 returns 一个 __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)
说 "generator")。
因此您将不得不推出自己的 isgenerator
版本,这也考虑到了 Cython-"generators"。方法有很多种,比如
%%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
在IPython中,我可以看到一个Cython class的属性是一个生成器,只需定义它然后调用:
%%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 class 的 属性 是否是生成器?
为什么通常的方法不起作用?
首先,您可能已经知道,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 returns 一个 __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)
说 "generator")。
因此您将不得不推出自己的 isgenerator
版本,这也考虑到了 Cython-"generators"。方法有很多种,比如
%%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