Is using range() in for loops really Pythonic?

J

John Salerno

I know it's popular and very handy, but I'm curious if there are purists
out there who think that using something like:

for x in range(10):
#do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

Anyone out there refuse to use it this way, or is it just impossible to
avoid?
 
M

Matt Nordhoff

John said:
I know it's popular and very handy, but I'm curious if there are purists
out there who think that using something like:

for x in range(10):
#do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

Anyone out there refuse to use it this way, or is it just impossible to
avoid?

Well, you should use "xrange(10)" instead of "range(10)". While range()
returns a list of every single number, xrange() returns an iterable
object that only generates them on-demand, so xrange(1) and
xrange(sys.maxint) will use the same amount of RAM.

(Not that it matters when it's only 10 items, of course.)

Other than that, "for i in xrange(10)" is a standard Python idiom, even
though it is a bit weird.
--
 
7

7stud

I know it's popular and very handy, but I'm curious if there are purists
out there who think that using something like:

for x in range(10):
    #do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

x = range(10)
print x

--output:--
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 
P

Paddy

I know it's popular and very handy, but I'm curious if there are purists
out there who think that using something like:

for x in range(10):
#do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

Anyone out there refuse to use it this way, or is it just impossible to
avoid?

Hi John,
If you have an object that is both indexable and iterable, then
visiting every member by first generating an index then indexing the
object is un-pythonic. You should just iterate over the object.

Like most rules, things can get fuzzy around the edges: if you have n
objects to be visited each index at a time, then the more functional
approach would be to izip all the objects and iterate over the result.
Another way would be to iterate over the the enumeration of one object
and use the index created to index the other n-1 objects.

In all such situations you need to remember that things such as code
clarity, and speed, might make the final decision for you.


In the following examples then the first is what I would use, izip. If
I needed an index then I'd prefer the last, which combines izip and
enumerate:

PythonWin 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit
(Intel)] on win32.
Portions Copyright 1994-2006 Mark Hammond - see 'Help/About PythonWin'
for further copyright information.
... print x,y,z
...
C a t
S u m
M e n ... print x, obj2, obj3
...
C a t
S u m
M e n ... print obj1, obj2, obj3
...
C a t
S u m
M e n ... print i, x, y, z
...
0 C a t
1 S u m
2 M e n

- Paddy.
 
P

Paul Rubin

John Salerno said:
for x in range(10):
#do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

It is pretty natural in imperative-style code. The one thing I'd do
differently is use xrange instead of range, to avoid creating a
10-element list in memory before starting the loop.
 
X

XLiIV

I know it's popular and very handy, but I'm curious if there are purists
out there who think that using something like:

for x in range(10):
    #do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

Anyone out there refuse to use it this way, or is it just impossible to
avoid?

The range() function returns a list and list is a sequence, isn't?
 
C

castironpi

It is pretty natural in imperative-style code.  The one thing I'd do
differently is use xrange instead of range, to avoid creating a
10-element list in memory before starting the loop.

If you give extras to memory, can Python live?
 
J

John Salerno

John said:
I know it's popular and very handy, but I'm curious if there are purists
out there who think that using something like:

for x in range(10):
#do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

Anyone out there refuse to use it this way, or is it just impossible to
avoid?

Ok, I think most people are misunderstanding my question a little. I
probably should have said xrange instead of range, but the point of my
question remains the same:

Should a for loop be used simply to do something X number of times, or
should it strictly be used to step through an iterable object for the
purpose of processing the items in that object?
 
T

Terry Reedy

I know it's popular and very handy, but I'm curious if there are purists
out there who think that using something like:

for x in range(10):
#do something 10 times

is unPythonic. The reason I ask is because the structure of the for loop
seems to be for iterating through a sequence. It seems somewhat
artificial to use the for loop to do something a certain number of
times, like above.

Anyone out there refuse to use it this way, or is it just impossible to
avoid?

|The range() function returns a list and list is a sequence, isn't?

yes, for loops iterate thru any iterable
 
J

John Salerno

XLiIV said:
The range() function returns a list and list is a sequence, isn't?

I think you're missing the point. To me, there seems to be a fundamental
difference between these two things:

---

people = ['Sam', 'Bob', 'Fred']

for name in people:
print name

---

AND

---

num = 33

for x in xrange(10):
print num += 1

---

To me, the first example is a pure use of the for loop. You are
iterating through an object and *using* the items you are stepping through.

