473,788 Members | 2,811 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Nested generator caveat

I met the following surprising behaviour
>>def gen0():
.... for i in range(3):
.... def gen1():
.... yield i
.... yield i, gen1()
....
>>for i,g in gen0(): print i, g.next()
....
0 0
1 1
2 2
>>for i,g in list(gen0()): print i, g.next()
....
0 2
1 2
2 2
If this is not a bug, it is at least quite confusing.
The apparent reason is that the free variables in
nested generator definitions are not bound (to a value) at invocation
time but only at access time.
Almost surely, the same applies to all locally defined functions
with free variables.
This would mean that locally defined functions with free
variables are very risky in generators.
--
Dieter
Jul 4 '08 #1
3 1909
On Jul 3, 9:20*pm, "Dieter Maurer" <die...@handsha ke.dewrote:
The apparent reason is that the free variables in
nested generator definitions are not bound (to a value) at invocation
time but only at access time.
<YawnThat's what it is supposed to do. Welcome to a dynamic
language.
Raymond
Jul 4 '08 #2
Dieter Maurer <di****@handsha ke.dewrote:
I met the following surprising behaviour
[code moved until later...]
The apparent reason is that the free variables in nested generator
definitions are not bound (to a value) at invocation time but only at
access time.
No. This is about the difference between binding and assignment.
Unfortunately, Python doesn't have explicit syntax for doing the former.

Here's what's actually going on in your generator.
>>>def gen0():
... for i in range(3):
... def gen1():
... yield i
... yield i, gen1()
The function gen0 contains a yield statement; it's therefore a
generator. It contains an assignment to a variable i (in this case,
it's implicit in the `for' loop). So, on entry to the code, a fresh
location is allocated, and the variable i is bound to it.

The function gen1 contains a yield statement too, so it's also a
generator. It contains a free reference to a variable i, so it shares
the binding in the outer scope.

Here's the important part: the for loop works by assigning to the
location named by i each time through. It doesn't rebind i to a fresh
location. So each time you kick gen1, it produces the current value of
i at that time. So...
>>>for i,g in gen0(): print i, g.next()
0 0
1 1
2 2
Here, the for loop in gen0 is suspended each iteration while we do some
printing. So the variable i (in gen0) still matches the value yielded
by gen0.

But...
>>>for i,g in list(gen0()): print i, g.next()
0 2
1 2
2 2
Here, gen0 has finished all of its iterations before we start kicking
any of the returned generators. So the value of i in gen0 is 2 (the
last element of range(3)).
Almost surely, the same applies to all locally defined functions
with free variables.
This would mean that locally defined functions with free
variables are very risky in generators.
It means that you must be careful about the difference between binding
and assignment when dealing with closures of whatever kind.

Here's an example without involving nested generators.

def gen():
for i in xrange(3):
yield lambda: i
for f in gen(): print f()
for f in list(gen()): print f()

To fix the problem, you need to arrange for something to actually rebind
a variable around your inner generator on each iteration through. Since
Python doesn't have any mechanism for controlling variable binding other
than defining functions, that's what you'll have to do.

def genfix():
for i in xrange(3):
def bind(i):
def geninner():
yield i
return geninner()
yield i, bind(i)

shows the general pattern, but since a generator has the syntactic form
of a function anyway, we can fold the two together.

def genfix2():
for i in xrange(3):
def geninner(i):
yield i
yield i, geninner(i)

Yes, this is cumbersome. A `let' statement would help a lot. Or
macros. ;-)

-- [mdw]
Jul 6 '08 #3
Excellent explanation by Mark Wooding. I would only like to add that
the standard pythonic idiom in such cases seems to be the (ab)use of a
default argument to the function, because these get evaluated at the
definition time:
def gen0():
for i in range(3):
def gen1(i = i):
yield i
yield i, gen1()
Jul 7 '08 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
5119
by: Oleg Leschov | last post by:
Could there be means of exiting nested loops in python? something similar to labelled loops in perl.. I consider it irrating to have to make a flag for sole purpose of checking it after loop if we need to break once more... So maybe there should be an argument to break that is an int which is a number of loops to break. So it would default to 1 (or whatever means the current enclosing loop), not breaking any code...
0
1886
by: Francis Avila | last post by:
A few days ago (see the 'itertools.flatten()?' thread from October 28) I became obsessed with refactoring a recursive generator that yielded the leaves of nested iterables. When the dust settled, I had many flatten functions at hand. So I had to time them. Results below. History of the functions (from flattrial.py): # There are three basic features:
1
10635
by: boris bass | last post by:
Below is linenumbered as well as original code -------------------------------------- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META http-equiv=Content-Type content="text/html; charset=windows-1255"> <META content="Microsoft FrontPage 5.0" name=GENERATOR></HEAD> <BODY text="#525252" vLink="#6666ae" aLink="#6666ae" link="#6666ae"
7
2658
by: aurora | last post by:
I love generator and I use it a lot. Lately I've been writing some recursive generator to traverse tree structures. After taking closer look I have some concern on its performance. Let's take the inorder traversal from http://www.python.org/peps/pep-0255.html as an example. def inorder(t): if t: for x in inorder(t.left):
20
1864
by: Jack | last post by:
Hi all, I need to do syntax parsing of simple naturual languages, for example, "weather of London" or "what is the time", simple things like these, with Unicode support in the syntax. In Java, there are JavaCC, Antlr, etc. I wonder what people use in Python? Antlr also has Python support but I'm not sure how good it is. Comments/hints are welcome.
16
2253
by: koutoo | last post by:
I start my code with some constants then a while statement. But I have some For statements towards the end within the While statement where I start getting some errors. I'm hoping I won't have to post my code, but it looks something like this: Import os, string while this: All Code indented like it should
4
2315
by: Wolfgang Draxinger | last post by:
If you know languages like Python or D you know, that nested functions can be really handy. Though some compilers (looking at GCC) provide the extension of nested functions, I wonder, how one could implement an equivalent behaviour with plain C (in this case I'm thinking of the language I'm developing, which shall be converted into C for target compilation). So far I didn't touch the topic "nested functions", since I just don't see an...
0
200
by: Maric Michaud | last post by:
Le Tuesday 12 August 2008 11:29:18 Cousson, Benoit, vous avez écrit : This is a language limitation. This is because nested scope is implemented for python function only since 2.3 allow late binding of free variables. the scope in class statment is not a closure, so there is only two possible scope in it : local and global. When "class C2(C1):" statment is interpreted, it is in the scope of class B for which a name C1 exists, but it...
0
154
by: Cousson, Benoit | last post by:
This is a language limitation. That was my understanding as well, but I think it is a pity to have that limitation. Don't you think that the same improvement that was done for method nested scope could be done as well for nested class? I can easily fix my current issue by doing the binding after the class declaration. My concern is more about the lack of symmetry of that approach; meaning that if both classes are in the global scope, one...
0
9656
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
10364
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10172
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10110
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8993
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7517
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6750
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5536
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
3670
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.