Coroutines: unexpected behaviour

Thomas Jollans thomas at jollans.com
Wed Jun 16 08:35:10 EDT 2010


On 06/16/2010 02:03 PM, Jérôme Mainka wrote:
> Hello,
> 
> I try to experiment with coroutines and I don't understand why this
> snippet doesn't work as expected... In python 2.5 and python 2.6 I get
> the following output:
> 
> 0
> Exception exceptions.TypeError: "'NoneType' object is not callable" in
> <generator object at 0x7e43f8> ignored
> 
> The TypeError exception comes from the pprint instruction...
> 
> If i replace the main part with:
> 
> ==
> p1 = dump()
> p2 = sort(p1)
> for item in my_list: p2.send(item)
> ==
> 
> it works as expected.

What a strange problem. I hope somebody else can shed more light on what
is going on

Anyway, it appears (to me) to be a scoping issue: if you move
"from pprint import pprint" into the dump() function body, it works. I
don't understand why this changes anything: pprint was in the global
namespace all along, and it's present and functioning exactly *once*,
after which it's None. It's still there, otherwise there'd be a
NameError, but it was set to None without any line of code doing this
explicitly as far as I can see.

Another VERY strange thing is, of course, your "fix": renaming "p" to
"p2" helps. "p", "p1", "p3", and "yyy" are just some examples of
variable names that don't work.

As for Python versions: I changed the code to work with Python 3 and get
the same odd behaviour.

> 
> I don't understand what is goind wrong. Has someone an explanation for
> this issue?
> 
> Thanks,
> 
> Jérôme
> 
> 
> ===
> from functools import wraps
> from pprint import pprint
> import random
> 
> def coroutine(f):
>     @wraps(f)
>     def start(*args, **kwargs):
>         res = f(*args, **kwargs)
>         res.next()
>         return res
>     return start
> 
> @coroutine
> def sort(target):
>     l = []
> 
>     try:
>         while True:
>             l.append((yield))
>     except GeneratorExit:
>         l.sort()
>         for item in l:
>             target.send(item)
> 
> @coroutine
> def dump():
>     while True:
>         pprint((yield))
> 
> if __name__ == "__main__":
>     my_list = range(100)
>     random.shuffle(my_list)
> 
>     p = sort(dump())
> 
>     for item in my_list:
>         p.send(item)




More information about the Python-list mailing list