The second example, however, is simply doing something 10 times, and
what it's doing has nothing to do with 'x' or xrange. So it seems like
an abuse of the for loop.
 
A

Arnaud Delobelle

John Salerno said:
Ok, I think most people are misunderstanding my question a little. I
probably should have said xrange instead of range, but the point of my
question remains the same:

Should a for loop be used simply to do something X number of times, or
should it strictly be used to step through an iterable object for the
purpose of processing the items in that object?

It makes me feel slightly uncomfortable too, but AFAIK there is no
better way in Python. What I sometimes do is make the for loop bind
its variable to something useful instead of an unused counter.
Contrived example:

# Print 'hello' 10 times; x is not used
for x in xrange(10):
print 'hello'

# By changing what is iterated over, no unused variable:
from itertools import repeat
for msg in repeat('hello', 10):
print msg
 
Y

Yves Dorfsman

John said:
To me, the first example is a pure use of the for loop. You are
iterating through an object and *using* the items you are stepping through.

The second example, however, is simply doing something 10 times, and
what it's doing has nothing to do with 'x' or xrange. So it seems like
an abuse of the for loop.

Well, I would say this:
myl = ['a', 'b', 'c', 'd']
for i in xrange(len(myl)):
print myl

As you would see in other languages, is an abuse in python. But in you need
to iterate 5 times over something. Do you have a cleaner / python'er
alternative ?

Do you find the following cleaner:

x = 0
while x <= 4:
print x
x += 1



Yves.
http://www.SollerS.ca
 
J

Jonathsn Cronin

XLiIV said:
The range() function returns a list and list is a sequence, isn't?

I think you're missing the point. To me, there seems to be a fundamental
difference between these two things:

---

people = ['Sam', 'Bob', 'Fred']

for name in people:
print name

---

AND

---

num = 33

for x in xrange(10):
print num += 1

---

To me, the first example is a pure use of the for loop. You are
iterating through an object and *using* the items you are stepping through.

The second example, however, is simply doing something 10 times, and
what it's doing has nothing to do with 'x' or xrange. So it seems like
an abuse of the for loop.

I agree in principle; the first is iteration and the second is repetition.
In Python, the common idiom for a fixed number of repetitions is iterating
over a number range. This is true in most languages I am familiar with,
probably because fixed repetition, where you don't care about the "index"
value, is rarely used.

The only language I've used that does have fixed repetition is an (old)
dialect of lisp, and I'm not sure it even made it into Common Lisp.
Smalltalk and Ruby do have fixed repetition.

Using range may not be entirely elegant, but is pragmatic, and not, to me,
particularly ugly. In Python, unlike some languages, you don't have to
declare the x.

I think you could add it without too much change to the parsing.

for <expression>:
<block>

Seeing a ":" instead of "in" would mean a repetition statement which would
be interpreted as:
-- if <expression> evaluates to an integer, execute the block that number of
times.
-- If <expression> evaluates to an iterator, execute the block until the
iterator is exhausted.

Even if possible, I see this at best a minor improvement and more likely a
negative because the for keyword is now overloaded. (see "static" in C/Java.)
You could add a new keyword but the benefit here is much to small to justify
the trouble.

Jonathan
 
C

Carl Banks

In such cases, the name 'dummy' is conventionally bound to the items
from the iterator, for clarity of purpose::

for dummy in range(10):
# do stuff that makes no reference to 'dummy'

Is this documented? I've never heard of this convention. It's not
PEP 8, and I've never seen consistent usage of any name. I'd be
interested in knowing where you read that this was a convention, or in
what subcommunities it's a convention in.

I think dummy is a terrible name to use for this, since in no other
usage I can think of does the word "dummy" suggest something isn't
used. In fact, quite the opposite. For example, the dummy_threads
module is most definitely used; the word dummy means that it's
stripped down. Based on that, your usage of the symbol dummy above
would suggest to me that it's a value used in lieu of something else
(such as a calculated value).

In mathematics, a dummy argument another name for the independent
variable of a function (or more accurately, the symbol used to
represent it), which also doesn't match your usage.

If a value isn't used, then I think the most clear name for it is
"unused".


Carl Banks
 
I

Ivan Illarionov

Is this documented? I've never heard of this convention. It's not PEP
8, and I've never seen consistent usage of any name. I'd be interested
in knowing where you read that this was a convention, or in what
subcommunities it's a convention in.

