By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,857 Members | 1,813 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,857 IT Pros & Developers. It's quick & easy.

removing list comprehensions in Python 3.0

P: n/a
George Sakkis wrote:
"Steven Bethard" <st************@gmail.com> wrote:
Dict comprehensions were recently rejected:
http://www.python.org/peps/pep-0274.html
The reason, of course, is that dict comprehensions don't gain you
much at all over the dict() constructor plus a generator expression,
e.g.:
dict((i, chr(65+i)) for i in range(4))


Sure, but the same holds for list comprehensions: list(i*i for i in
xrange(10)). The difference is historic I guess; list comprehensions
preceded generator expressions and so they cannot be removed, at least
not before 3.0. I wonder if they will/should be in the language when
the constraint of backwards compatibility is lifted. IMO they should
not (TIOOWTDI, uniformity among builtin data structures, not
overwhelmingly more useful than set or dict comprehensions), but
there's a long way till that day.


I think the jury's still out on this one:

* Alex Martelli expects list comprehensions to be removed. [1]
* Robert Kern wants list comprehensions removed. [2]
* Raymond Hettinger encourages continued use of list comprehensions [3]
* Jeremy Bowers thinks list comprehensions should stay. [4]

I only searched a few relatively recent threads in c.l.py, so there are
probably more, but it looks to me like the final decision will have to
be made by a pronouncement from Guido.

[1]http://groups-beta.google.com/group/comp.lang.python/msg/f5613c00cb8c9539
[2]http://groups-beta.google.com/group/comp.lang.python/msg/b2cf0cd72d53fbe5
[3]http://groups-beta.google.com/group/comp.lang.python/msg/781dfab03701dd18
[4]http://groups-beta.google.com/group/comp.lang.python/msg/771a47d9eb24c863
Jul 21 '05 #1
Share this Question
Share on Google+
30 Replies


P: n/a
Steven Bethard schrieb:
I think the jury's still out on this one:

* Alex Martelli expects list comprehensions to be removed. [1]
* Robert Kern wants list comprehensions removed. [2]
* Raymond Hettinger encourages continued use of list comprehensions [3]
* Jeremy Bowers thinks list comprehensions should stay. [4]

I only searched a few relatively recent threads in c.l.py, so there are
probably more, but it looks to me like the final decision will have to
be made by a pronouncement from Guido.


Well, I want to offer a more radical proposal: why not free squared
braces from the burden of representing lists at all? It should be
sufficient to write
list()

list()

After being free one can use them for other purposes e.g. replacing the
ugly @ decorator character by the lovely [ .. ] notation or other
important features no one never trusted to implement waiting for the
right syntax sugar. More than this round braces together with lists can
be considered as a concession to the LISP programmer who was repelled
from Python by the decision to eliminate functional programming
features.

Kay

Jul 21 '05 #2

P: n/a
Kay Schluehr wrote:
Well, I want to offer a more radical proposal: why not free squared
braces from the burden of representing lists at all? It should be
sufficient to write
list()


list()


So then what would the expression list('foo') mean? Would it be
equivalent to ['foo'] (if so, how would you convert a string or other
iterable to a list under Py3k?), or would it be equivalent to ['f', 'o',
'o'] as it is in now (and is so, what gives?)?
Jul 21 '05 #3

P: n/a
List comprehensions are faster than generator comprehensions for
iterating over smaller sequences.

Jul 21 '05 #4

P: n/a
Kay Schluehr wrote:
Well, I want to offer a more radical proposal: why not free squared
braces from the burden of representing lists at all? It should be
sufficient to write
list()

list()

After being free one can use them for other purposes e.g. replacing the
ugly @ decorator character by the lovely [ .. ] notation or other
important features no one never trusted to implement waiting for the
right syntax sugar. More than this round braces together with lists can
be considered as a concession to the LISP programmer who was repelled
from Python by the decision to eliminate functional programming
features.


Heh heh.

So how do I write a list literal then? Or do we only get tuple literals
in Python 3.0. ;)

STeVe
Jul 21 '05 #5

P: n/a
Devan L wrote:
List comprehensions are faster than generator comprehensions for
iterating over smaller sequences.


Could you give me an example? For the simple one below, the generator
expression was faster:

