如何编写(Python模块的)C代码以返回Python迭代器对象? 我在C++中成功编写了一个极简的Python 3.6扩展模块之后,我计划提供一个Python模块,它与下面的Python函数 ItIdieEngMyBuySub(< /代码>:)相同。 def iterUniqueCombos(lstOfSortableItems,sizeOfCombo): lstOfSortedItems=已排序(lstOfSortableItems) sizeOfList=len(lstofsortitems) lstComboCandidate=[] def idxNextUnique(idxItemOfList): idxNextUniqueCandidate=idxItemOfList+1 当( idxNextUniqueCandidate=sizeOfCombo-len(lstcombo候选者): 追加(lstOfSortedItems[idxItemOfList]) 组合产量(idxItemOfList+1) lstComboCandidate.pop() 组合产量(idxNextUnique(idxItemOfList)) 结合产量(0) 我对Python和C++编程有一些基本的了解,但是绝对不知道如何将Python < Stutial>屈服> /Stand >转换成Python扩展模块的C++代码。所以我的问题是: 如何编写(python模块的C++代码)能够返回Python迭代器对象?< /P>

如何编写(Python模块的)C代码以返回Python迭代器对象? 我在C++中成功编写了一个极简的Python 3.6扩展模块之后,我计划提供一个Python模块,它与下面的Python函数 ItIdieEngMyBuySub(< /代码>:)相同。 def iterUniqueCombos(lstOfSortableItems,sizeOfCombo): lstOfSortedItems=已排序(lstOfSortableItems) sizeOfList=len(lstofsortitems) lstComboCandidate=[] def idxNextUnique(idxItemOfList): idxNextUniqueCandidate=idxItemOfList+1 当( idxNextUniqueCandidate=sizeOfCombo-len(lstcombo候选者): 追加(lstOfSortedItems[idxItemOfList]) 组合产量(idxItemOfList+1) lstComboCandidate.pop() 组合产量(idxNextUnique(idxItemOfList)) 结合产量(0) 我对Python和C++编程有一些基本的了解,但是绝对不知道如何将Python < Stutial>屈服> /Stand >转换成Python扩展模块的C++代码。所以我的问题是: 如何编写(python模块的C++代码)能够返回Python迭代器对象?< /P>,python,c,python-3.x,iterator,python-c-extension,Python,C,Python 3.x,Iterator,Python C Extension,欢迎任何提示让我开始 更新(状态2017-05-07): 两个注释:收益率没有C++等价。首先,我将在Python中手动实现迭代器协议,以摆脱屈服和屈服的心态USER245112 4月26日1:16,答案在“丹尼< /代码> >。这个问题的答案与“如何实现一个不使用收益率的迭代器”,而是在C++扩展中,而不是纯Python中一样。通过重写算法代码以消除yield和从头开始编写Python扩展模块的C代码(导致出现分段错误错误),我的编程工作朝着错误的方向重新开始 我目前在这个问题上的最新知识是,

欢迎任何提示让我开始

更新(状态2017-05-07):

两个注释:收益率没有C++等价。首先,我将在Python中手动实现迭代器协议,以摆脱屈服和屈服的心态USER245112 4月26日1:16,答案在“<代码>丹尼< /代码> >。这个问题的答案与“如何实现一个不使用收益率的迭代器”,而是在C++扩展中,而不是纯Python中一样。通过重写算法代码以消除

yield
和从头开始编写Python扩展模块的C代码(导致出现
分段错误
错误),我的编程工作朝着错误的方向重新开始

我目前在这个问题上的最新知识是,使用它可以将上述Python代码(使用
yield
)直接转换为Python扩展模块的C代码。


这不仅可以按原样使用Python代码(无需重写任何内容),但除此之外,Cython通过使用
yield
的算法创建的扩展模块的速度至少是使用
iter
\uuuuuuuuuuuuuuuuuuuuu>重写算法从创建到迭代器类的扩展模块的两倍(如果Python脚本中未添加Cython特定的速度优化代码,则后者有效).Python中的迭代器是生成器的一种特殊形式,由一个类实现,该类包含方法
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

<> P>为了提供一个C++等价物,C++代码需要实现那些与Python函数一致的协议。结果扩展类型是迭代器。

换句话说,这个问题的答案与“如何在不使用<代码>收益率>代码>的情况下实现迭代器”相同,而是在C++扩展中而不是纯Python。对于堆栈溢出,存在几个现有的答案。


注意-
next
是Python3上的
\uuuuuuuuuuuuuuuuuuuuu

这与其说是一个完整的答案,不如说是对你的问题编辑的回应-我同意Danny回答的要点,你需要在一个类中用
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu.在你的编辑中,你断言这一定是可能的,因为Cython能做到。我认为值得一看Cython到底是如何做到的

从一个基本示例开始(选择此示例是因为它有几个不同的
yield
语句和一个循环):

Cython所做的第一件事是定义一个
\uuupyx\uCoroutineObject
C类,该类带有一个
\uupyx\uGenerator\uNext
方法,该方法实现
\uuuuUnext\uUcode>/
Next

  • body
    -实现您定义的逻辑的C函数指针
  • resume\u label
    -一个整数,用于记住您在
    body
  • closure
    -一个自定义创建的C类,用于存储
    正文
    中使用的所有变量
以稍微迂回的方式,
\upyx\u Generator\u Next
调用
body
属性,该属性是您定义的Python代码的翻译

然后,让我们看看分配给
body
的函数是如何工作的——在我的例子中称为
\uuupyx\ugb\u5iters\u2generator
。它做的第一件事是使用
resume\ulabel
跳转到右侧
yield
语句:

switch (__pyx_generator->resume_label) {
    case 0: goto __pyx_L3_first_run;
    case 1: goto __pyx_L4_resume_from_yield;
    case 2: goto __pyx_L5_resume_from_yield;
    case 3: goto __pyx_L8_resume_from_yield;
    case 4: goto __pyx_L9_resume_from_yield;
    default: /* CPython raises the right error here */
    __Pyx_RefNannyFinishContext();
    return NULL;
  }
任何变量赋值都是通过
闭包
结构完成的(本地命名为
\uuuupyx\ucur\u scope

/*     a = 0             # <<<<<<<<<<<<<< */
__pyx_cur_scope->__pyx_v_a = __pyx_int_0
循环稍微复杂一点,但基本上是一样的——它使用
goto
跳入C循环(这是合法的)

最后,一旦到达终点,它将引发
StopIteration
错误:

PyErr_SetNone(PyExc_StopIteration);

总之,Cython做的正是别人建议你做的:它定义
/*     a = 0             # <<<<<<<<<<<<<< */
__pyx_cur_scope->__pyx_v_a = __pyx_int_0
__pyx_generator->resume_label = 1;
return __pyx_r;
PyErr_SetNone(PyExc_StopIteration);