Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a generator not a generator? Why does calling my function with yield not return a generator object sometimes

I have a function (f) with a yield. I have a list (E).
If I try E += f() then f() doesn't return a generator object, but instead runs the function, which throws an exception because some global variables aren't ready.

To forestall any comments, I know E += f() is wrong, but it provides an example for my question. If I do the right thing E += [f()] or E.append(f()) then f() returns a generator object and the code of f() is not evaluated till the generator object's next method is called.

My question is, why is f() being evaluated in the wrong situation at all, and why instead is the exception raised not something along the lines of "function object not iterable".

like image 299
sirlark Avatar asked Dec 17 '22 04:12

sirlark


1 Answers

Because the expression f() calls f, and E += f() will run the generator until its end and append the values it generates to E. It's not "wrong" at all, but it does require a fully working f that yields a finite number of values:

>>> E = [1,2,3]
>>> def f():
...  yield 4
...  yield 5
...
>>> E += f()
>>> E
[1, 2, 3, 4, 5]

By contrast, E += [f()] will call f, but then stops before the first line of the code because then the interpreter has a complete enough object, namely the generator object, to store in the single-element list [f()]. Only later, when you request more elements from E[-1], will code up to the first yield run and the exception be raised.

like image 199
Fred Foo Avatar answered Dec 18 '22 16:12

Fred Foo