I think dummy is a terrible name to use for this, since in no other
usage I can think of does the word "dummy" suggest something isn't used.
In fact, quite the opposite. For example, the dummy_threads module is
most definitely used; the word dummy means that it's stripped down.
Based on that, your usage of the symbol dummy above would suggest to me
that it's a value used in lieu of something else (such as a calculated
value).

In mathematics, a dummy argument another name for the independent
variable of a function (or more accurately, the symbol used to represent
it), which also doesn't match your usage.

If a value isn't used, then I think the most clear name for it is
"unused".


Carl Banks

I agree with Carl. This group is the only place I've heard about this
convension and it looks terrible IMO. Even if a value is not used, the
variable still has a meaning: it is a counter, or an index.

I know about the other convention: "for i in xrange" or "for i in range".
Wikipedia agrees with me:
http://en.wikipedia.org/wiki/For_loop
Examples in wikipedia article use either "i" or "counter".

It is established convention in almost every programming language and its
origins are in mathematics (matrix indices).

Google search for "for dummy in range" (with quotes) gives 164 results
While "for dummy in range" gives 146 000 results. Almost thousand times
more.

So, "i" is more conventional and as such is more readable.

-- Ivan
 
J

John Salerno

Ben said:
Which is better done by 'num += 10'.

Can you come up with an example that isn't trivially replaced with
clearer code? That might make it clearer what your concern is.

::sigh:: No, unfortunately I don't have a strong enough grasp of Python
to give a really in-depth example. I understand what you're asking
though. Perhaps people don't use this idiom as much as I think they do,
so to give a trivial example to support my point isn't helpful.

As far as I know, though, I think this is used often enough, so I
thought I'd just ask if there are purists out there who don't like this
use of the loop and feel it's an abuse of the syntax.
 
C

Carl Banks

It's not a documented standard, to my knowledge.


It has been in this forum that the use of the name '_' for "don't care
about the value" was deprecated, since that name is already overloaded
with other meanings.

That doesn't follow at all from what you wrote: no one in this thread
had even mentioned the usage of "_" for unused values--how did you
expect us to know you were talking about something no one brought up?

So it seems that usage of "dummy" is not a convention, and avoidance
of "_" is not really a convention except on this group.

I think it's far superior to '_'. I'd be just as happy with any other
name that explicitly distinguishes itself for this purpose.


Sounds good to me. Now we merely need to convince the world.

I'm happy to discourage the world from using "_" for this purpose;
ambivalent whether you even need to use a specific name.


Carl Banks
 
I

Ivan Illarionov

In such cases, the name 'dummy' is conventionally bound to the items
from the iterator, for clarity of purpose
[..]
If a value isn't used, then I think the most clear name for it is
"unused".
[...]

Maybe my brain works differently, but I find both "dummy" and "unused"
are extremely confusing names for loop counters. The loop begins to look
like it doesn't iterate at all if its counter is dummy or unused.

If it *counts* it is *used* and it's *not* dummy.

Why reinvent the wheel when "a common identifier naming convention is for
the loop counter to use the variable names i, j and k (and so on if
needed)" (from Wikipedia http://en.wikipedia.org/wiki/Loop_counter )

-- Ivan
 
P

Paddy

Contrived example:

# Print 'hello' 10 times; x is not used
for x in xrange(10):
print 'hello'

I've used Fortran and C and so would tend to use either i,j,k as the
unused loop variable above, or, for clarity, call it something
descriptive like loop_count, if the loop body would be clearer.

I would also just use range for small, (especially small constant),
ranges.
# By changing what is iterated over, no unused variable:
from itertools import repeat
for msg in repeat('hello', 10):
print msg
I guess I would not go to the trouble of using itertools.repeat unless
it was simplifying/homogenising a larger expression - i.e if it was
part of some functional expression

I've never fealt the need for a separate repeat statement myself
either.

- Paddy.

P.S: I do understand that your examples are contrived. Just my
thoughts.
 
I

Ivan Illarionov

]
That is also regrettably common in Python code. It still suffers from
being unnecessarily ambiguous, since there are *also* plenty of loops
using 'i', 'j', etc. where the loop counter *is* used.

Differentiating these use cases by appropriate naming is, IMO, worth the
effort of choosing a meaningful name.

Even if the counter is not used inside the loop's body it's still in
control of the whole loop and, IMO, any special discriminating and non-
conventional name doesn't worth the added confusion.

-- Ivan
 

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,754
Messages
2,569,527
Members
44,998
Latest member
MarissaEub

Latest Threads

Top