This PEP proposes to simplify iteration over intervals ofintegers, by extending the range of expressions allowed after a“for” keyword to allow three-way comparisons such as
forlower<=var<upper:
in place of the current
foriteminlist:
syntax. The resulting loop or list iteration will loop over allvalues of var that make the comparison true, starting from theleft endpoint of the given interval.
This PEP is rejected. There were a number of fixable issues withthe proposal (see the fixups listed in Raymond Hettinger’spython-dev post on 18 June 2005[1]). However, even with the fixups theproposal did not garner support. Specifically, Guido did not buythe premise that therange() format needed fixing, “The whole point(15 years ago) ofrange() was toavoid needing syntax to specify aloop over numbers. I think it’s worked out well and there’s nothingthat needs to be fixed (exceptrange() needs to become an iterator,which it will in Python 3.0).”
One of the most common uses of for-loops in Python is to iterateover an interval of integers. Python provides functionsrange()andxrange() to generate lists and iterators for such intervals,which work best for the most frequent case: half-open intervalsincreasing from zero. However, therange() syntax is more awkwardfor open or closed intervals, and lacks symmetry when reversingthe order of iteration. In addition, the call to an unfamiliarfunction makes it difficult for newcomers to Python to understandcode that usesrange() orxrange().
The perceived lack of a natural, intuitive integer iterationsyntax has led to heated debate on python-list, and spawned atleast four PEPs before this one.PEP 204 (rejected) proposedto re-use Python’s slice syntax for integer ranges, leading to aterser syntax but not solving the readability problem ofmulti-argumentrange().PEP 212 (deferred) proposed severalsyntaxes for directly converting a list to a sequence of integerindices, in place of the current idiom
range(len(list))
for such conversion, andPEP 281 proposes to simplify the sameidiom by allowing it to be written as
range(list).
PEP 276 proposes to allow automatic conversion of integers toiterators, simplifying the most common half-open case but notaddressing the complexities of other types of interval.Additional alternatives have been discussed on python-list.
The solution described here is to allow a three-way comparisonafter a “for” keyword, both in the context of a for-loop and of alist comprehension:
forlower<=var<upper:
This would cause iteration over an interval of consecutiveintegers, beginning at the left bound in the comparison and endingat the right bound. The exact comparison operations used woulddetermine whether the interval is open or closed at either end andwhether the integers are considered in ascending or descendingorder.
This syntax closely matches standard mathematical notation, so islikely to be more familiar to Python novices than the currentrange() syntax. Open and closed interval endpoints are equallyeasy to express, and the reversal of an integer interval can beformed simply by swapping the two endpoints and reversing thecomparisons. In addition, the semantics of such a loop wouldclosely resemble one way of interpreting the existing Pythonfor-loops:
foriteminlist
iterates over exactly those values of item that cause theexpression
iteminlist
to be true. Similarly, the new format
forlower<=var<upper:
would iterate over exactly those integer values of var that causethe expression
lower<=var<upper
to be true.
We propose to extend the syntax of a for statement, currently
for_stmt:"for"target_list"in"expression_list":"suite["else"":"suite]
as described below:
for_stmt:"for"for_test":"suite["else"":"suite]for_test:target_list"in"expression_list|or_exprless_compor_exprless_compor_expr|or_exprgreater_compor_exprgreater_compor_exprless_comp:"<"|"<="greater_comp:">"|">="
Similarly, we propose to extend the syntax of list comprehensions,currently
list_for:"for"expression_list"in"testlist[list_iter]
by replacing it with:
list_for:"for"for_test[list_iter]
In all cases the expression formed by for_test would be subject tothe same precedence rules as comparisons in expressions. The twocomp_operators in a for_test must be required to be both ofsimilar types, unlike chained comparisons in expressions which donot have such a restriction.
We refer to the two or_expr’s occurring on the left and rightsides of the for-loop syntax as the bounds of the loop, and themiddle or_expr as the variable of the loop. When a for-loop usingthe new syntax is executed, the expressions for both bounds willbe evaluated, and an iterator object created that iterates throughall integers between the two bounds according to the comparisonoperations used. The iterator will begin with an integer equal ornear to the left bound, and then step through the remainingintegers with a step size of +1 or -1 if the comparison operationis in the set described by less_comp or greater_comp respectively.The execution will then proceed as if the expression had been
forvariableiniterator
where “variable” refers to the variable of the loop and “iterator”refers to the iterator created for the given integer interval.
The values taken by the loop variable in an integer for-loop maybe either plain integers or long integers, according to themagnitude of the bounds. Both bounds of an integer for-loop mustevaluate to a real numeric type (integer, long, or float). Anyother value will cause the for-loop statement to raise aTypeErrorexception.
The following issues were raised in discussion of this and relatedproposals on the Python list.
xrange. True, but we see this as ashortcoming in the general list-comprehension syntax, beyond thescope of this proposal. In addition,xrange() will still beavailable.range() orxrange(), or by a list comprehension syntax such as[2*xfor0<=x<=100]
foriteminlist
syntax, leading to a possible loss of readability. We feel thatthis loss is outweighed by the increase in readability from anatural integer iteration syntax.
range()) while this PEP is primarily concernedwith simplifying all other cases. However, if this PEP isapproved, its new simpler syntax for integer loops could to someextent reduce the motivation forPEP 276.floor() andceiling() in integerfor-loops, as it is difficult to use them now withrange(). Wehave erred on the side of flexibility, but this may lead to someimplementation difficulties in determining the smallest andlargest integer values that would cause a given comparison to betrue.int(), and allow as bounds anything that can be soconverted instead of just floats. However, this would changethe semantics:0.3<=x is not the same asint(0.3)<=x, and itwould be confusing for a loop with 0.3 as lower bound to startat zero. Also, in generalint(f) can be very far fromf.An implementation is not available at this time. Implementationis not expected to pose any great difficulties: the new syntaxcould, if necessary, be recognized by parsing a general expressionafter each “for” keyword and testing whether the top leveloperation of the expression is “in” or a three-way comparison.The Python compiler would convert any instance of the new syntaxinto a loop over the items in a special iterator object.
This document has been placed in the public domain.
Source:https://github.com/python/peps/blob/main/peps/pep-0284.rst
Last modified:2025-02-01 08:55:40 GMT