An implementation of a variation on "for 1 <= i <= 10" [was Re: PEP 276 Simple Iterator for ints (fwd)]

Nick Mathewson QnickQm at alum.mit.edu
Thu Dec 6 20:00:16 EST 2001


A while ago, Greg (I believe) proposed an alternative to PEP-276 that
would allow iteration syntax of the form "for 1 <= i <= 10".

In article <eppstein-2691AC.13312906122001 at news.service.uci.edu>, 
       David Eppstein wrote:
 [...]
> But anyway, it would also be acceptable to me to use a syntax like
> "for i in lb < ... <= ub". This would also answer the other common 
> objection that all for-loops must use "for var in iterator" syntax.
> I prefer the other syntax, because I think this one is verbose in a way 
> that doesn't actually improve readability (verbosity that improves 
> readability is better than conciseness, though).

Here's some code that implements almost this behavior.  Now you can type:

for i in 1 <= ints <= 10:
   print i

I don't have "for i in ints <= 10" going yet, but that should be a fairly
easy extension.

This code requires that you have at least Python 2.2 for the iterator
logic to work.  Python2.2 is still in beta, but hey -- so is this
code. :)

============================================================
#!/usr/bin/python

class Integers:
    def __init__(self, step=None, auto=0):
	self.lb = None   #Lower bound (inclusive)
	self.ub = None   #Upper bound (inclusive)
	self.up = None   #Flag: Are we counting up (a<i<c) or down (a>i>c)?
	self.step = step #Stepping increment
	self.auto = auto #Automatically return an iterator when we have 2
	                 # bounds?

    def __gt__(self, n):
	self.lb = n+1
	if self.ub == None: self.up = 1	
	if self.auto and self.ub != None and self.lb != None:
	    return iter(self)
	else:
	    return self

    def __lt__(self, n):
	self.ub = n-1
	if self.lb == None: self.up = 0
	if self.auto and self.ub != None and self.lb != None:
	    return iter(self)
	else:
	    return self

    def __ge__(self, n):
	self.lb=n
	if self.ub == None: self.up = 1
	if self.auto and self.ub != None and self.lb != None:
	    return iter(self)
	else:
	    return self

    def __le__(self, n):
	self.ub=n
	if self.lb == None: self.up = 0
	if self.auto and self.ub != None and self.lb != None:
	    return iter(self)
	else:
	    return self

    def __nonzero__(self):
	return 1

    def __iter__(self):
	if self.step == None:
	    self.step = (-1, 1)[self.up]
	else:
	    assert self.step != 0 and self.up == (self.step > 0)
    
	if self.up:
	    return iter(xrange(self.lb, self.ub+1, self.step))
	else:
	    return iter(xrange(self.ub, self.lb-1, self.step))

ints = Integers(step=1, auto=1)

if __name__=='__main__':

    assert [i for i in 1 <= Integers() <= 10] == range(1,11)
    assert [i for i in 10 >= Integers() >= 1] == range(10,0,-1)

    assert [i for i in 1 < Integers() < 10] == range(2,10)
    assert [i for i in 10 > Integers() > 1] == range(9,1,-1)

    assert [i for i in 1 < Integers() <= 10] == range(2,11)
    assert [i for i in 10 > Integers() >= 1] == range(9,0,-1)

    assert [i for i in 1 <= Integers() < 10] == range(1,10)
    assert [i for i in 10 >= Integers() > 1] == range(10,1,-1)
 
    assert [i for i in 2 <= Integers(step=2) < 99] == range(2,99,2)

    n = 0
    for i in 1 <= ints <= 10:
	for j in 1 <= ints <= 10:
	    n += 1
    assert n == 100 
    
    assert zip(1 <= ints <= 3, 1 <= ints <= 3) == zip((1,2,3), (1,2,3))
	   
============================================================

What-a-tangled-web-we-weave-when-iterators-interleave'ly yours,

-- 
 Nick Mathewson    <Q nick Q m at alum dot mit dot edu>
                      Remove Q's to respond.  No spam.



More information about the Python-list mailing list