[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