$ python -m timeit "for x in (i for i in xrange(10)): y = x"
100000 loops, best of 3: 4.75 usec per loop

$ python -m timeit "for x in [i for i in xrange(10)]: y = x"
100000 loops, best of 3: 5.33 usec per loop
And for another one, the results are basically indistinguishable:

$ python -m timeit "for x in (i for i in 'abcdefg'): y = x"
100000 loops, best of 3: 3.82 usec per loop

$ python -m timeit "for x in [i for i in 'abcdefg']: y = x"
100000 loops, best of 3: 3.87 usec per loop
I vaguely remember that in Python 2.4 conversion to tuples can take
longer because of the tuple extension code:

$ python -m timeit "tuple(i for i in xrange(10000))"
100 loops, best of 3: 2.24 msec per loop

$ python -m timeit "tuple([i for i in xrange(10000)])"
100 loops, best of 3: 1.85 msec per loop

But IIRC, this is supposed to be fixed in Python 2.5.
I found that for some longer sequences, generator expressions were
notably faster:

$ python -m timeit "set(i for i in xrange(10000))"
100 loops, best of 3: 3.77 msec per loop

$ python -m timeit "set([i for i in xrange(10000)])"
100 loops, best of 3: 4.54 msec per loop
Timings that validate your statement would be appreciated. ;)

STeVe
Jul 21 '05 #6

P: n/a
On Fri, 08 Jul 2005 16:07:50 -0600, Steven Bethard
<st************@gmail.com> declaimed the following in comp.lang.python:

I only searched a few relatively recent threads in c.l.py, so there are
probably more, but it looks to me like the final decision will have to
be made by a pronouncement from Guido.
Great... It takes me two releases of Python to get comfortable
with them, and then they are threatened to be removed again...

Might as well submit the language to ISO for standardization --
then I wouldn't be following an erratic target <G>

-- ================================================== ============ <
wl*****@ix.netcom.com | Wulfraed Dennis Lee Bieber KD6MOG <
wu******@dm.net | Bestiaria Support Staff <
================================================== ============ <
Home Page: <http://www.dm.net/~wulfraed/> <
Overflow Page: <http://wlfraed.home.netcom.com/> <

Jul 21 '05 #7

P: n/a


Leif K-Brooks schrieb:
Kay Schluehr wrote:
Well, I want to offer a more radical proposal: why not free squared
braces from the burden of representing lists at all? It should be
sufficient to write
>list()


list()


So then what would the expression list('foo') mean? Would it be
equivalent to ['foo'] (if so, how would you convert a string or other
iterable to a list under Py3k?), or would it be equivalent to ['f', 'o',
'o'] as it is in now (and is so, what gives?)?


Spiltting a string and putting the characters into a list could be done
in method application style:
"abc".tolist() list('a','b','c')

Or equivalent from lists point of view:
list.from_str("abc")

list("a", "b", "c" )

Kay

Jul 21 '05 #8

P: n/a
Dennis Lee Bieber wrote:
On Fri, 08 Jul 2005 16:07:50 -0600, Steven Bethard
<st************@gmail.com> declaimed the following in comp.lang.python:
I only searched a few relatively recent threads in c.l.py, so there are
probably more, but it looks to me like the final decision will have to
be made by a pronouncement from Guido.


Great... It takes me two releases of Python to get comfortable
with them, and then they are threatened to be removed again...

Might as well submit the language to ISO for standardization --
then I wouldn't be following an erratic target <G>


Two points:

(1) There's no reason to get uncomfortable even if they're removed.
You'd just replace [] with list().

(2) *IMPORTANT* If this happens *at all*, it won't happen until Python
3.0, which is probably at least 5 years away. And the Python 2.X branch
will still be available then, so if you don't like Python 3.0, you don't
have to use it.

STeVe
Jul 21 '05 #9

P: n/a
Kay Schluehr wrote:

Leif K-Brooks schrieb:
Kay Schluehr wrote:
Well, I want to offer a more radical proposal: why not free squared
braces from the burden of representing lists at all? It should be
sufficient to write
>>list()

list()


So then what would the expression list('foo') mean? Would it be
equivalent to ['foo'] (if so, how would you convert a string or other
iterable to a list under Py3k?), or would it be equivalent to ['f', 'o',
'o'] as it is in now (and is so, what gives?)?

