Is there some philosophical reasoning behind why python uses this syntax:
for x in range(1,11,3):
instead of, for example, the BASIC syntax:
for x = 1 to 10 step 3
If Python is supposed to be more human readable than most languages, in this case particular case it seems to be worse than say Sinclair BASIC.
I was trying to think of how a human might express this. Perhaps "With x taking the values 1 through 10:" Seems like the BASIC way is closer.
2 Answers 2
Note that range() is not actually part of the python language; it is a function. Having range be a function means you can plug any other function into a "for in" loop, including functions that don't increase monotonically, functions that lazy-execute, and functions that replace range() with something that better satisfies your personal sensibilities.
In other words, python's way affords you tremendous flexibility to do it however you want.
Your example is not exactly a fair one. It describes a scenario that would be very rare in practice. For a dice roll, it is simply
for x in range(6)
-
I guess that's not too bad. But I wouldn't say it's as readable as BASIC.zooby– zooby2019年11月08日 02:25:36 +00:00Commented Nov 8, 2019 at 2:25
-
2Exactly. There is such a thing as too much readability; it gives you things like COBOL.Kilian Foth– Kilian Foth2019年11月08日 07:16:46 +00:00Commented Nov 8, 2019 at 7:16
-
2It is not about any "function". It is about any "iterable". Ordinary functions are not iterables - generator functions are. Also,
range
is a class, not a function. (A similar generator function to be pluggable infor
loops would be trivial, butrange
objects can respond as full Sequences, with random item access and containment checking (in O(1) time) as well.jsbueno– jsbueno2019年11月08日 15:13:06 +00:00Commented Nov 8, 2019 at 15:13 -
@zooby you aren't understanding,
range
isn't part of the syntax. The syntax, abstractly, would be something likefor <target_name> in <iterable>
which is quite readable. Python for-loops are generally used to iterate over containers/iterables/iterators, and not for these sort of ranges. For that particular case, Python has the built-in iterable typerange
. But again, you rarely see this in any real python code.juanpa.arrivillaga– juanpa.arrivillaga2019年12月03日 23:38:06 +00:00Commented Dec 3, 2019 at 23:38
There are multiple different ways to approach this answer (bold emphasis mine):
What is the reason python uses range in for loops?
This is not a for
loop. It is a foreach
loop. I.e. it is not a loop that loops over a pre-defined set of loop indices, it is an iterator that iterates over the elements of a collection.
In particular, in
for e in [2, 3, 5, 7, 11, 13, 17]:
print(e)
The result will not be
0
1
2
3
4
5
6
but
2
3
5
7
11
13
17
What is the reason python uses range in for loops?
It doesn't. It uses an arbitrary expression. More precisely, an arbitrary expression that evaluates to an iterator or to something that can be implicitly converted to an iterator (such as an iterable):
class MyIterator:
def __init__(self):
self.counter = -1
self.lost = [4, 8, 15, 16, 23, 42]
def __next__(self):
self.counter += 1
if self.counter == 6:
raise StopIteration
return self.lost[self.counter]
class MyIterable:
def __iter__(self):
return MyIterator()
my_iterable = MyIterable()
for num in my_iterable:
print(num)
# 4
# 8
# 15
# 16
# 23
# 42
Is there some philosophical reasoning behind why python uses this syntax
Yes: It is more general and thus makes the language simpler. The BASIC for
loop can do one thing and one thing only: loop over a pre-defined set of loop indices. In fact, it is even more limited than that, because there are further restrictions on the loop indices: they need to be monotonically increasing or decreasing with a fixed step size.
If you want the indices to be non-monotonic, you need a new language construct. If you want the indices to have varying step sizes, you need a new language construct. If you want to iterate over the elements of a collection, you need a new language construct.
With Python's foreach
loop, you can simply have a function that generates indices in whatever order you want, and loop over those. You can iterate over the elements of any arbitrary collection, and note that "collection" is interpreted very broadly.
Actually, you can iterate over the elements of any arbitrary iterator. An iterator can be something very general, and it doesn't even have to be finite, e.g. "all prime numbers".
As I have shown above, it is very easy to create your own custom iterators and iterables. It is in fact even more easy using generator functions:
def my_generator():
yield 4
yield 8
yield 15
yield 16
yield 23
yield 42
for num in my_generator():
print(num)
# 4
# 8
# 15
# 16
# 23
# 42
And even more easy with generator expressions.
If Python is supposed to be more human readable than most languages, in this case particular case it seems to be worse than say Sinclair BASIC.
If you are looping over loop indices in Python (or any modern language, really), you are doing it wrong.
You should be using higher-level iterators instead, such as reduce
(you may also know this one under the name fold
or more general Catamorphism), accumulate
(you may also know this one under the name scan
or prefix-sum), cycle
, chain
, groupby
, or product
. Or, you should be using list / set / dictionary comprehensions, generator expressions, or algorithms and data structures supplied by the standard library or third-party libraries.
-
Well I'm not so sure about the reason about the fixed steps in a for loop. You can easily do: for x=1 to 10 y=f(x) and have y be your variable. With any function you like for f.zooby– zooby2019年11月09日 01:28:50 +00:00Commented Nov 9, 2019 at 1:28
-
for x in [1,3,5,7,11] is just the same as for y=0 to 4; x=[1,3,5,7,11](y). I think it's debatable whether foreach loops or for loops are more readable. In fact I generally find for loops more readable but maybe that's because I learned BASIC first.zooby– zooby2019年11月09日 01:31:44 +00:00Commented Nov 9, 2019 at 1:31
for x in range
is the wrong thing to do in Python. You should instead just iterate the iterable (e.g. list, dict, generator) directly or useenumerate()
instead of usingrange()
.for x range(<whatever>):
, there are almost always better constructs, usually you just want to iterate over the colleciton itself, likefor item in some_list:
. Note,range
isn't a part of the for-statement syntax, it is merely an object, a sequence, that can be iterated over, like any other iterable.