[Tutor] Generator next()

Steven D'Aprano steve at pearwood.info
Sun Dec 29 13:38:28 CET 2013


Last one!

On Sun, Dec 29, 2013 at 01:57:31AM -0500, Keith Winston wrote:

> In the previous timer function that I was using, it defined a timer class,
> and then I had to instantiate it before I could use it, and then it saved a
> list of timing results. I think in yours, it adds attributes to each
> instance of a function/method, in which the relevant timings are stored. 

Correct. Rather than dump those attributes on the original function, it 
creates a new function and adds the attributes to that. The new function 
wraps the older one, that is, it calls the older one:

def f(x):
    return g(x)

We say that "f wraps g". Now, obviously wrapping a function just to 
return its result unchanged is pretty pointless, normally the wrapper 
function will do something to the arguments, or the result, or both. 
Otherwise why bother?

> I guess that's just an observation, I've played with it a bit and it's
> interesting. You said you didn't like the prior implementation, I'd be
> interested in anything further you have to say about why: 

I find it too complicated for something that shouldn't be that 
complicated.


> specifically, you
> called it a coroutine, and a "decorator factory" (tell me you made that
> up). Any more on that?

After my previous two emails, you should have an idea of what a factory 
is by now: it's a function that returns a new function. So a decorator 
factory is a function that returns a decorator. What's a decorator? In 
this context, it's a function that takes a function as argument and 
wraps it in another function.

So here we have a function A which creates a function B which takes as 
argument a function C and returns another function D which wraps 
(decorates) C.

That's actually not the complicated part. The complicated part is that 
it uses coroutines instead of normal function calls. What's a coroutine, 
I hear you ask? Don't ask.

Actually, I can give a quick and dirty explanation of coroutines. In a 
normal function, you have one entry point, calling the function, and 
at least one exit point (a return statement, or falling off the end of 
the function when there's nothing more to do). We enter the function at 
the top, and run the code inside it until we get to the end, then we 
finish:

def test():
    do_this()  # runs first
    do_that()  # runs second
    do_more()  # runs third
    # nothing more to do, the function exits


In a coroutine, you don't have a single entry point, you have multiple 
entry points, and you use the "send" method to feed values into the 
coroutine, and get values back. This makes them very powerful. For 
something as simple as timing instrumentation, too powerful -- it's 
using a nuclear-powered bulldozer to nudge your mouse an inch to the 
left.



-- 
Steven


More information about the Tutor mailing list