473,804 Members | 2,265 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

StopIteration in the if clause of a generator expression

To confuse a newbies and old hands alike, Bengt Richter wrote:
Need something more straightforward , e.g., a wrapped one-liner:
>>> def guess(n=3): print ("You're right!", 'No more tries for
>>> you!!!')[n-1 in ... (x for x in xrange(n) for t in [raw_input('Gues s my name:
')=='Ben']
... if not t or iter([]).next())]
... >>> guess()
To make it a bit clearer, a StopIteration raised in a generator expression
silently terminates that generator:
def stop(): raise StopIteration .... list(i for i in range(10) if i < 5 or stop()) [0, 1, 2, 3, 4]

In a list comprehension, on the other hand, it is propagated:
[i for i in range(10) if i < 5 or stop()]

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in stop
StopIteration

Is that an intentional difference?

Peter

Jul 18 '05 #1
16 2301
jfj
Peter Otten wrote:
To confuse a newbies and old hands alike, Bengt Richter wrote:
got me for one:)


To make it a bit clearer, a StopIteration raised in a generator expression
silently terminates that generator:


*any* exception raised from a generator, terminates the generator
jfj
Jul 18 '05 #2
Peter Otten wrote:
To confuse a newbies and old hands alike, Bengt Richter wrote:
Need something more straightforward , e.g., a wrapped one-liner:
>>> def guess(n=3): print ("You're right!", 'No more tries for
>>> you!!!')[n-1 in ... (x for x in xrange(n) for t in [raw_input('Gues s my name:
')=='Ben']
... if not t or iter([]).next())]
...
>>> guess()
To make it a bit clearer, a StopIteration raised in a generator

expression silently terminates that generator:
def stop(): raise StopIteration ... list(i for i in range(10) if i < 5 or stop()) [0, 1, 2, 3, 4]

In a list comprehension, on the other hand, it is propagated:
[i for i in range(10) if i < 5 or stop()]

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in stop
StopIteration

Is that an intentional difference?

Very interesting. I'm not sure if the designers even considered this
particular subtlety. Why it happens is pretty plain. In the generator
expression case, the generator expression does propogate the
StopIteration, but list() traps it. List comprehensions are internally
treated as a for-loop (kind of), which doesn't trap StopIteration.
Maybe it should.

The list comprehension [ x for x in y ] is currently treated as
equivalent to the following, with byte-code optimizations:

.. _ = []
.. for x in y:
.. _.append(x)
Perhaps it ought to be equivalent to:

.. _ = []
.. try:
.. for x in y:
.. _.append(x)
.. except StopIteration:
.. pass
However, I would guess the Python gods wouldn't approve of this use of
StopIteration, and so would make no sacrifices to get it.
Nevertheless, it seems likely to be how a list comprehension would
behave in Python 3.0, so maybe we should do it.
--
CARL BANKS

Jul 18 '05 #3
[Peter Otten]
a StopIteration raised in a generator expression
silently terminates that generator:
def stop(): raise StopIteration ... list(i for i in range(10) if i < 5 or stop()) [0, 1, 2, 3, 4]

In a list comprehension, on the other hand, it is propagated:
[i for i in range(10) if i < 5 or stop()]

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in stop
StopIteration

Is that an intentional difference?


I would call it an unfortunate assymmetry -- one the never comes up unless
you're up to no good ;-)

In a way, both behave identically. They both raise StopIteration. In the case
of the generator expression, that StopIteration is intercepted by the enclosing
list() call. That becomes obvious if you write a pure python equivalent for
list:

def lyst(s):
it = iter(s)
result = []
try:
while 1:
result.append(i t.next())
except StopIteration: # guess who trapped StopIter
return result
Raymond Hettinger

Jul 18 '05 #4
On Fri, 01 Apr 2005 16:34:32 GMT, "Raymond Hettinger" <vz******@veriz on.net> wrote:
[Peter Otten]
a StopIteration raised in a generator expression
silently terminates that generator:
>>> def stop(): raise StopIteration ...
>>> list(i for i in range(10) if i < 5 or stop())

[0, 1, 2, 3, 4]

In a list comprehension, on the other hand, it is propagated:
>>> [i for i in range(10) if i < 5 or stop()]

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in stop
StopIteration

Is that an intentional difference?


I would call it an unfortunate assymmetry -- one the never comes up unless
you're up to no good ;-)

;-)
In a way, both behave identically. They both raise StopIteration. In the case
of the generator expression, that StopIteration is intercepted by the enclosing
list() call. That becomes obvious if you write a pure python equivalent for
list:

def lyst(s):
it = iter(s)
result = []
try:
while 1:
result.append(i t.next())
except StopIteration: # guess who trapped StopIter
return result

I assumed that all standard sequence consumers (including list, of course) would intercept
the StopIteration of a sequence given them in the form of a generator expression, so your
lyst example would have an analogue for other sequence consumers as well, right?
I.e., there's not a hidden list(genex) in those others I would hope ;-)

E.g., "in" in my toy exposed more clearly, using Peter's stop:
def show(x): print x,; return x ... def stop(): raise StopIteration ... 2 in (x for x in xrange(5) if show(x)<4 or stop()) 0 1 2
True 7 in (x for x in xrange(5) if show(x)<4 or stop())

0 1 2 3 4
False

BTW I notice that this also nicely shortcuts when the 2 is found.

Regards,
Bengt Richter
Jul 18 '05 #5
> I assumed that all standard sequence consumers (including list, of course)
would intercept
the StopIteration of a sequence given them in the form of a generator expression, so your lyst example would have an analogue for other sequence consumers as well, right? I.e., there's not a hidden list(genex) in those others I would hope ;-)
Right.
E.g., "in" in my toy exposed more clearly, using Peter's stop:
>>> def show(x): print x,; return x ... >>> def stop(): raise StopIteration ... >>> 2 in (x for x in xrange(5) if show(x)<4 or stop()) 0 1 2
True >>> 7 in (x for x in xrange(5) if show(x)<4 or stop())

