enumerate improvement proposal

J

James Stroud

I think that it would be handy for enumerate to behave as such:

def enumerate(itrbl, start=0, step=1):
i = start
for it in itrbl:
yield (i, it)
i += step

This allows much more flexibility than in the current enumerate,
tightens up code in many cases, and seems that it would break no
existing code. Yes, I have needed this behavior with enumerate, like
tonight and the current example. I put the "step" parameter in for
conceptual symmetry with slicing.

Here is a case use (or is it use case?):


# with the proposed enumerate
import operator
def in_interval(test, bounds, first=1, reverse=False):
op = operator.gt if reverse else operator.lt # python 2.5
bounds = sorted(bounds, reverse=reverse)
for i, bound in enumerate(bounds, first):
if op(test, bound):
return i
return i + 1


# with the existing enumerate
import operator
def in_interval(test, bounds, first=1, reverse=False):
op = operator.gt if reverse else operator.lt # python 2.5
bounds = sorted(bounds, reverse=reverse)
for i, bound in enumerate(bounds):
if op(test, bound):
return i + first
return i + first + 1


py> # eg
....
py> in_interval(8, bounds)
2
py> in_interval(1, bounds)
1
py> in_interval(1, bounds, reverse=True)
5
py> in_interval(8, bounds, reverse=True)
4
py> in_interval(20, bounds, reverse=True)
2

Of course, I haven't used step here. Even in this trivial example the
proposed enumerate cleans the code and logic, eliminating a couple of
plus signs. For this real-world example, the practical requirement for
reversing the bins obfuscates somewhat the de-obfuscation provided by
the proposed enumerate. But I think that it might be obvious that the
proposed enumerate could help significantly in cases a bit more
complicated than this one.

Any thoughts?

James
 
J

James Stroud

James said:
I think that it would be handy for enumerate to behave as such:

def enumerate(itrbl, start=0, step=1):
i = start
for it in itrbl:
yield (i, it)
i += step

This allows much more flexibility than in the current enumerate,
tightens up code in many cases, and seems that it would break no
existing code. Yes, I have needed this behavior with enumerate, like
tonight and the current example. I put the "step" parameter in for
conceptual symmetry with slicing.

Here is a case use (or is it use case?):


# with the proposed enumerate
import operator
def in_interval(test, bounds, first=1, reverse=False):
op = operator.gt if reverse else operator.lt # python 2.5
bounds = sorted(bounds, reverse=reverse)
for i, bound in enumerate(bounds, first):
if op(test, bound):
return i
return i + 1


# with the existing enumerate
import operator
def in_interval(test, bounds, first=1, reverse=False):
op = operator.gt if reverse else operator.lt # python 2.5
bounds = sorted(bounds, reverse=reverse)
for i, bound in enumerate(bounds):
if op(test, bound):
return i + first
return i + first + 1


py> # eg
...
py> in_interval(8, bounds)
2
py> in_interval(1, bounds)
1
py> in_interval(1, bounds, reverse=True)
5
py> in_interval(8, bounds, reverse=True)
4
py> in_interval(20, bounds, reverse=True)
2

Of course, I haven't used step here. Even in this trivial example the
proposed enumerate cleans the code and logic, eliminating a couple of
plus signs. For this real-world example, the practical requirement for
reversing the bins obfuscates somewhat the de-obfuscation provided by
the proposed enumerate. But I think that it might be obvious that the
proposed enumerate could help significantly in cases a bit more
complicated than this one.

Any thoughts?

James

After a brief reflection, I realized that I just described a
"for-to-step-do" style loop one might find in many other languages, most
notably BASIC.

James
 
F

Fredrik Lundh

James said:
def enumerate(itrbl, start=0, step=1):
i = start
for it in itrbl:
yield (i, it)
i += step

that's spelled

izip(count(start), sequence)

in today's Python.
> def in_interval(test, bounds, first=1, reverse=False):

why is it this function's job to add an offset to the actual sequence index?

</F>
 
J

James Stroud

Fredrik said:
why is it this function's job to add an offset to the actual sequence
index?

</F>

The code is for an economist. She is insistent on starting with the
first bin as 1. I'm guessing, practically, binning linerizes data and
the bin number may potentially become a divisor or perhaps the operand
in a logarithm.

James
 
J

James Stroud

Fredrik said:
that's spelled

izip(count(start), sequence)

in today's Python.


why is it this function's job to add an offset to the actual sequence
index?

</F>

BTW, thank you for your tip.

James
 
F

Fredrik Lundh

James said:
The code is for an economist. She is insistent on starting with the
first bin as 1.

leaky abstractions in reverse, in other words? that's not a good design
approach.

</F>
 
J

James Stroud

Fredrik said:
leaky abstractions in reverse, in other words? that's not a good design
approach.

</F>

I'm not sure I understand what "leaky abstractions" means.

