slicing, mapping types, ellipsis etc.

Bengt Richter bokr at oz.net
Mon Nov 29 18:44:54 EST 2004


On 29 Nov 2004 16:45:52 -0500, Jerry Sievers <jerry at jerrysievers.com> wrote:

>"Caleb Hattingh" <caleb1 at telkomsa.net> writes:
>
>> I'm going to assume the following is self-explanatory - type the commands  
>> in yourself.
>
>[snip]
>
>Yes, it certainly is self-explanatory.  And, I appreciate your
>response.
>
>However, my question pertains to advanced use of the slicing features
>which I have found to be not totally explained in the docs.
>
>The use of [start:stop:step] on sequence types is NOT unclear to me at
>all.
>
>I'd like to know;
>
>1. what the Ellipsis object or ... syntax is used for
>2. what a slice [..., j:k:l] does
>3. how slices are applied to object of mapping types
>
 >>> class C(object):
 ...     def __getitem__(self, i): print i; return None
 ...
 >>> c=C()
 >>> c[1]
 1
 >>> c[1:2]
 slice(1, 2, None)
 >>> c[1:2:3]
 slice(1, 2, 3)
 >>> c[:2:3]
 slice(None, 2, 3)
 >>> c[::3]
 slice(None, None, 3)
 >>> c[::]
 slice(None, None, None)
 >>> c[1,::]
 (1, slice(None, None, None))
 >>> c[1,...,::]
 (1, Ellipsis, slice(None, None, None))
 >>> c[1, 2, ..., 3:4]
 (1, 2, Ellipsis, slice(3, 4, None))
 >>> c[...]
 Ellipsis

An object implementing __getitem__ (and/or __setitem__) will be passed arguments
as above and is free to use them in any way that makes sense to it's author.
Making sense to the users of the author's software is another thing ;-)

AFAIK Ellipsis is just a special builtin object that can be used as a handy
standard place holder in the get/setitem context. But any other builtin
could be passed also, e.g., 

 >>> c[1,2,abs,3]
 (1, 2, <built-in function abs>, 3)

so AFAIK it's just that an Ellipsis reference is generated when you use ... in the
getitem context. The compiler generates a reference to the built-in constant, so
you can make a test for it for your object's logic, e.g.

 >>> class C(object):
 ...     def __getitem__(self, i):
 ...         if i is Ellipsis or isinstance(i, tuple) and Ellipsis in i:
 ...             print 'got ... in the index arg %r'%(i,)
 ...         else:
 ...             print 'did not get ... in the index arg %r'%(i,)
 ...
 >>> c=C()
 >>> c[1,2]
 did not get ... in the index arg (1, 2)
 >>> c[::]
 did not get ... in the index arg slice(None, None, None)
 >>> c[::, ...]
 got ... in the index arg (slice(None, None, None), Ellipsis)
 >>> c[...]
 got ... in the index arg Ellipsis
 >>> c[Ellipsis]
 got ... in the index arg Ellipsis

But interestingly, compare the appearance of Ellipsis in the disassembly
of foo and bar (LOAD_GLOBAL vs LOAD_CONST). The global you can shadow or
rebind, but the const is apparently known by the compiler, and it is arranged
that they both refer to the same object by default, so the 'is' test succeeds.

 >>> class C(object):
 ...     def __getitem__(self, i): return i
 ...     def foo(self): return self[...]
 ...     def bar(self): return self.foo() is Ellipsis
 ...
 >>> c= C()
 >>> c[...] is Ellipsis
 True
 >>> c.foo() is Ellipsis
 True
 >>> c.bar()
 True
 >>> import dis
 >>> dis.dis(C)
 Disassembly of __getitem__:
   2           0 LOAD_FAST                1 (i)
               3 RETURN_VALUE

 Disassembly of bar:
   4           0 LOAD_FAST                0 (self)
               3 LOAD_ATTR                1 (foo)
               6 CALL_FUNCTION            0
               9 LOAD_GLOBAL              2 (Ellipsis)
              12 COMPARE_OP               8 (is)
              15 RETURN_VALUE

 Disassembly of foo:
   3           0 LOAD_FAST                0 (self)
               3 LOAD_CONST               1 (Ellipsis)
               6 BINARY_SUBSCR
               7 RETURN_VALUE

HTH

Regards,
Bengt Richter



More information about the Python-list mailing list