2017-04-26 3 views
2

++ (see here) 나는 다음과 같은 파이썬 기능 iterUniqueCombos()와 동일하게 수행하는 파이썬 모듈 제공 할 계획 :Python iterator 객체를 반환 할 수있는 (파이썬 모듈의) C 코드를 작성하는 방법은 무엇입니까? 내가 곧 C에서 최소한의 Python3.6 확장 모듈을 서면으로 성공 후

def iterUniqueCombos(lstOfSortableItems, sizeOfCombo): 
    lstOfSortedItems = sorted(lstOfSortableItems) 
    sizeOfList = len(lstOfSortedItems) 

    lstComboCandidate = [] 

    def idxNextUnique(idxItemOfList): 
     idxNextUniqueCandidate = idxItemOfList + 1 

     while (
       idxNextUniqueCandidate < sizeOfList 
        and 
       lstOfSortedItems[idxNextUniqueCandidate] == lstOfSortedItems[idxItemOfList] 
     ): # while 
      idxNextUniqueCandidate += 1 

     idxNextUnique = idxNextUniqueCandidate 

     return idxNextUnique 

    def combinate(idxItemOfList): 
     if len(lstComboCandidate) == sizeOfCombo: 
      yield tuple(lstComboCandidate) 
     elif sizeOfList - idxItemOfList >= sizeOfCombo - len(lstComboCandidate): 
      lstComboCandidate.append(lstOfSortedItems[idxItemOfList]) 
      yield from combinate(idxItemOfList + 1) 
      lstComboCandidate.pop() 
      yield from combinate(idxNextUnique(idxItemOfList)) 

    yield from combinate(0) 

나는 몇 가지 기본이를 파이썬과 C++ 프로그래밍에 대한 이해는 있지만, 파이썬 (Pythons) 으로 변환하는 방법은 파이썬 확장 모듈의 C++ 코드로 절대 이해할 수 없습니다. 내 질문은 :

How to write C++ code (of a Python module) able to return a Python iterator object?

나를 시작하는 데 도움이되는 모든 의견을 환영합니다.

UPDATE (상태 2017년 5월 7일) :

주석 둘 : 수율이 더 C++ 해당이 없습니다. 필자는 Python에서 반복자 프로토콜을 수동으로 구현하여 마인드에서 수익률과 수익률을 극복하기 시작했다. - user2357112 Apr 26 at 1:16 그리고 대답의 힌트는 danny입니다.이 질문에 대한 대답은 'yield를 사용하지 않고 반복자를 구현하는 방법은 무엇인가'와 같지만 순수 Python 대신 C++ 확장을 묻는 것과 같습니다.yield을 제거하고 Python 확장 모듈의 C 코드를 처음부터 작성하여 (Segmentation Fault 오류가 발생 했음) 알고리즘 코드를 다시 작성하여 휠을 다시 작성하는 잘못된 방향으로 프로그래밍 작업을했습니다.

The state-of-the-art of my current knowledge on the subject of the question is that using Cython it is possible to translate the above Python code (which is using yield) directly into C code of a Python extension module.

이것은 (아무것도 재 작성 필요없이)는 그대로 파이썬 코드를 사용하지 않는 경우에만 가능하지만,에 yield 실행을 사용하여 알고리즘에서 사이 썬에 의해 생성 된 확장 모듈의 속도에 추가 __iter____next__ 다시 작성 알고리즘 (Cython 특정 속도 최적화 코드가 Python 스크립트에 추가되지 않은 경우 후자는 유효 함)을 사용하여 반복 모듈에 생성 된 확장 모듈의 최소 두 배 이상.

+1

'yield'에는 C++가 없습니다. 먼저 [iterator 프로토콜을 수동으로 구현] (https : //www.python.org/dev/peps/pep-0234 /)를 파이썬에서 사용하면 마인드 세트에서 'yield'와 'yield'를 벗어날 수 있습니다. – user2357112

답변

1

이것은에 __next__ 더 완전한 해답보다는 질문 편집에 대한 응답 - 나는 당신이 클래스에서이를 구현하는 데 필요한, 대니의 대답의 요지에 동의 __next__/next 메소드 (파이썬 버전에 따라 다름). 편집에서는 Cython이 그것을 할 수 있기 때문에 가능해야한다고 주장합니다.Cython이 어떻게하는지 정확하게 볼 가치가 있다고 생각했습니다. (그것은 몇 가지 yield 제표 및 루프를 가지고 있기 때문에 픽업) 기본 예제와

시작 :

def basic_iter(n): 
    a = 0 
    b = 5 
    yield a 
    a+=3 
    yield b 
    b+=2 

    for i in range(n): 
     yield a+b+n 
     a = b+1 
     b*=2 
    yield 50 

사이 썬가하는 첫 번째 일은 __next__를 구현하는 __Pyx_Generator_Next 방법으로 __pyx_CoroutineObject C 클래스를 정의입니다/next. __pyx_CoroutineObject의 몇 가지 관련 속성 :

  • body

    - 당신이 정의한 논리를 구현하는 C 함수 포인터.
  • resume_label
  • 은 - body 내에서 사용되는 모든 변수를 저장하는 사용자 정의 만든 C 클래스 - 정수는 body
  • closure에 의해 정의 된 기능에있어 얼마나 기억하는 데 사용됩니다. 약간 로터리 방식으로

__Pyx_Generator_Next 당신이 정의한 파이썬 코드로 번역되어있는 body 속성을 호출합니다.

body에 할당 된 기능 (예 : __pyx_gb_5iters_2generator)의 작동 방식을 살펴 보겠습니다.

/*  a = 0    # <<<<<<<<<<<<<< */ 
__pyx_cur_scope->__pyx_v_a = __pyx_int_0 

yieldresume_label과를 설정

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; 
    } 