Spiltting a string and putting the characters into a list could be done
in method application style:

"abc".tolist()


list('a','b','c')


"abc".splitchrs()

There's already a str.split() to create a list of words,
and a str.splitline() to get a list of lines, so it would group related
methods together.

I don't thin adding sting methods to lists is a good idea.

Cheers,
Ron

Jul 21 '05 #10

P: n/a
Kay Schluehr wrote:
list.from_str("abc")


list("a", "b", "c" )

I assume we'll also have list.from_list, list.from_tuple,
list.from_genexp, list.from_xrange, etc.?
Jul 21 '05 #11

P: n/a
>>> import timeit
t1 = timeit.Timer('list(i for i in xrange(10))')
t1.timeit() 27.267753024476576 t2 = timeit.Timer('[i for i in xrange(10)]')
t2.timeit() 15.050426800054197 t3 = timeit.Timer('list(i for i in xrange(100))')
t3.timeit() 117.61078097914682 t4 = timeit.Timer('[i for i in xrange(100)]')
t4.timeit()

83.502424470149151

Hrm, okay, so generators are generally faster for iteration, but not
for making lists(for small sequences), so list comprehensions stay.

Jul 21 '05 #12

P: n/a
On Fri, 08 Jul 2005 22:29:30 -0600, Steven Bethard <st************@gmail.com> wrote:
Dennis Lee Bieber wrote:
On Fri, 08 Jul 2005 16:07:50 -0600, Steven Bethard
<st************@gmail.com> declaimed the following in comp.lang.python:
I only searched a few relatively recent threads in c.l.py, so there are
probably more, but it looks to me like the final decision will have to
be made by a pronouncement from Guido.
Great... It takes me two releases of Python to get comfortable
with them, and then they are threatened to be removed again...

Might as well submit the language to ISO for standardization --
then I wouldn't be following an erratic target <G>


Two points:

(1) There's no reason to get uncomfortable even if they're removed.
You'd just replace [] with list().


So list(1, 2, 3) will be the same as [1, 2, 3] ??

Right now,
list(1,2,3)

Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: list() takes at most 1 argument (3 given)

have fun ;-)

(2) *IMPORTANT* If this happens *at all*, it won't happen until Python
3.0, which is probably at least 5 years away. And the Python 2.X branch
will still be available then, so if you don't like Python 3.0, you don't
have to use it.

STeVe


Regards,
Bengt Richter
Jul 21 '05 #13

P: n/a
Leif K-Brooks wrote:
Kay Schluehr wrote:
>list.from_str("abc")


list("a", "b", "c" )


I assume we'll also have list.from_list, list.from_tuple,
list.from_genexp, list.from_xrange, etc.?


List from list isn't needed, nor list from tuple. That's what the * is
for. And for that matter neither is the str.splitchar() either.
class mylist(list):
def __init__(self,*args):
self[:]=args[:]
mylist(*[1,2,3]) -> [1,2,3]

mylist(*(1,2,3)) -> [1,2,3]

mylist(*"abc") -> ['a','b','c']

mylist(1,2,3) -> [1,2,3]

mylist([1],[2]) -> [[1],[2]]

mylist('hello','world') -> ['hello','world']

Works for me. ;-)

I always thought list([1,2,3]) -> [1,2,3] was kind of silly.
Cheers,
Ron
Jul 21 '05 #14

P: n/a
Leif K-Brooks schrieb:
Kay Schluehr wrote:
>list.from_str("abc")


list("a", "b", "c" )

I assume we'll also have list.from_list, list.from_tuple,
list.from_genexp, list.from_xrange, etc.?


One might unify all those factory functions into a single
list.from_iter that dispatches to the right constructor that still
lives under the hood. More conceptually: there is some abstract iter
base class providing a from_iter method which may be overwritten in
concrete subclasses like tuple, str or list.

I would further suggest a lazy iterator used to evaluate objects when
they get accessed the first time:
l = lazy( math.exp(100) , 27 ) <lazy-iterator object at 0x4945f0> l[1]

27

The first element won't ever be evaluated if it does not get accessed
explicitely. This is some very special kind of partial
evaluation/specialization.