I am helping someone with dubious programming skills make sense of a
pile of code they wrote--code which getting a little unwieldy to debug.
I think "design approach" can't really apply here. The idea is to make
it comprehensible at some level.

I'm still curious what you mean by "leaky abstractions". Please explain.

James
 
P

Peter Otten

James said:
I think that it would be handy for enumerate to behave as such:

def enumerate(itrbl, start=0, step=1):
i = start
for it in itrbl:
yield (i, it)
i += step

This allows much more flexibility than in the current enumerate,
tightens up code in many cases, and seems that it would break no
existing code. Yes, I have needed this behavior with enumerate, like
tonight and the current example. I put the "step" parameter in for
conceptual symmetry with slicing.

Here is a case use (or is it use case?):

I don' think you have a use case here:

# untested
def find_interval(value, bounds, funny_offset=0, reverse=False):
bounds = sorted(bounds)
if reverse:
index = len(bounds) - bisect.bisect_left(bounds, value)
else:
index = bisect.bisect_right(bounds, value)
return index + funny_offset

You can tell by its name which of the arguments I would have omitted :)
Of course, I haven't used step here.

That seems to be typical. The only use case I've ever come across is start=1
for output aimed at a human reader.
Even in this trivial example the
proposed enumerate cleans the code and logic, eliminating a couple of
plus signs. For this real-world example, the practical requirement for
reversing the bins obfuscates somewhat the de-obfuscation provided by
the proposed enumerate. But I think that it might be obvious that the
proposed enumerate could help significantly in cases a bit more
complicated than this one.

Of course you get these claimed advantages from a self-written function,
too.
Any thoughts?

You have my support for adding a start parameter to enumerate(). I fear it
won't make a difference.

Peter
 
G

Georg Brandl

James said:
I think that it would be handy for enumerate to behave as such:

def enumerate(itrbl, start=0, step=1):
i = start
for it in itrbl:
yield (i, it)
i += step

This allows much more flexibility than in the current enumerate,
tightens up code in many cases, and seems that it would break no
existing code. Yes, I have needed this behavior with enumerate, like
tonight and the current example. I put the "step" parameter in for
conceptual symmetry with slicing.

Here is a case use (or is it use case?):

Incidentally, I yesterday wrote a patch giving enumerate() a start parameter
(and, more importantly, changing it so that it doesn't wraparound at
sys.maxint). It can be found here:

https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1586315&group_id=5470

Georg
 
B

Ben Finney

James Stroud said:
The code is for an economist. She is insistent on starting with the
first bin as 1.

Note that 'enumerate' is actually a built-in type, and 'enumerate()'
is the constructor returning a new object of that type.

