Okay, I have a generator function (a function which uses the yield statement).
Specifically, it is a part of a Cythonized thing I'm working on to have Python play Sudoku. (Yes, that is trivial, but it's what I'm working on right now and it is relevant to other things.)
That's part 1 of establishing context. Part 2 is that the Sudoku grid is stored as a list of lists of Cells (extension type because I can do so, for this it might as well be a smart integer that can work out what it could, and even should, be based on the other instances that have been fed to it - anyway).
Here's the portion of the code in question:
cpdef box_gen(self):
cdef:
unsigned char y1, x, y2
list box
for y1 in range(0,9,3):
for x in range(0,9,3):
box = []
for y2 in range(y1,y1+3):
box.extend(self.grid[y2][x:x+3])
yield [cell.c for cell in box]
cpdef row_gen(self):
cdef:
list row
for row in self.grid:
yield [x.c for x in row]
cpdef col_gen(self):
cdef:
char i
for i in range(9):
yield [row[i].c for row in self.grid]
Oh, also, the numeric value of a Cell (or 0 if they has yet to be determined or assigned) is stored in the attribute 'c'.
So: what should I type these functions as? Is there a type I need to cimport from cpython? Is there something I need to grap using a cdef extern
block?
Thanks for your time.
This doesn't work - you can only use generators with def
functions.
To explain why it doesn't really make sense for them to work with cdef
functions: cdef
functions produce something that can be directly translated into a C function signature
cdef int f(float y):
#...
becomes (with some name mangling)
int f(float y) {
// ...
}
Generators (and also inner functions) by necessity have some internal state to keep track of where in the closure it is and what variables have been changed. This would be represented in C as at least two functions
some_opaque_structure_type* prepare_generator_f(float y) {
// ...
}
int use_generator_f(some_opaque_structure_type* s) {
// ...
}
(And this ignores how to signal that iteration has finished, or how to pass data back into the iterator, or the result = yield from some_other_generator
syntax)
Although none of this would be impossible to implement, it would break the link of "cdef
functions have a clear C signature and thus can be passed as a C function pointer or readily be used by user-defined C code". cdef
functions have a set of limitations that enable them to be called slightly more efficiently from Cython, and thus it makes sense that they can't do everything that Python def
functions can do.
Just use a def
function.