Kay

Jul 21 '05 #15

P: n/a
Bengt Richter wrote:
On Fri, 08 Jul 2005 22:29:30 -0600, Steven Bethard <st************@gmail.com> wrote:
(1) There's no reason to get uncomfortable even if they're removed.
You'd just replace [] with list().


So list(1, 2, 3) will be the same as [1, 2, 3] ??


No, the discussion is about list comprehensions. [1,2,3] is not a list
comprehension, as you know.

-Peter
Jul 21 '05 #16

P: n/a
In all probability, both list comprehensions and generator expressions
will be around in perpetuity. List comps have been a very successful
language feature.

The root of this discussion has been the observation that a list
comprehension can be expressed in terms of list() and a generator
expression. However, the former is faster when you actually want a
list result and many people (including Guido) like the square brackets.

After the advent of generators, it seemed for a while that all
functions and methods that returned lists would eventually return
iterators instead. What we are learning is that there is a place for
both. It is darned inconvenient to get an iterator when you really
need a list, when you want to slice the result, when you want to see a
few elements through repr(), and when you need to loop over the
contents more than once.
Raymond Hettinger

Jul 21 '05 #17

P: n/a
On Sat, 09 Jul 2005 10:16:17 -0400, Peter Hansen <pe***@engcorp.com> wrote:
Bengt Richter wrote:
On Fri, 08 Jul 2005 22:29:30 -0600, Steven Bethard <st************@gmail.com> wrote:
(1) There's no reason to get uncomfortable even if they're removed.
You'd just replace [] with list().


So list(1, 2, 3) will be the same as [1, 2, 3] ??


No, the discussion is about list comprehensions. [1,2,3] is not a list
comprehension, as you know.

D'oh. Sorry to have come in from contextual outer space ;-/

Regards,
Bengt Richter
Jul 21 '05 #18

P: n/a
"Raymond Hettinger" <py****@rcn.com> wrote in message
news:11*********************@g14g2000cwa.googlegro ups.com...
In all probability, both list comprehensions and generator expressions
will be around in perpetuity. List comps have been a very successful
language feature.

The root of this discussion has been the observation that a list
comprehension can be expressed in terms of list() and a generator
expression. However, the former is faster when you actually want a
list result and many people (including Guido) like the square brackets.

After the advent of generators, it seemed for a while that all
functions and methods that returned lists would eventually return
iterators instead. What we are learning is that there is a place for
both. It is darned inconvenient to get an iterator when you really
need a list, when you want to slice the result, when you want to see a
few elements through repr(), and when you need to loop over the
contents more than once.
I was wondering about what seemed like an ill-concieved rush to
make everything an iterator. Iterators are, of course, useful but there
are times when you really did want a list.

John Roth

Raymond Hettinger


Jul 21 '05 #19

P: n/a
"Raymond Hettinger" <py****@rcn.com> wrote:
In all probability, both list comprehensions and generator expressions
will be around in perpetuity. List comps have been a very successful
language feature.

The root of this discussion has been the observation that a list
comprehension can be expressed in terms of list() and a generator
expression.
No, the root of the discussion, in this thread at least, was the answer
to "why not dict comprehensions ?", which was along the lines of "well,
you can do it in one line by dict(gen_expression)".
However, the former is faster when you actually want a
list result and many people (including Guido) like the square brackets.
Also dict comprehensions are faster if you actually want a dict result,
set comprehensions for set result, and so on and so forth.
After the advent of generators, it seemed for a while that all
functions and methods that returned lists would eventually return
iterators instead. What we are learning is that there is a place for
both.
Altering the result type of existing functions and methods is not
exactly the same with the discussion on the future of list
comprehensions; the latter affects only whether listcomps are special
enough to be granted special syntax support, when there is an
equivalent way to express the same thing. It's funny how one of the
arguments for removing lambda -- you can do the same by defining a
named function -- does not apply for list comprehensions.
It is darned inconvenient to get an iterator when you really
need a list, when you want to slice the result, when you want to see a
few elements through repr(), and when you need to loop over the
contents more than once.

Raymond Hettinger


Similar arguments can be given for dict comprehensions as well.

George

Jul 21 '05 #20

