[Python-Dev] Slicing

Michael Hudson mwh@python.net
19 Jun 2002 11:09:24 +0100


"David Abrahams" <david.abrahams@rcn.com> writes:

> I did a little experiment to see if I could use a uniform interface for
> slicing (from C++):
> 
> >>> range(10)[slice(3,5)]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: sequence index must be integer
> >>> class Y(object):
> ...     def __getslice__(self, a, b):
> ...             print "getslice",a,b
> ...
> >>> y = Y()
> >>> y[slice(3,5)]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: unsubscriptable object
> >>> y[3:5]
> getslice 3 5
> 
> This seems to indicate that I can't, in general, pass a slice object to
> PyObject_GetItem in order to do slicing.** Correct?

No.  The time machine has got you here; update to CVS and try again.

This comes down to the (slightly odd, IMHO) distinction between
sequences and mappings, which doesn't really appear at the Python
level.

type_pointer->tp_as_sequence->sq_item

takes a single int as a parameter

type_pointer->tp_as_mapping->mp_subscr

takes a PyObject*.  Builtin sequences (as of last week) have mp_subscr
methods that handle slices.  I haven't checked, but would be amazed if
PyObject_GetItem can't now be used with sliceobjects.

(PS: I'm not sure I've got all the field names right here.  They're
close).

> So I went looking around for alternatives to PyObject_GetItem. I found
> PySequence_GetSlice, but that takes int parameters, and AFAIK there's no
> rule saying you can't slice on strings, for example.
> 
> Further experiments revealed:
> 
> >>> y['hi':'there']
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: unsubscriptable object
> >>> class X(object):
> ...     def __getitem__(self, x):
> ...             print 'getitem',x
> ...
> >>> X()['hi':'there']
> getitem slice('hi', 'there', None)
> 
> So I /can/ slice on strings, but only through __getitem__(). And...
> 
> >>> class Z(Y):
> ...     def __getitem__(self, x):
> ...             print 'getitem',x
> ...
> >>> Z()[3:5]
> getslice 3 5
> >>> Z()['3':5]
> getitem slice('3', 5, None)
> 
> So Python is doing some dispatching internally based on the types of the

This area is very messy.

> slice elements, but:
> 
> >>> class subint(int): pass
> ...
> >>> subint()
> 0
> >>> Z[subint():5]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: unsubscriptable object

This last one is easy: you're trying to subscript the class object!

> So it's looking at the concrete type of the slice elements. I'm not
> sure I actually understand how this one fails.
> 
> I want to make a generalized getslice function in C which can operate on a
> triple of arbitrary objects. Here's the python version I came up with:
> 
>     def getslice(x,start,finish):
>         if (type(start) is type(finish) is int
>             and hasattr(type(x), '__getslice__')):
>             return x.__getslice__(start, finish)
>         else:
>             return x.__getitem__(slice(start,finish))
> 
> Have I got the logic right here?

You can't do this logic from Python, AFAIK.  I think PyObject_GetItem
is your best bet.

Cheers,
M.

-- 
  The only problem with Microsoft is they just have no taste.
              -- Steve Jobs, (From _Triumph of the Nerds_ PBS special)
                         and quoted by Aahz Maruch on comp.lang.python