代码之家  ›  专栏  ›  技术社区  ›  user1717828

如何测试cython属性是否为generator?

  •  2
  • user1717828  · 技术社区  · 6 年前

    在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类的属性是否为生成器?

    1 回复  |  直到 6 年前
        1
  •  2
  •   ead    6 年前

    为什么通常的方法不起作用?

    首先,你可能已经知道 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;
    

    与此无关 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