P: n/a
"George Sakkis" <gs*****@rutgers.edu> wrote in message
news:11**********************@g49g2000cwa.googlegr oups.com...
It's funny how one of the
arguments for removing lambda -- you can do the same by defining a
named function -- does not apply for list comprehensions.
Which is a point a number of people have made many times,
with about as much effect as spitting into the wind.

Making a piece of functionality less convenient simply to
satisfy someone's sense of language esthetics doesn't seem
to me, at least, to be a really good idea.

John Roth



George


Jul 21 '05 #21

P: n/a
Devan L wrote:
import timeit
t1 = timeit.Timer('list(i for i in xrange(10))')
t1.timeit()
27.267753024476576
t2 = timeit.Timer('[i for i in xrange(10)]')
t2.timeit()
15.050426800054197
t3 = timeit.Timer('list(i for i in xrange(100))')
t3.timeit()
117.61078097914682
t4 = timeit.Timer('[i for i in xrange(100)]')
t4.timeit()


83.502424470149151

Hrm, okay, so generators are generally faster for iteration, but not
for making lists(for small sequences), so list comprehensions stay.


Ahh, thanks. Although, it seems like a list isn't very useful if you
never iterate over it. ;)

Also worth noting that in Python 3.0 it is quite likely that list
comprehensions and generator expressions will have the same underlying
implementation. So while your tests above satisfy my curiosity
(thanks!) they're not really an argument for retaining list
comprehensions in Python 3.0. And list comprehensions won't go away
before then because removing them will break loads of existing code.

STeVe
Jul 21 '05 #22

P: n/a
Raymond Hettinger wrote:
The root of this discussion has been the observation that a list
comprehension can be expressed in terms of list() and a generator
expression.
As George Sakkis already noted, the root of the discussion was actually
the rejection of the dict comprehensions PEP.
However, the former is faster when you actually want a list result
I would hope that in Python 3.0 list comprehensions and generator
expressions would be able to share a large amount of implementation, and
thus that the speed differences would be much smaller. But maybe not...
and many people (including Guido) like the square brackets.

^
|
This --------------------------+ of course, is always a valid point. ;)

STeVe
Jul 21 '05 #23

P: n/a
[Steven Bethard]
I would hope that in Python 3.0 list comprehensions and generator
expressions would be able to share a large amount of implementation, and
thus that the speed differences would be much smaller. But maybe not...


Looking under the hood, you would see that the implementations are
necessarily as different as night and day. Only the API is similar.
Raymond

Jul 21 '05 #24

P: n/a
[Raymond Hettinger]
It is darned inconvenient to get an iterator when you really
need a list, when you want to slice the result, when you want to see a
few elements through repr(), and when you need to loop over the
contents more than once.

[George Sakkis] Similar arguments can be given for dict comprehensions as well.


You'll find that "lever" arguments carry little weight in Python
language design (well, you did X in place Y so now you have to do it
everywhere even if place Z lacks compelling use cases).

For each variant, the balance is different. Yes, of course, list
comprehensions have pros and cons similar to set comprehensions, dict
comps, etc. However, there are marked differences in frequency of use
cases, desirability of having an expanded form, implementation issues,
varying degrees of convenience, etc.

The utility and generality of genexps raises the bar quite high for
these other forms. They would need to be darned frequent and have a
superb performance advantage.

Take it from the set() and deque() guy, we need set, dict, and deque
comprehensions like we need a hole in the head. The constructor with a
genexp does the trick just fine.

Why the balance tips the other way for list comps is both subjective
and subtle. I don't expect to convince you by a newsgroup post.
Rather, I can communicate how one of the core developers perceives the
issue. IMHO, the current design strikes an optimal balance.

'nuff said,
Raymond

Jul 21 '05 #25

P: n/a
Raymond Hettinger wrote:
[Steven Bethard]
I would hope that in Python 3.0 list comprehensions and generator
expressions would be able to share a large amount of implementation, and
thus that the speed differences would be much smaller. But maybe not...


Looking under the hood, you would see that the implementations are
necessarily as different as night and day. Only the API is similar.


Necessarily? It seems like list comprehensions *could* be implemented
as a generator expression passed to the list constructor. They're not
now, and at the moment, changing them to work this way seems like a bad
idea because list comprehensions would take a performance hit. But I
don't understand why the implementations are *necessarily* different.
Could you explain?