0 1 2 3 4
False

BTW I notice that this also nicely shortcuts when the 2 is found.


That's a fact.
Raymond
Jul 18 '05 #6
Raymond Hettinger wrote:

(quoting Bengt)
I assumed that all standard sequence consumers (including list, of
course) would intercept the StopIteration of a sequence given them in the
form of a generator expression, so your lyst example would have an
analogue for other sequence consumers as well, right?
I.e., there's not a hidden list(genex) in those others I would hope ;-)
Right.


I see I followed the historical evolvement and saw generator expressions as
a lazy listcomp rather than a cool new way to write a generator. That
turned out to be the road to confusion.

Thanks Carl, thanks Raymond for setting me straight.
I would call it an unfortunate assymmetry -- one the never comes up unless
you're up to no good ;-)


Do you see any chance that list comprehensions will be redefined as an
alternative spelling for list(<generator expression>)?

Peter

Jul 18 '05 #7
jfj wrote:
To make it a bit clearer, a StopIteration raised in a generator
expression silently terminates that generator:


*any* exception raised from a generator, terminates the generator


Yeah, but StopIteration is the only expected exception and therefore the
only one that client code (nearly) always knows to deal with:
def choke(): raise ValueError .... list(i for i in range(10) if i < 3 or choke()) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in <generator expression>
File "<stdin>", line 1, in choke
ValueError [i for i in range(10) if i < 3 or choke()]

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 1, in choke
ValueError

Here you can *not* tell apart list(genexp) and listcomp.

(Of course, as has since been pointed out, the StopIteration is actually
caught in the list constructor, so nothing magic to the example in my
initial post)

Peter

Jul 18 '05 #8
[Peter Otten]
Do you see any chance that list comprehensions will be redefined as an
alternative spelling for list(<generator expression>)?


Not likely. It is possible that the latter spelling would make it possible for
Py3.0. eliminate list comps entirely. However, they are very popular and
practical, so my bet is that they will live on.

The more likely change is that in Py3.0 list comps will no longer expose the
loop variable outside the loop.
Raymond Hettinger

Jul 18 '05 #9
Raymond Hettinger wrote:
[Peter Otten]
Do you see any chance that list comprehensions will be redefined as an
alternative spelling for list(<generator expression>)?


Not likely. It is possible that the latter spelling would make it possible for
Py3.0. eliminate list comps entirely. However, they are very popular and
practical, so my bet is that they will live on.


I suspect you're right, but I certainly wouldn't complain if list comps
disappeared. TOOWTDI and all, and I often find myself alternating
between the two when I can't decide which one seems more Pythonic.
(These days I generally write a listcomp, but I wouldn't put any money
on my code being entirely consistent about this...)

STeVe
Jul 18 '05 #10

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

Similar topics

72
4431
by: Raymond Hettinger | last post by:
Peter Norvig's creative thinking triggered renewed interest in PEP 289. That led to a number of contributors helping to re-work the pep details into a form that has been well received on the python-dev list: http://www.python.org/peps/pep-0289.html In brief, the PEP proposes a list comprehension style syntax for creating fast, memory efficient generator expressions on the fly: sum(x*x for x in roots)
24
3362
by: Mahesh Padmanabhan | last post by:
Hi, When list comprehension was added to the language, I had a lot of trouble understanding it but now that I am familiar with it, I am not sure how I programmed in Python without it. Now I see that generator expressions have been added to the language with 2.4 and I question the need for it. I know that it allows for lazy evaluation which speeds things up for larger lists but why was it necessary to add it instead of improving list...
45
3054
by: Joh | last post by:
hello, i'm trying to understand how i could build following consecutive sets from a root one using generator : l = would like to produce : , , , ,
5
11511
by: malcolm | last post by:
Example, suppose you have these 2 tables (NOTE: My example is totally different, but I'm simply trying to setup the a simpler version, so excuse the bad design; not the point here) CarsSold { CarsSoldID int (primary key) MonthID int DealershipID int NumberCarsSold int
2
2364
by: aj70000 | last post by:
This is my query select ano,max(date),a_subject from MY_TAB where table_name='xyz' and ano=877 group by a_subject,ano order by a_subject ANO max(Date) A_Subject 877 2005-01-20 00:00:00.000 Subject_1 877 1900-01-01 00:00:00.000 Subject_2 877 2004-12-20 00:00:00.000 Subject_3
9
2025
by: bonono | last post by:
Hi, I initially thought that generator/generator expression is cool(sort of like the lazy evaluation in Haskell) until I notice this side effect. >>>a=(x for x in range(2)) >>>list(a) >>>list(a)
7
8119
by: Laurent Pointal | last post by:
on win32] Given the following: 45 .... (<generator object at 0x00A79788>,) .... File "<stdin>", line 1 SyntaxError: invalid syntax
5
1751
by: Kris Kowal | last post by:
I had a thought that might be pepworthy. Might we be able to break outer loops using an iter-instance specific StopIteration type? This is the desired, if not desirable, syntax:: import string letters = iter(string.lowercase) for letter in letters: for number in range(10): print letter, number
6
14677
by: ccy56781 | last post by:
I'm writing to see calcuration process. And so, I can't catch StopIteration... What is mistake? def collatz(n): r= while n>1: r.append(n) n = 3*n+1 if n%2 else n/2
0
10599
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
10346
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
10347
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
10090
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
6863
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
5673
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4308
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
2
3832
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
3001
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.