모든 변수 할당 로컬 __pyx_cur_scope에라는 closure 구조 (를 통해 수행된다 : 그것은 수행하는 첫 번째 일은 올바른 yield 문으로 이동합니다 resume_label를 사용하다 반환 (다음 번에 다시 점프 할 수 있도록 resume_label).

__pyx_generator->resume_label = 1; 
return __pyx_r; 

루프는 약간 더 복잡하지만 기본적으로는 동일합니다. goto을 사용하여 C 루프로 건너 뜁니다 (이는 합법입니다). 그 끝에 도달 된 후에는

마지막으로,이 StopIteration 오류가 발생합니다 : 그것은 __next__ 또는 next으로 클래스를 정의

PyErr_SetNone(PyExc_StopIteration); 
요약

, 사이 썬은 당신이 할 것을 권고했습니다 정확히 수행 메서드를 호출하고 해당 클래스를 사용하여 상태를 추적합니다. 자동으로 수행되므로 참조 횟수를 추적하는 데 상당히 도움이되므로 사용자가 경험 한 오류 Segmentation Fault을 피할 수 있습니다. 이전 실행 지점으로 돌아가려면 goto을 사용하는 것이 효율적이지만주의가 필요합니다.

하나의 __next__/ next 기능의 측면에서 C에서 발전기 기능을 재 작성 이유를 볼 수

는 간청하고, 사이 썬은 분명히 자신을 C 작성하지 않고 그 일을하는 간단한 방법을 제공하지만 특별한 기술을 사용하지 않습니다 이미 들었던 것을 바탕으로 번역을해야합니다.

+0

당신은 다음과 같이 씁니다 :'Cython은 직접 C를 쓰지 않고 직접 할 수있는 명확한 방법을 제공하지만, 이미 들었던 것을 바탕으로 특별한 기술을 사용하지는 않습니다. ' 내가 당신의 답을 이해했다면), Cython이 파이썬의 'yield'를 적절한 C 상응하는 것으로 변환하기 위해 사용하는 특별한 기술을 설명해주십시오 : 반복문의 상태가 'goto' 문으로 전환되는 것을 사용하십시오. 특별한 '폐쇄'구조를 유지했다. – Claudio

+1

당신은 그것을 올바르게 이해합니다. 제 말은 당신이 스스로 쓸 수있는 것이 아무것도 아니라고 생각합니다. 나는 C 프로그래머에게 파이썬 생성기처럼 작동하도록 여러 번 호출 할 수있는 함수를 작성하는 문제를 제기했다면 아마 비슷한 (아마도 'goto'를 피하는) 것을 생각해 냈을 것이다. 어쨌든 - 저는 주로 Cython이 어떻게 작동하는지 살펴볼 가치가 있다고 생각했습니다. 복사 할 수있는 유용한 메커니즘을 보여 주거나 직접 작성하지 말고 Cython을 사용해야합니다 (두 가지 모두 괜찮은 결과입니다) – DavidW

+0

이 컨텍스트에서 파이썬 인터프리터는 자신의 C 코드를 사용합니다. Cython이 파이썬이 어떻게 동작 하는지를 복사한다면 나는 놀랄 것입니다. – Claudio

1

파이썬의 반복자는 발전기의 특별한 형태 및 방법을 __iter__next를 포함하는 클래스에 의해 구현된다 __iter__ 반환 selfnext 반환 반복의 끝에 StopIteration을 제기 차례로 각 값 - see PEP.

C++ 코드를 제공하려면 C++ 코드가 프로토콜과 일치하는 동일한 파이썬 함수를 구현해야합니다. 결과 확장 유형은 반복자입니다. 즉

는이 질문에 대한 대답은 대신 순수한 파이썬의 C++에서 확장 '나는 yield를 사용하지 않고 반복자를 구현하려면 어떻게 '를 묻는 것과 동일합니다. 스택 오버 플로우에 대한 몇 가지 기존 답변이 있습니다.

NB - next 파이썬 3

+0

대답은 'PEP 여기에 설명 된 프로토콜 구현'이라는 주석보다 훨씬 더 자세하게 반복자를 구현하는 방법에 대한 질문에 직접 답합니다. 그러므로 나는 그것이 더 명확하고 적절하다고 느낍니다. 귀하의 질문이 더 이상 적용되지 않거나 귀하가 다른 곳에서 다루어 진 것으로 생각되는 경우, 그러한 부분을 잠그고 업데이트하는 것을 고려하십시오. – danny

+0

답의 마지막 줄을보십시오. – danny

+0

나는 평가자의 결론에 동의한다. 정답은 유효하며 답변에는 위의 답변에없는 추가 관련 정보가 없습니다. – danny

관련 문제