STeVe

P.S. The dis.dis output for list comprehensions makes what they're doing
pretty clear. But dis.dis doesn't seem to give me as much information
when looking at a generator expression:

py> def ge(items):
.... return (item for item in items if item)
....
py> dis.dis(ge)
2 0 LOAD_CONST 1 (<code object <generator
expression> at 0116FD20, file "<interactive input>", line 2>)
3 MAKE_FUNCTION 0
6 LOAD_FAST 0 (items)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE

I tried to grep through the dist\src directories for what a generator
expression code object looks like, but without any luck. Any chance you
could point me in the right direction?
Jul 21 '05 #26

P: n/a
On Sat, 09 Jul 2005 22:32:22 -0600, Steven Bethard <st************@gmail.com> wrote:
Raymond Hettinger wrote:
[Steven Bethard]
I would hope that in Python 3.0 list comprehensions and generator
expressions would be able to share a large amount of implementation, and
thus that the speed differences would be much smaller. But maybe not...


Looking under the hood, you would see that the implementations are
necessarily as different as night and day. Only the API is similar.


Necessarily? It seems like list comprehensions *could* be implemented
as a generator expression passed to the list constructor. They're not
now, and at the moment, changing them to work this way seems like a bad
idea because list comprehensions would take a performance hit. But I
don't understand why the implementations are *necessarily* different.
Could you explain?

STeVe

P.S. The dis.dis output for list comprehensions makes what they're doing
pretty clear. But dis.dis doesn't seem to give me as much information
when looking at a generator expression:

py> def ge(items):
... return (item for item in items if item)
...
py> dis.dis(ge)
2 0 LOAD_CONST 1 (<code object <generator
expression> at 0116FD20, file "<interactive input>", line 2>)
3 MAKE_FUNCTION 0
6 LOAD_FAST 0 (items)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE

I tried to grep through the dist\src directories for what a generator
expression code object looks like, but without any luck. Any chance you
could point me in the right direction?

import dis
g = ge([1,2,0,3,'',4])
dis.dis(g) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "d:\python-2.4b1\lib\dis.py", line 46, in dis
raise TypeError, \
TypeError: don't know how to disassemble generator objects

but:
dis.dis(ge) 2 0 LOAD_CONST 1 (<code object <generator expression> at 02EE4FA0, file "<stdin>", line 2>)
3 MAKE_FUNCTION 0
6 LOAD_FAST 0 (items)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE ge.func_code <code object ge at 02EE4E60, file "<stdin>", line 1> ge.func_code.co_consts (None, <code object <generator expression> at 02EE4FA0, file "<stdin>", line 2>) ge.func_code.co_consts[1] <code object <generator expression> at 02EE4FA0, file "<stdin>", line 2> dis.dis(ge.func_code.co_consts[1])
2 0 SETUP_LOOP 28 (to 31)
3 LOAD_FAST 0 ([outmost-iterable]) 6 FOR_ITER 21 (to 30) 9 STORE_FAST 1 (item)
12 LOAD_FAST 1 (item)
15 JUMP_IF_FALSE 8 (to 26)
18 POP_TOP
19 LOAD_FAST 1 (item)
22 YIELD_VALUE
23 JUMP_ABSOLUTE 6 26 POP_TOP 27 JUMP_ABSOLUTE 6 30 POP_BLOCK
31 LOAD_CONST 0 (None)

34 RETURN_VALUE

A little more info, anyway. HTH.

Regards,
Bengt Richter
Jul 21 '05 #27

P: n/a
EP
Well, I want to offer a more radical proposal: why not free squared
braces from the burden of representing lists at all? It should be
sufficient to write
list()
list()


<snip>
From a visual comprehenison point of view, I would assert that the square form [] is much easier on the eyes than the subtler curved forms (e.g. "{" and "(").


Burdened with old eyes, small fonts, and an old, inflexible mind (;-), one of Python features near and dear to me are lists, [], and list comprehensions, but perhaps a more important point for 3.0 would be that there is a seamless consistency across the language (e.g.[list(), dict(), tuple()] or [[], {}, () ] rather than[list(), {}, ()]) thus reflecting a cohesiveness both in underlying approach and symbology.

