[ZPT] CVS: Releases/Zope/lib/python/ZTUtils - CHANGES.txt:1.6.8.1 Iterator.py:1.3.2.1
Evan Simpson
evan@zope.com
Thu, 13 Dec 2001 15:26:03 -0500
Update of /cvs-repository/Releases/Zope/lib/python/ZTUtils
In directory cvs.zope.org:/tmp/cvs-serv20474/ZTUtils
Modified Files:
Tag: Zope-2_5-branch
CHANGES.txt Iterator.py
Log Message:
Merge changes from trunk
=== Releases/Zope/lib/python/ZTUtils/CHANGES.txt 1.6 => 1.6.8.1 ===
Version 1.1.4
+ Features Added
+
+ - Under Python 2.2, Iterator both accepts and produces Python
+ iterator objects.
+
+ - first() and last() methods allow you to tell whether the
+ current element is different from the next or previous
+ element. This is most useful when the sequence is sorted.
+
Bugs Fixed
- Handle both string and class Unauthorized exceptions.
=== Releases/Zope/lib/python/ZTUtils/Iterator.py 1.3 => 1.3.2.1 ===
__doc__='''Iterator class
+Unlike the builtin iterators of Python 2.2+, these classes are
+designed to maintain information about the state of an iteration.
+The Iterator() function accepts either a sequence or a Python
+iterator. The next() method fetches the next item, and returns
+true if it succeeds.
+
$Id$'''
__version__='$Revision$'[11:-2]
@@ -21,21 +27,39 @@
'''Simple Iterator class'''
__allow_access_to_unprotected_subobjects__ = 1
-
+
+ nextIndex = 0
def __init__(self, seq):
self.seq = seq
- self.nextIndex = 0
+ for inner in seqInner, iterInner:
+ if inner._supports(seq):
+ self._inner = inner
+ self._prep_next = inner.prep_next
+ return
+ raise TypeError, "Iterator does not support %s" % `seq`
- def next(self):
- i = self.nextIndex
+ def __getattr__(self, name):
try:
- self.seq[i]
- except IndexError:
+ inner = getattr(self._inner, 'it_' + name)
+ except AttributeError:
+ raise AttributeError, name
+ return inner(self)
+
+ def next(self):
+ if not (hasattr(self, '_next') or self._prep_next(self)):
return 0
- self.index = i
+ self.index = i = self.nextIndex
self.nextIndex = i+1
+ self._advance(self)
return 1
+ def _advance(self, it):
+ self.item = self._next
+ del self._next
+ del self.end
+ self._advance = self._inner.advance
+ self.start = 1
+
def number(self): return self.nextIndex
def even(self): return not self.index % 2
@@ -67,16 +91,108 @@
def roman(self, lower=string.lower):
return lower(self.Roman())
- def start(self): return self.nextIndex == 1
+ def first(self, name=None):
+ if self.start: return 1
+ return not self.same_part(name, self._last, self.item)
+
+ def last(self, name=None):
+ if self.end: return 1
+ return not self.same_part(name, self.item, self._next)
+
+ def same_part(self, name, ob1, ob2):
+ if name is None:
+ return ob1 == ob2
+ no = []
+ return getattr(ob1, name, no) == getattr(ob2, name, no) is not no
+
+ def __iter__(self):
+ return IterIter(self)
+
+class InnerBase:
+ '''Base Inner class for Iterators'''
+ # Prep sets up ._next and .end
+ def prep_next(self, it):
+ it.next = self.no_next
+ it.end = 1
+ return 0
- def end(self):
- try: self.seq[self.nextIndex]
- except IndexError: return 1
+ # Advance knocks them down
+ def advance(self, it):
+ it._last = it.item
+ it.item = it._next
+ del it._next
+ del it.end
+ it.start = 0
+
+ def no_next(self, it):
return 0
- def item(self):
- return self.seq[self.index]
+ def it_end(self, it):
+ if hasattr(it, '_next'):
+ return 0
+ return not self.prep_next(it)
+
+class SeqInner(InnerBase):
+ '''Inner class for sequence Iterators'''
+
+ def _supports(self, ob):
+ try: ob[0]
+ except TypeError: return 0
+ except: pass
+ return 1
+
+ def prep_next(self, it):
+ i = it.nextIndex
+ try:
+ it._next = it.seq[i]
+ except IndexError:
+ it._prep_next = self.no_next
+ it.end = 1
+ return 0
+ it.end = 0
+ return 1
+
+ def it_length(self, it):
+ it.length = l = len(it.seq)
+ return l
+
+try:
+ StopIteration=StopIteration
+except NameError:
+ StopIteration="StopIteration"
- def length(self):
- return len(self.seq)
+class IterInner(InnerBase):
+ '''Iterator inner class for Python iterators'''
+
+ def _supports(self, ob):
+ try:
+ if hasattr(ob, 'next') and (ob is iter(ob)):
+ return 1
+ except:
+ return 0
+
+ def prep_next(self, it):
+ try:
+ it._next = it.seq.next()
+ except StopIteration:
+ it._prep_next = self.no_next
+ it.end = 1
+ return 0
+ it.end = 0
+ return 1
+
+class IterIter:
+ def __init__(self, it):
+ self.it = it
+ self.skip = it.nextIndex > 0 and not it.end
+ def next(self):
+ it = self.it
+ if self.skip:
+ self.skip = 0
+ return it.item
+ if it.next():
+ return it.item
+ raise StopIteration
+seqInner = SeqInner()
+iterInner = IterInner()