[Python-checkins] r54679 - sandbox/trunk/abc/abc.py sandbox/trunk/abc/test_abc.py

guido.van.rossum python-checkins at python.org
Wed Apr 4 02:17:13 CEST 2007


Author: guido.van.rossum
Date: Wed Apr  4 02:17:12 2007
New Revision: 54679

Modified:
   sandbox/trunk/abc/abc.py
   sandbox/trunk/abc/test_abc.py
Log:
Move the index and slice helpers to global functions.
Add proper slice support for AdaptToSequence.


Modified: sandbox/trunk/abc/abc.py
==============================================================================
--- sandbox/trunk/abc/abc.py	(original)
+++ sandbox/trunk/abc/abc.py	Wed Apr  4 02:17:12 2007
@@ -406,6 +406,56 @@
 ### SEQUENCES ###
 
 
+def _index(i):
+    # Internal helper to raise TypeError for non-integer(-castable) values
+    if not isinstance(i, int):
+        if not hasattr(i, "__index__"):
+            raise TypeError
+        i = i.__index__()
+        if not isinstance(i, int):
+            raise TypeError
+    return i
+
+
+def _slice(slc, size):
+    # Internal helper to normalize a slice into start, stop, step
+    # ints; arguments are a slice object and the length of the
+    # sequence.
+    # XXX A problem this shares with Python 2: a[n-1:-1:-1] (where n
+    # is len(a)) returns an empty slice because the stop value is
+    # normalized to n-1.
+    start, stop, step = slc.start, slc.stop, slc.step
+
+    if start is not None:
+        start = _index(start)
+        if start < 0:
+            start += size
+    if stop is not None:
+        stop = _index(stop)
+        if stop < 0:
+            stop += size
+    if step is not None:
+        step = _index(step)
+
+    if step is None:
+        step = 1
+    if step == 0:
+        raise ValueError
+    if step < 0:
+        if start is None:
+            start = size - 1
+        if stop is None:
+            stop = -1
+    else:
+        if start is None:
+            start = 0
+        if stop is None:
+            stop = size
+
+    return start, stop, step
+    
+
+
 class Sequence(Sizeable, Iterable):
 
     """A minimal sequence.
@@ -418,44 +468,14 @@
     giving an iterable providing the elements.
     """
 
-    def __index(self, i):
-        # Internal helper to raise TypeError for non-integer(-castable) values
-        if not isinstance(i, int):
-            if not hasattr(i, "__index__"):
-                raise TypeError
-            i = i.__index__()
-            if not isinstance(i, int):
-                raise TypeError
-        return i
-
     @abstractmethod
     def __getitem__(self, index):
         if isinstance(index, slice):
-            return self.__getslice(index)
-        index = self.__index(index)
-        raise IndexError
-
-    def __getslice(self, slc):
-        # XXX Would be nice to make this generally available?
-        start, stop, step = slc.start, slc.stop, slc.step
-        for index in start, stop, step:
-            if index is not None:
-                self.__index(index)
-        if step is None:
-            step = 1
-        if step == 0:
-            raise ValueError
-        if step < 0:
-            if start is None:
-                start = len(self) - 1
-            if stop is None:
-                stop = -1
+            start, stop, step = _slice(index, len(self))
+            return self.__class__(self[i] for i in range(start, stop, step))
         else:
-            if start is None:
-                start = 0
-            if stop is None:
-                stop = len(self)
-        return self.__class__(self[i] for i in range(start, stop, step))
+            index = _index(index)
+            raise IndexError
 
     @abstractmethod
     def __len__(self):
@@ -491,7 +511,7 @@
         # XXX Looks like we need an ABC to indicate integer-ness...
         if not isinstance(repeat, int) and not hasattr(repeat, "__index__"):
             return NotImplemented
-        repeat = self.__index(repeat)
+        repeat = _index(repeat)
         return self.__class__(elem for i in range(repeat) for elem in self)
 
     def __eq__(self, other):
@@ -555,12 +575,17 @@
 class AdaptToSequence(Sequence):
 
     def __new__(cls, adaptee):
-        self = Sequence.__new__(cls)
-        self.adaptee = adaptee
-        return self
+        if not hasattr(adaptee, "__getitem__"):
+            # Hack so that the self.__class__(<generator>) calls above work
+            adaptee = list(adaptee)
+        obj = Sequence.__new__(cls)
+        obj.adaptee = adaptee
+        return obj
 
     def __getitem__(self, index):
-        return self.adaptee[index]
+        if isinstance(index, slice):
+            return super(AdaptToSequence, self).__getitem__(index)
+        return self.adaptee[_index(index)]
 
     def __len__(self):
         return len(self.adaptee)

Modified: sandbox/trunk/abc/test_abc.py
==============================================================================
--- sandbox/trunk/abc/test_abc.py	(original)
+++ sandbox/trunk/abc/test_abc.py	Wed Apr  4 02:17:12 2007
@@ -46,7 +46,9 @@
         self.assertEqual(a[-1], 9)
         self.assertEqual(list(a), range(10))
         #self.assertEqual(a, range(10))
-        # Slicing isn't implemented correctly
+        b = a[1:-1]
+        self.assertEqual(b.__class__, abc.AdaptToSequence)
+        self.assertEqual(list(b), range(1, 9))
 
     def test_adapt_to_mapping(self):
         a = abc.AdaptToMapping({1: 10, 2: 20})


More information about the Python-checkins mailing list