473,804 Members | 3,126 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Why don't generators execute until first yield?

Hi!

First a bit of context.

Yesterday I spent a lot of time debugging the following method in a
rather slim database abstraction layer we've developed:

,----
| def selectColumn(se lf, table, column, where={}, order_by=[], group_by=[]):
| """Performs a SQL select query returning a single column
|
| The column is returned as a list. An exception is thrown if the
| result is not a single column."""
| query = build_select(ta ble, [column], where, order_by, group_by)
| result = DBResult(self.r awQuery(query))
| if result.colcount != 1:
| raise QueryError("Que ry must return exactly one column", query)
| for row in result.fetchAll RowsAsList():
| yield row[0]
`----

I'd just rewritten the method as a generator rather than returning a
list of results. The following test then failed:

,----
| def testSelectColum nMultipleColumn s(self):
| res = self.fdb.select Column('db3ut1' , ['c1', 'c2'],
| {'c1':(1, 2)}, order_by='c1')
| self.assertRais es(db3.QueryErr or, self.fdb.select Column,
| 'db3ut1', ['c1', 'c2'], {'c1':(1, 2)}, order_by='c1')
`----

I expected this to raise a QueryError due to the result.colcount != 1
constraint being violated (as was the case before), but that isn't the
case. The constraint it not violated until I get the first result from
the generator.

Now to the main point. When a generator function is run, it immediately
returns a generator, and it does not run any code inside the generator.
Not until generator.next( ) is called is any code inside the generator
executed, giving it traditional lazy evaluation semantics. Why don't
generators follow the usual eager evaluation semantics of Python and
immediately execute up until right before the first yield instead?
Giving generators special case semantics for no good reason is a really
bad idea, so I'm very curious if there is a good reason for it being
this way. With the current semantics it means that errors can pop up at
unexpected times rather than the code failing fast.

Martin
Jun 27 '08
13 1823
On May 7, 7:37*am, Marco Mariani <ma...@sferacar ta.comwrote:
Duncan Booth wrote:
Perhaps if you'd copied all of my code (including the decorator that was
the whole point of it)...

Sure, I missed the point. Python's symbols become quoting levels and
mess up messages.

Anyway, I would loathe to start execution of a generator before starting
to iterate through it. Especially when generators are passed around.
The current behavior makes perfect sense.
Question:
>>def f( ):
... print 0
... while 1:
... yield 1
...
>>g= f( )
g.next( )
0
1
>>g.next( )
1
>>g.next( )
1

This might fit the bill:
>>def dropfirst( h ):
... h.next( )
... return h
...
>>g= dropfirst( f( ) )
0
>>g.next( )
1
>>g.next( )
1
>>g.next( )
1

However as dropfirst is dropping a value, both caller -and- cally have
to designate a/the exception. Hold generators are better "first-
dropped", and you hold 'next' inherently causes side effects. @greedy
(from earlier) frees the caller of a responsibility/obligation.

What can follow without a lead?

The definitions may lean harder on the 'generation' as prior to the
'next': generators inherently don't cause side effects.

Or hold, first-dropped is no exception:
>>special= object( )
def f( ):
... print 0
... yield special
... while 1:
... yield 1
...
>>g= f( )
g.next( )
0
<object object at 0x00980470>
>>g.next( )
1
>>g.next( )
1
>>g.next( )
1
Jun 27 '08 #11
Now to the main point. When a generator function is run, it immediately
returns a generator, and it does not run any code inside the generator.
Not until generator.next( ) is called is any code inside the generator
executed, giving it traditional lazy evaluation semantics. Why don't
generators follow the usual eager evaluation semantics of Python and
immediately execute up until right before the first yield instead?
Giving generators special case semantics for no good reason is a really
bad idea, so I'm very curious if there is a good reason for it being
this way. With the current semantics it means that errors can pop up at
unexpected times rather than the code failing fast.
The semantics of a generator are very clear: on .next(), run until the next
yield is reached and then return the yielded value. Plus of course the
dealing with StopIteration-stuff.

Your scenario would introduce a special-case for the first run, making it
necessary to keep additional state around (possibly introducing GC-issues
on the way), just for the sake of it. And violate the lazyness a generator
is all about. Think of a situation like this:

def g():
while True:
yield time.time()

Obviously you want to yield the time at the moment of .next() being called.
Not something stored from ages ago. If anything that setups the generator
shall be done immediatly, it's easy enough:

def g():
first_result = time.time()
def _g():
yield first_result
while True:
yield time.time()
return _()

Diez
Jun 27 '08 #12
Martin Sand Christensen wrote:
Why don't
generators follow the usual eager evaluation semantics of Python and
immediately execute up until right before the first yield instead?
A great example of why this behavior would defeat some of the purpose of
generators can be found in this amazing PDF presentation:

http://www.dabeaz.com/generators/Generators.pdf
Giving generators special case semantics for no good reason is a really
bad idea, so I'm very curious if there is a good reason for it being
this way. With the current semantics it means that errors can pop up at
unexpected times rather than the code failing fast.
Most assuredly they do have good reason. Consider the cases in the PDF
I just mentioned. Building generators that work on the output of other
generators allows assembling entire pipelines of behavior. A very
powerful feature that would be impossible if the generators had the
semantics you describe.

