I believe the following is a common use-case for enumerate() (at least, I've used it quite some times): for lineno, line in enumerate(fileobject): ... For this, it would be nice to have a start parameter for enumerate(). The changes are minimal -- okay for 2.6? Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.
On Sun, May 11, 2008 at 3:20 PM, Georg Brandl <g.brandl@gmx.net> wrote:
I believe the following is a common use-case for enumerate() (at least, I've used it quite some times):
for lineno, line in enumerate(fileobject): ...
For this, it would be nice to have a start parameter for enumerate(). The changes are minimal -- okay for 2.6?
Taking a new argument that has a default shouldn't be an issue. +1 from me. I assume it is just going to start the count at that number, not advance the iterable to that point, right? -Brett
Brett Cannon schrieb:
On Sun, May 11, 2008 at 3:20 PM, Georg Brandl <g.brandl@gmx.net> wrote:
I believe the following is a common use-case for enumerate() (at least, I've used it quite some times):
for lineno, line in enumerate(fileobject): ...
For this, it would be nice to have a start parameter for enumerate(). The changes are minimal -- okay for 2.6?
Taking a new argument that has a default shouldn't be an issue. +1 from me. I assume it is just going to start the count at that number, not advance the iterable to that point, right?
Exactly. Georg -- Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out.
Brett Cannon wrote:
Taking a new argument that has a default shouldn't be an issue. +1 from me. I assume it is just going to start the count at that number, not advance the iterable to that point, right?
I wonder if it would be best for it to be a keyword-only argument. So many of the utility functions on iterables are foo(*iterables) that I might be inclined to think enumerate(foo, bar) is equivalent to enumerate(chain(foo, bar)), but enumerate(foo, start=bar) is pretty obvious. And if you consider that the enumeration is prepended to the values of foo, enumerate(foo, bar) is "backwards." Just saying.. -Scott -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
+1 to this. On Sun, May 11, 2008 at 6:23 PM, Scott Dial <scott+python-dev@scottdial.com> wrote:
Brett Cannon wrote:
Taking a new argument that has a default shouldn't be an issue. +1 from me. I assume it is just going to start the count at that number, not advance the iterable to that point, right?
I wonder if it would be best for it to be a keyword-only argument. So many of the utility functions on iterables are foo(*iterables) that I might be inclined to think enumerate(foo, bar) is equivalent to enumerate(chain(foo, bar)), but enumerate(foo, start=bar) is pretty obvious. And if you consider that the enumeration is prepended to the values of foo, enumerate(foo, bar) is "backwards." Just saying..
-Scott
-- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
_______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/guido%40python.org
-- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Sun, May 11, 2008 at 6:23 PM, Scott Dial <scott+python-dev@scottdial.com> wrote:
Brett Cannon wrote:
Taking a new argument that has a default shouldn't be an issue. +1 from me. I assume it is just going to start the count at that number, not advance the iterable to that point, right?
I wonder if it would be best for it to be a keyword-only argument. So many of the utility functions on iterables are foo(*iterables) that I might be inclined to think enumerate(foo, bar) is equivalent to enumerate(chain(foo, bar)), but enumerate(foo, start=bar) is pretty obvious. And if you consider that the enumeration is prepended to the values of foo, enumerate(foo, bar) is "backwards." Just saying..
Sure, making it 'start' or something and having it be keyword-only makes sense. -Brett
Brett Cannon wrote:
Sure, making it 'start' or something and having it be keyword-only makes sense.
http://bugs.python.org/issue2831 -Scott -- Scott Dial scott@scottdial.com scodial@cs.indiana.edu
On Mon, 12 May 2008 08:20:51 am Georg Brandl wrote:
I believe the following is a common use-case for enumerate() (at least, I've used it quite some times):
for lineno, line in enumerate(fileobject): ...
For this, it would be nice to have a start parameter for enumerate().
Why would it be nice? What would you use it for? The only thing I can think of is printing lines with line numbers, and starting those line numbers at one instead of zero. If that's the only use-case, should it require built-in support? -- Steven
On Sun, May 11, 2008 at 4:42 PM, Steven D'Aprano <steve@pearwood.info> wrote:
On Mon, 12 May 2008 08:20:51 am Georg Brandl wrote:
I believe the following is a common use-case for enumerate() (at least, I've used it quite some times):
for lineno, line in enumerate(fileobject): ...
For this, it would be nice to have a start parameter for enumerate().
Why would it be nice? What would you use it for?
The only thing I can think of is printing lines with line numbers, and starting those line numbers at one instead of zero. If that's the only use-case, should it require built-in support?
It's a common enough use-case, so I think it makes sense. With the cost being so minimal to add support I think this one use-case alone is enough to justify adding the support. -Brett
2008/5/11, Brett Cannon <brett@python.org>:
It's a common enough use-case, so I think it makes sense. With the cost being so minimal to add support I think this one use-case alone is enough to justify adding the support.
+1 -- . Facundo Blog: http://www.taniquetil.com.ar/plog/ PyAr: http://www.python.org/ar/
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Greg Ewing wrote: | Steven D'Aprano wrote: |> The only thing I can think of is printing lines with line numbers | | Parsing a file and wanting to be able to print | error messages with line numbers would seem to | be a fairly likely use. What is wrong with: for lineno,line in enumerate(file) : ~ print lineno+1,line :-? - -- Jesus Cea Avion _/_/ _/_/_/ _/_/_/ jcea@jcea.es - http://www.jcea.es/ _/_/ _/_/ _/_/ _/_/ _/_/ jabber / xmpp:jcea@jabber.org _/_/ _/_/ _/_/_/_/_/ ~ _/_/ _/_/ _/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/ _/_/ _/_/ _/_/ _/_/ "My name is Dump, Core Dump" _/_/_/ _/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.8 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iQCVAwUBSCnopJlgi5GaxT1NAQJSAAP/V8U23owV+YjGiAKQbZOb6FIXA6Wfll65 /oLg1WuzQ/KBre41LJ3sw4RS8+FThrfihe56nYmJagnkvo353rceb/W45T85b17Y +VXg33jQy8UkoJX2a0YwFP8jZPO+5iWlO6zUc44iisBmh8BeLCMQAJHl6+0pJfqQ /cp/BLcxEYI= =T1Bc -----END PGP SIGNATURE-----
Steven D'Aprano wrote:
On Mon, 12 May 2008 08:20:51 am Georg Brandl wrote:
I believe the following is a common use-case for enumerate() (at least, I've used it quite some times):
for lineno, line in enumerate(fileobject): ...
For this, it would be nice to have a start parameter for enumerate().
Why would it be nice? What would you use it for?
The only thing I can think of is printing lines with line numbers, and starting those line numbers at one instead of zero. If that's the only use-case, should it require built-in support?
It's fairly common in financial applications to number checks in batches, from a starting point that depends on the number of checks issued in previous runs. Having a start point would allow this to be done more simply, though it's not anyway what I would call an onerous task. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 Holden Web LLC http://www.holdenweb.com/
"Steven D'Aprano" <steve@pearwood.info> wrote:
On Mon, 12 May 2008 08:20:51 am Georg Brandl wrote:
I believe the following is a common use-case for enumerate() (at least, I've used it quite some times):
for lineno, line in enumerate(fileobject): ...
For this, it would be nice to have a start parameter for enumerate().
Why would it be nice? What would you use it for?
The only thing I can think of is printing lines with line numbers, and starting those line numbers at one instead of zero. If that's the only use-case, should it require built-in support?
If you are generating paginated output then a function to generate an arbitrary page would likely want to enumerate starting at some value larger than one. Of course in that case you'll also want to skip part way through the data, but I think it is more likely that you'll want to enumerate the partial data (e.g. if it is a database query) rather than slice the enumeration.
"Duncan Booth" <duncan.booth@suttoncourtenay.org.uk> wrote in message news:Xns9A9DA3EB5E8EBduncanrcpcouk@127.0.0.1... | | If you are generating paginated output then a function to generate an | arbitrary page would likely want to enumerate starting at some value larger | than one. | | Of course in that case you'll also want to skip part way through the data, | but I think it is more likely that you'll want to enumerate the partial | data (e.g. if it is a database query) rather than slice the enumeration. Not if the data is split across multiple files. I remember editing and printing a book from multiple files. Decent word processors have an option to start page numbering at something other than 1. Much bigger memories perhaps make this less common now.
Georg Brandl wrote:
I believe the following is a common use-case for enumerate() (at least, I've used it quite some times):
for lineno, line in enumerate(fileobject): ...
For this, it would be nice to have a start parameter for enumerate(). The changes are minimal -- okay for 2.6?
I'd like to hear from Raymond before we do this. I'm pretty sure we had a reason for *not* doing it that way in when enumerate() was added, but I can't remember what that reason might have been... Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
"Nick Coghlan" <ncoghlan@gmail.com> wrote in message news:4828C59B.8070008@gmail.com... | I'd like to hear from Raymond before we do this. I'm pretty sure we had | a reason for *not* doing it that way in when enumerate() was added, but | I can't remember what that reason might have been... http://bugs.python.org/issue2831
Terry Reedy wrote:
"Nick Coghlan" <ncoghlan@gmail.com> wrote in message news:4828C59B.8070008@gmail.com... | I'd like to hear from Raymond before we do this. I'm pretty sure we had | a reason for *not* doing it that way in when enumerate() was added, but | I can't remember what that reason might have been...
Thanks. I think this part is the main reason I see a start argument to enumerate as potentially problematic: """all variants can easily be misread as starting at the nth item in the sequence (much like islice() does now): enumerate(3, 'abcdefg') --> (3,'d') (4,'e') (5, 'f') (6, 'g').""" Is the need to use zip(count(3), seq) for the offset index case really such a burden given the associated benefits in keeping the builtin function really simple and easy to understand? Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
On Tue, May 13, 2008 at 2:40 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Terry Reedy wrote:
"Nick Coghlan" <ncoghlan@gmail.com> wrote in message news:4828C59B.8070008@gmail.com... | I'd like to hear from Raymond before we do this. I'm pretty sure we had | a reason for *not* doing it that way in when enumerate() was added, but | I can't remember what that reason might have been...
Thanks. I think this part is the main reason I see a start argument to enumerate as potentially problematic:
"""all variants can easily be misread as starting at the nth item in the sequence (much like islice() does now): enumerate(3, 'abcdefg') --> (3,'d') (4,'e') (5, 'f') (6, 'g')."""
So the ambiguity is that enumerate(it, start=N) could be taken as skipping the first N items of it rather than adding N to the index it returns. (And it is my own argument!) I'd like to withdraw this argument. There are two separate use cases for using enumerate(): one is to iterate over a sequence and to have a handy index by which to update the value in the sequence. Another is for 1-based counting, usually when printing 1-based ordinals (such as line numbers in files, dates in a month or months in a year, etc.). N-based counting is less common but still conceivable. However I see no use for skipping items from the start, and if that use case ever came up, passing a slice to enumerate() would be the appropriate thing to do. In fact, if you passed in a slice, you might also want to pass a corresponding start value so the indices produced match those of the original sequence. So, I am still in favor of adding a new argument to enumerate(). I'm neutral on the need for a keyword (don't think it would hurt, not sure how much it matters). I'm strongly against making it an optional *leading* argument like Raymond proposed; that's a style I just don't want to promote, range() and the curses module notwithstanding.
Is the need to use zip(count(3), seq) for the offset index case really such a burden given the associated benefits in keeping the builtin function really simple and easy to understand?
Yes, zip(count(3), seq) is too complex for this simple use case. I've always solved this so far with this less-than-elegant but certainly simpler idiom (except for users stuck in the tradition of for-loops in certain older languages :-): for i, line in enumerat(lines): i += 1 print "%4d. %s" % (i, line) and variants thereof. [Also added to the issue.] -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Wed, 14 May 2008 12:25:01 am Guido van Rossum wrote:
However I see no use for skipping items from the start,
You've never had to deal with data where the first N items were special in some way? e.g. skipping over a header line in a file? I know I've written code like this before: it = iter(whatever()) for i in xrange(N): # skip the first N items it.next() for item in it: process(item)
and if that use case ever came up, passing a slice to enumerate() would be the appropriate thing to do.
While slices are wonderfully useful things, they aren't panaceas. They're not so useful with iterators, and they make a copy of the data, which can be problematic if there's a *lot* of it. [tongue firmly in cheek] Perhaps what we need is a more flexible enumerate function? enumerate(iterable, start_at_index=0, count_from=0) Having a consistent index provided by enumerate reduces the amount of thought I have to put into the loop structure, and avoids the temptation to do this: for i, item in enumerate(seq, start=1): print "line %d: %s" % (i, item) # subtract one from the index to adjust for one-based counting seq[i-1] = foo(item) I never need to think about whether it is zero-based, one-based, or some other N-based counting, because it is always zero-based. -0 on any change to enumerate. -- Steven D'Aprano
2008/5/13, Steven D'Aprano <steve@pearwood.info>:
Perhaps what we need is a more flexible enumerate function? enumerate(iterable, start_at_index=0, count_from=0)
+1 to provide both options: they're not intrusive (as I can keep using enumerate without those), and having both helps in the understanding of the function. I mean, if I find an option that is "start", I can confuse if it will start counting or giving me the elements of the iterable... if I found both parameters, it will be easier to understand. Regards, -- . Facundo Blog: http://www.taniquetil.com.ar/plog/ PyAr: http://www.python.org/ar/
On Tue, May 13, 2008 at 11:59 AM, Facundo Batista <facundobatista@gmail.com> wrote:
2008/5/13, Steven D'Aprano <steve@pearwood.info>:
Perhaps what we need is a more flexible enumerate function? enumerate(iterable, start_at_index=0, count_from=0)
+1 to provide both options: they're not intrusive (as I can keep using enumerate without those), and having both helps in the understanding of the function.
I mean, if I find an option that is "start", I can confuse if it will start counting or giving me the elements of the iterable... if I found both parameters, it will be easier to understand.
Actually, having both dramatically increases the potential for confusion. Once you have the starting index option, you're always going to be worried about whether the first index generated defaults to zero or to the starting index, since depending on your use case one or the other is vastly more useful... We already have itertools.islice() which can handle both of these easily (slice the input or slice the output). -1 on providing a start index. +1 on providing a start value for the count, making it a positional-with-optional-keyword-name ('start') parameter. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum schrieb:
On Tue, May 13, 2008 at 11:59 AM, Facundo Batista <facundobatista@gmail.com> wrote:
2008/5/13, Steven D'Aprano <steve@pearwood.info>:
Perhaps what we need is a more flexible enumerate function? enumerate(iterable, start_at_index=0, count_from=0)
+1 to provide both options: they're not intrusive (as I can keep using enumerate without those), and having both helps in the understanding of the function.
I mean, if I find an option that is "start", I can confuse if it will start counting or giving me the elements of the iterable... if I found both parameters, it will be easier to understand.
Actually, having both dramatically increases the potential for confusion. Once you have the starting index option, you're always going to be worried about whether the first index generated defaults to zero or to the starting index, since depending on your use case one or the other is vastly more useful...
We already have itertools.islice() which can handle both of these easily (slice the input or slice the output).
-1 on providing a start index. +1 on providing a start value for the count, making it a positional-with-optional-keyword-name ('start') parameter.
This is what's now implemented in SVN. Thanks for the discussion! cheers, Georg
On Tue, May 13, 2008 at 11:53 AM, Steven D'Aprano <steve@pearwood.info> wrote:
On Wed, 14 May 2008 12:25:01 am Guido van Rossum wrote:
However I see no use for skipping items from the start,
You've never had to deal with data where the first N items were special in some way? e.g. skipping over a header line in a file?
Of course I have. But never in the argument to enumerate(). [...]
and if that use case ever came up, passing a slice to enumerate() would be the appropriate thing to do.
While slices are wonderfully useful things, they aren't panaceas. They're not so useful with iterators, and they make a copy of the data, which can be problematic if there's a *lot* of it.
That's why we have itertools.islice(). -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Wed, 14 May 2008 05:01:20 am you wrote:
While slices are wonderfully useful things, they aren't panaceas. They're not so useful with iterators, and they make a copy of the data, which can be problematic if there's a *lot* of it.
That's why we have itertools.islice().
I always forget itertools. Perhaps I should engrave it on my monitor as a reminder. With iterators being such a fundamental part of Python these days, perhaps one day we'll see the functions in the itertools module become iterator methods, as happened with strings. But that's a discussion for another day. -- Steven
On Tue, May 13, 2008 at 3:11 PM, Steven D'Aprano <steve@pearwood.info> wrote:
With iterators being such a fundamental part of Python these days, perhaps one day we'll see the functions in the itertools module become iterator methods, as happened with strings. But that's a discussion for another day.
Unlikely. Every method needs to be reimplemented for each type that is expected to support it. There are only two string types, so that's manageable. But there are many dozens of iterator types. Insisting on a common base class would be unpythonic. Plus, the functional approach makes it possible to treat various non-iterators (like sequences and other iterables) the same way. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Steven D'Aprano wrote:
With iterators being such a fundamental part of Python these days, perhaps one day we'll see the functions in the itertools module become iterator methods
I hope not. The set of potential functions that operate on iterators is open-ended, and there's no reason to single out a particular subset and make them methods. Also, it would force all iterators to inherit from a common base class in order to support those methods, which is not a Pythonic thing to do. Strings are different, because (a) they're a concrete class, and (b) string methods benefit from having access to implementation details of the string. -- Greg
Greg Ewing wrote:
Steven D'Aprano wrote:
With iterators being such a fundamental part of Python these days, perhaps one day we'll see the functions in the itertools module become iterator methods
I hope not. The set of potential functions that operate on iterators is open-ended, and there's no reason to single out a particular subset and make them methods.
I've occasionally experimented with the idea of a 'FlexibleIterator' class that accepted an arbitrary iterable in it's constructor and then used itertools internally to provide native support for concatenation (via itertools.chain) and slicing (via itertools.islice), but have never been able to come up with anything which didn't lend itself to fundamental misunderstanding of what it was doing. I've come to the conclusion that there are some aspects of dealing with arbitrary iterators where trying to make it look 'pretty' starts to hide things that the programmer really needs to be aware of in order to reason correctly about the program. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
Steven D'Aprano wrote: [...]
[tongue firmly in cheek] Perhaps what we need is a more flexible enumerate function? enumerate(iterable, start_at_index=0, count_from=0)
Super idea. Then we can have a thread about whether it belongs in itertools or somewhere else. [...] Please take your tongue out of your cheek immediately. I am beginning to feel somewhat uncomfortable on your behalf. regards Steve -- Steve Holden +1 571 484 6266 +1 800 494 3119 Holden Web LLC http://www.holdenweb.com/
participants (13)
-
A.M. Kuchling
-
Brett Cannon
-
Duncan Booth
-
Facundo Batista
-
Georg Brandl
-
Greg Ewing
-
Guido van Rossum
-
Jesus Cea
-
Nick Coghlan
-
Scott Dial
-
Steve Holden
-
Steven D'Aprano
-
Terry Reedy