Even old guys can adjust to something new that is good and clean.

Jul 21 '05 #28

P: n/a
Steven Bethard wrote:
py> def ge(items):
... return (item for item in items if item)
...


Bengt Richter wrote:
>>> dis.dis(ge) 2 0 LOAD_CONST 1 (<code object <generator expression> at 02EE4FA0, file "<stdin>", line 2>)
3 MAKE_FUNCTION 0
6 LOAD_FAST 0 (items)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE

[snip]
>>> dis.dis(ge.func_code.co_consts[1]) 2 0 SETUP_LOOP 28 (to 31)
3 LOAD_FAST 0 ([outmost-iterable]) >> 6 FOR_ITER 21 (to 30) 9 STORE_FAST 1 (item)
12 LOAD_FAST 1 (item)
15 JUMP_IF_FALSE 8 (to 26)
18 POP_TOP
19 LOAD_FAST 1 (item)
22 YIELD_VALUE
23 JUMP_ABSOLUTE 6 >> 26 POP_TOP 27 JUMP_ABSOLUTE 6 >> 30 POP_BLOCK
>> 31 LOAD_CONST 0 (None) 34 RETURN_VALUE


Outstanding. Thanks a lot! For comparison, here's the relevant dis.dis
output for list comprehensions.

py> def lc(items):
.... return [item for item in items if item]
....
py> dis.dis(lc)
2 0 BUILD_LIST 0
3 DUP_TOP
4 STORE_FAST 1 (_[1])
7 LOAD_FAST 0 (items)
10 GET_ITER 11 FOR_ITER 24 (to 38) 14 STORE_FAST 2 (item)
17 LOAD_FAST 2 (item)
20 JUMP_IF_FALSE 11 (to 34)
23 POP_TOP
24 LOAD_FAST 1 (_[1])
27 LOAD_FAST 2 (item)
30 LIST_APPEND
31 JUMP_ABSOLUTE 11 34 POP_TOP 35 JUMP_ABSOLUTE 11 38 DELETE_FAST 1 (_[1])

41 RETURN_VALUE

Interestingly, the LC code and the code of a GE's "generator-expression"
code object look quite similar, with basically a LOAD_FAST/LIST_APPEND
replaced by a YIELD_VALUE.

But I don't know byte code well enough to guess how the dangling local
variable in LCs will be eliminated in Python 3.0 (as has been suggested
a number of times). One way to eliminate it would be (as suggested) to
make LCs syntactic sugar for list(<genexp>). But it also looks like it
might be possible to do a DELETE_FAST with an appropriately hidden name...

STeVe
Jul 21 '05 #29

P: n/a
Steven Bethard <st************@gmail.com> writes:
$ python -m timeit "for x in (i for i in xrange(10)): y = x"
100000 loops, best of 3: 4.75 usec per loop


Yowza! One of the features I really liked in Perl has shored Python island
somewhere in the 2.4'ies, it seems[1]. Thanks for the tip!

PS. In case it wasn't clear what I referred to, it was the ability to run
given module as a script. Of course you could supply full path to timeit.py:

$ python2.3 /usr/lib/python2.3/timeit.py \
"for x in [i for i in xrange(10)]: y = x"
100000 loops, best of 3: 9.96 usec per loop

But using -m makes it much more convenient.
Footnotes:
[1] Well, not exactly equal to -M in Perl, but close enough for timing stuff

--
# Edvard Majakari Software Engineer
# PGP PUBLIC KEY available Soli Deo Gloria!
You shouldn't verb verbs.
Jul 21 '05 #30

P: n/a
Edvard Majakari wrote:
Steven Bethard <st************@gmail.com> writes:
$ python -m timeit "for x in (i for i in xrange(10)): y = x"
100000 loops, best of 3: 4.75 usec per loop
Yowza! One of the features I really liked in Perl has shored Python island
somewhere in the 2.4'ies, it seems[1]. Thanks for the tip!

[snip] But using -m makes it much more convenient.


Yup, it showed up in Python 2.4. Great, isn't it?

STeVe
Jul 21 '05 #31

This discussion thread is closed

Replies have been disabled for this discussion.