A special case isn't special enough to change the built-in type.
[(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')]
... seq = [(i+1, x) for (i, x) in enumerate(items)]
... return iter(seq)
... [(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E')]

This doesn't produce an 'enumerate' object; if you really want that,
you could subclass 'enumerate', but it seems the above function does
what you want.
 
B

Ben Finney

Ben Finney said:
[(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D'), (4, 'E')]
... seq = [(i+1, x) for (i, x) in enumerate(items)]
... return iter(seq)
...[(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E')]

An improvement: using a generator so as not to unnecessarily create an
intermediate list from the initial enumerator:
... enum_iter = iter((i+1, x) for (i, x) in enumerate(items))
... return enum_iter
... [(1, 'A'), (2, 'B'), (3, 'C'), (4, 'D'), (5, 'E')]
 
J

James Stroud

Fredrik said:
leaky abstractions in reverse, in other words? that's not a good design
approach.

</F>

Okay, I've googled "leaky abstractions" (as was probably your intended
affect with your silence), read the famous essay, and still
don't know what you mean and how it applies to what I have described.

Do you plan to justify your statement or emptily accuse people of violating
esoteric principles?

James

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
A

Anders J. Munch

Ben said:
... enum_iter = iter((i+1, x) for (i, x) in enumerate(items))
... return enum_iter

iter is redundant here.

def natural_enumerate_improvement(items, start=0):
return ((i+start, x) for (i, x) in enumerate(items))

- Anders
 
D

Diez B. Roggisch

Okay, I've googled "leaky abstractions" (as was probably your intended
affect with your silence), read the famous essay, and still
don't know what you mean and how it applies to what I have described.

Do you plan to justify your statement or emptily accuse people of violating
esoteric principles?

While I can't claim to know what the effbot thinks (the
skull-socks-wearing-python-coder-mindlink-technology is yet to be
developed), I think it's pretty clear what he is after here:

Computers compute offsets into data zero-based. Some languages like
pascal completely abstract that away from the user, but python doesn't.

So if your colleague/boss/whatever insists on indices being one-based,
this abstraction you introduced for her pretty fast leaks pretty badly.
Consider this simple example:

for offset, item in enumerate(some_list, start=1):
if item.is_the_chosen_one():
chosen_one_offset = offset

the_chosen_one = some_list[chosen_one_offset]

And bang, its Judas not Petrus who gets the pearly gates inc. stock options.

Diez
 
J

James Stroud

Diez said:
Okay, I've googled "leaky abstractions" (as was probably your intended
affect with your silence), read the famous essay, and still
don't know what you mean and how it applies to what I have described.

Do you plan to justify your statement or emptily accuse people of
violating
esoteric principles?


While I can't claim to know what the effbot thinks (the
skull-socks-wearing-python-coder-mindlink-technology is yet to be
developed), I think it's pretty clear what he is after here:

Computers compute offsets into data zero-based. Some languages like
pascal completely abstract that away from the user, but python doesn't.

So if your colleague/boss/whatever insists on indices being one-based,
this abstraction you introduced for her pretty fast leaks pretty badly.
Consider this simple example:

for offset, item in enumerate(some_list, start=1):
if item.is_the_chosen_one():
chosen_one_offset = offset

the_chosen_one = some_list[chosen_one_offset]

And bang, its Judas not Petrus who gets the pearly gates inc. stock
options.

Diez

Thank you for this explanation. Very illuminating. I think understand
this idea well and the thought of 1 basing this function makes me cringe
as much as the next guy (though I lacked the vocabulary to explain
exactly why I cringe).

But you see, weaning this university faculty level economist (who
already has her own way of doing everything...and to whom I happen to be
married) from the traditional economics tools of gauss and sas towards
the more sane and flexible tools of python, numarray, and rpy has been a
multi-stage process. Tweaking the chosen abstractions to not be as leaky
(thank you and thank Fredrik for introducing me to this vocabulary) is
still one of the things I'm working towards. I want to solidify the
conversion before I concentrate on nuance.

So, before too much criticism, I challenge even the most skilled python
programmer to find his or her own faculty economist (or statistician or
physicist) and get them to radically change their computational tools.
When you've walked a mile in my shoes, leaky abstractions won't seem
like such a big deal after all.

James

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
S

Steve Holden

James said:
Diez said:
Okay, I've googled "leaky abstractions" (as was probably your intended
affect with your silence), read the famous essay, and still
don't know what you mean and how it applies to what I have described.

Do you plan to justify your statement or emptily accuse people of
violating
esoteric principles?


While I can't claim to know what the effbot thinks (the
skull-socks-wearing-python-coder-mindlink-technology is yet to be
developed), I think it's pretty clear what he is after here:

Computers compute offsets into data zero-based. Some languages like
pascal completely abstract that away from the user, but python doesn't.

So if your colleague/boss/whatever insists on indices being one-based,
this abstraction you introduced for her pretty fast leaks pretty badly.
Consider this simple example:

for offset, item in enumerate(some_list, start=1):
if item.is_the_chosen_one():
chosen_one_offset = offset

the_chosen_one = some_list[chosen_one_offset]

And bang, its Judas not Petrus who gets the pearly gates inc. stock
options.

Diez


Thank you for this explanation. Very illuminating. I think understand
this idea well and the thought of 1 basing this function makes me cringe
as much as the next guy (though I lacked the vocabulary to explain
exactly why I cringe).

But you see, weaning this university faculty level economist (who
already has her own way of doing everything...and to whom I happen to be
married) from the traditional economics tools of gauss and sas towards
the more sane and flexible tools of python, numarray, and rpy has been a
multi-stage process. Tweaking the chosen abstractions to not be as leaky
(thank you and thank Fredrik for introducing me to this vocabulary) is
still one of the things I'm working towards. I want to solidify the
conversion before I concentrate on nuance.

So, before too much criticism, I challenge even the most skilled python
programmer to find his or her own faculty economist (or statistician or
physicist) and get them to radically change their computational tools.
When you've walked a mile in my shoes, leaky abstractions won't seem
like such a big deal after all.
Divorce is obviously the only answer. How could you end up marrying
someone who counts from one and not zero? ;-)

regards
Steve
 
J

James Stroud

Steve said:
How could you end up marrying
someone who counts from one and not zero? ;-)

She's the only other person I've ever met who used vi key binding at the
command line.

James


--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
M

Mark Elston

* James Stroud wrote (on 10/30/2006 4:39 PM):
She's the only other person I've ever met who used vi key binding at the
command line.

James

Well, there's your problem. You need to C-x C-f a new mate. :)

Mark
(Emacs rules)
 
B

Ben Finney

Mark Elston said:
* James Stroud wrote (on 10/30/2006 4:39 PM):

Well, there's your problem. You need to C-x C-f a new mate. :)

I don't have the commitment for that. What if I were to C-x C-v
a few different ones instead?
 
P

Paddy

James said:
She's the only other person I've ever met who used vi key binding at the
command line.
Wow. Now I see!

It's only Python. Just add one to indices where appropriate, buy her
chocolates. Don't say a thing when you squelch your seventh off-by-one
error. Look interested in the shoe store. (even for the fifth shoe, of
the third store). - *Your partner does vi*

Whoa!

- Paddy :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top