Nope. Like so:
>>> def test():
... x = 0
... while True:
... x += 1
... yield x
...
>>> type(test)
<type 'function'>
So what it returns is a function object. Details from there get hairy; the short course is that the code object belonging to the function (test.func_code
) is marked as a generator by one of the flags in test.func_code.co_flags
.
You can disassemble the bytecode for test
to see that it's just like any other function otherwise, apart from that a generator function always contains a YIELD_VALUE
opcode:
>>> import dis
>>> dis.dis(test)
2 0 LOAD_CONST 1 (0)
3 STORE_FAST 0 (x)
3 6 SETUP_LOOP 25 (to 34)
>> 9 LOAD_GLOBAL 0 (True)
12 POP_JUMP_IF_FALSE 33
4 15 LOAD_FAST 0 (x)
18 LOAD_CONST 2 (1)
21 INPLACE_ADD
22 STORE_FAST 0 (x)
5 25 LOAD_FAST 0 (x)
28 YIELD_VALUE
29 POP_TOP
30 JUMP_ABSOLUTE 9
>> 33 POP_BLOCK
>> 34 LOAD_CONST 0 (None)
37 RETURN_VALUE
To do it the way you have in mind, the horrors just start ;-) if you think about how to create an object to mimic just this:
def test():
yield 2
yield 3
yield 4
Now your next()
method would have to carry additional hidden state just to remember which yield
comes next. Wrap that in some nested loops with some conditionals, and "unrolling" it into a single-entry next()
becomes a nightmare.