If you want generators to behave as you suggest they should, then a
conventional for x in blah approach is likely the better way to go.

I use a generator anytime I want to be able to iterate across something
that has a potentially expensive cost, in terms of memory or cpu, to do
all at once.
Jun 27 '08 #13
On May 7, 4:51*pm, Michael Torrie <torr...@gmail. comwrote:
Martin Sand Christensen wrote:
Why don't
generators follow the usual eager evaluation semantics of Python and
immediately execute up until right before the first yield instead?

A great example of why this behavior would defeat some of the purpose of
generators can be found in this amazing PDF presentation:

http://www.dabeaz.com/generators/Generators.pdf
Giving generators special case semantics for no good reason is a really
bad idea, so I'm very curious if there is a good reason for it being
this way. With the current semantics it means that errors can pop up at
unexpected times rather than the code failing fast.

Most assuredly they do have good reason. *Consider the cases in the PDF
I just mentioned. *Building generators that work on the output of other
generators allows assembling entire pipelines of behavior. *A very
powerful feature that would be impossible if the generators had the
semantics you describe.

If you want generators to behave as you suggest they should, then a
conventional for x in blah approach is likely the better way to go.

I use a generator anytime I want to be able to iterate across something
that has a potentially expensive cost, in terms of memory or cpu, to do
all at once.
The amount of concentration you can write in a program in a sitting
(fixed amount of time) is kind of limited. Sounds like @greedy was
the way to go. The recall implementation may have a short in the
future, but isn't functools kind of full? Has wraptools been
written? Is it any different?

Naming for @greedy also comes to question. My humble opinion muscles
glom on to @early vs. @late; @yieldprior; @dropfirst; @cooperative.
Thesaurus.com adds @ahead vs. @behind.

Jun 27 '08 #14

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

Similar topics

23
3740
by: Francis Avila | last post by:
Below is an implementation a 'flattening' recursive generator (take a nested iterator and remove all its nesting). Is this possibly general and useful enough to be included in itertools? (I know *I* wanted something like it...) Very basic examples: >>> rl = , '678', 9]] >>> list(flatten(rl)) >>> notstring = lambda obj: not isinstance(obj, type(''))
9
2691
by: Francis Avila | last post by:
A little annoyed one day that I couldn't use the statefulness of generators as "resumable functions", I came across Hettinger's PEP 288 (http://www.python.org/peps/pep-0288.html, still listed as open, even though it's at least a year old and Guido doesn't seem very hot on the idea). I'm not too sure of its ideas on raising exceptions in generators from outside (although it looks like it might be convenient in some cases), but being able...
3
1653
by: David Stockwell | last post by:
Hi, Section 9.10 of the tutorial discusses the yield keyword. When I tried using it I get the following SyntaxError. What does this error mean? Does it mean we can't use yield in our code? Is yield a form of a 'return' ?? class9.py:71: Warning: 'yield' will become a reserved keyword in the future File "class9.py", line 71
1
1949
by: fishboy | last post by:
Howdy, I'm in middle of a personal project. Eventually it will download multipart binary attachments and look for missing parts on other servers. And so far I've got it to walk a newsgroup and download and decode single part binaries. I thought I'd post the code and see what people think. I'd appreciate any feedback. It's my first program with generators and I'm worried I'm making this twice and hard as it needs to be.
0
1869
by: fishboy | last post by:
Howdy, Sorry if this is a double post. First try seemed to go into hyperspace. I'm working on a personal project. It's going to be a multipart binary attachment downloader that will search alternate servers for missing pieces. This is the working code so far. It will walk a newsgroup and download and decode all the single part attachments. Just change server,user,password,group at the bottom to something less
8
2263
by: Timothy Fitz | last post by:
It seems to me that in python, generators are not truly coroutines. I do not understand why. What I see is that generators are used almost exclusively for generation of lists just-in-time. Side effects are frowned upon. Coroutines, in contrast, are like split functions where side effects are often as important or more important than return values. I am currently writing a real time strategy game where I have visual effects and use...
24
3969
by: Lasse Vågsæther Karlsen | last post by:
I need to merge several sources of values into one stream of values. All of the sources are sorted already and I need to retrieve the values from them all in sorted order. In other words: s1 = s2 = s3 = for value in ???(s1, s2, s3):
6
4535
by: Talin | last post by:
I've been using generators to implement backtracking search for a while now. Unfortunately, my code is large and complex enough (doing unification on math expressions) that its hard to post a simple example. So I decided to look for a simpler problem that could be used to demonstrate the technique that I am talking about. I noticed that PEP 255 (Simple Generators) refers to an implementation of the "8 Queens" problem in the lib/test...
18
4571
by: jess.austin | last post by:
hi, This seems like a difficult question to answer through testing, so I'm hoping that someone will just know... Suppose I have the following generator, g: def f() i = 0 while True: yield i
0
9575
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10564
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
10320
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...
0
10073
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9134
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...
0
6846
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
5513
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5645
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4288
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

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.