[Python-Dev] non-integer slice indices?

Viorel Preoteasa viorel.preoteasa@abo.fi
Thu, 17 Feb 2000 23:33:39 +0200


Dear All,

Thank you very much for your answers.

I will try to give answers to all problems that arise from
my question on non-integer slices. First I will comment on any
idea that arises from it, and then I will give my example.

1.

peter> Hmmmm.... I was very astonished to read this, since it broke a frozen

peter> model in my ---wannabe a python guru--- brain.
peter>   >>> class HyperSeq:
peter>   ...     def __setslice__(self, i, j, sequence):
peter>   ...         print "Just kidding. index i =", i, "j =", j, "seq =",
sequence
peter>   >>> t = HyperSeq()
peter>   >>> t['a':'abc'] = "does this work?"
peter>   Traceback (innermost last):
peter>     File "<stdin>", line 1, in ?
peter>   TypeError: slice index must be int
peter>   >>>
peter> Now I think, that the model in my brain was not so wrong and that at
peter> least in Python 1.5.2 slicing can't work with non-integer indices.
skip> Indeed.  (Obviously I didn't read the manual or perform the concrete
skip> experiment that Peter did.)

Before posting my message to python-hep, I have read the manual, I have
tried
a version of the above example, and I have read the python-FAQ. I have asked
the
question because I have guessed that may be there is a way to get
__setslice__
called even when the indexes are not integers. Any way it is also useful
to find out that there is not.

I guess that this "frozen model" guides some answers that I got.
Why this when somebody can give a consistent semantic for his
program, and when there is a function that should deal with this?
(Skip's idea)

2.

greg> Currently, a person can do the following:
greg>    foo[slice('a','abc')] = some_sequence

Yes he/she can, but it is easier and nicer to have something like
    foo.slice('a', 'abc', some_sequence)
and much nicer
    foo['a':'abc'] = some_sequence
when there is an appropriate semantic for it.

3.

skip> Well, I'll be damned!  To wit:
skip>    class SliceableDict(UserDict.UserDict):
skip>         ...

Yes. I also don't have now a good example of data structure like
dictionaries that can support such operation. But I have an example
of data structure like lists. I guess it has a good semantic for
the range between the non-integer indexes.
See the example from the end.

4.

Christian> When we write
Christian> x[low:high] = some_sequence
Christian>
Christian> then we imply that there is a sequence on the left hand that
Christian> can be indexed by the implicit ordered set of integers in
Christian> the range [low, high), and we allow this assignment to change
Christian> the sequence's length arbitrarily.

Almost yes. But why by "implicit ordered set of ...". Why this order cannot
depend also on the data that is stored in x. See my example.

Christian> Well, I don't like any of these so much. They make dicts look
Christian> like something ordered, that rings a bell about too much
Christian> cheating.

Yes, may be your example is not appropriate for such operation. But
<<if the __setslice__ programmer is willing to do the type checking and
provide the semantics of "from X to Y" for arbitrary X and Y>> then
why the interpreter could not let <<non-integer indices pass>>. As Skip
suggested.


My example:

My example is very simple. I want to have an object that has as data
structure lines of, for example, characters. So the basic data type
is a list of strings, or list of list of characters. The indexes are
pairs of line, column (how Tk Text Widget works). The order between
indexes is given by the lexicographic order, i.e. (x,y)<=(u,v)
iff x<u or (x=u and y<=v). The range between (x,y) and (u,v) is not
given by all pairs between (x,y) and (u,v). Instead, it depends on the
actual size of the data represented. For example:

class t:
    def __init__(self):
       data = ['abcdefgh', '12345', 'xyz']
    def __setslice__(...):
        ...
    def __getslice__(...):
        ...

__getslice__ could be implemented such that if x is an instance of t,
(x = t()), then after the assignment

y = x['0.4', '2.1']

y can be ['efgh', '12345', 'x'] or a new instance of t with
y.data = ['efgh', '12345', 'x']. It depends on the programer wish.

__setslice__ could be implemented such that the assignment

x['0.4', '2.1'] = y

changes x.data to ['abcdAA', 'BBBBBB', 'CCCCCCC', 'DDDCyz'], where
y is ['AA', 'BBBBBB', 'CCCCCCC', 'DDD'], or is an instance of t with
y.data = ['AA', 'BBBBBB', 'CCCCCCC', 'DDD'].

Sounds consistent?

More over:

1. Python allows slices like x[1:100], where x is [1,2,3,4]. This
does not implies (as Christian suggested)  that x is a sequence
that "can be indexed by the implicit ordered set of integers in the
range [1, 100)". In fact the number of elements of x[1:100] depends
not only on the range(1,100) but also on the actual length of x.
So why not allow a more general feature of this.

2. In the case of dictionaries. Some times could be useful to get
from a dictionary the elements that have the keys between two elements,
supposing that are comparable with the dictionary keys.
For example if

x = {'john': 4523864, 'andrew': 3745365, 'roland': 4529413, 'anna': 2342231}

then
    print x['a':'b']
would print the only entries that have keys starting with 'a', i.e.
    {'andrew': 3745365, 'anna': 2342231}
in general x[a:b] will be
    {key: val | (key in x.keys()) and (a <= key < b)}.
In this case it is possible as
    x['a':'b'] = y
to have no meaning. But when some body wants to
implement something like this, he/she can chose to not define
__setslice__. If this function is not defined when "x['a':'b'] = y"
occur in a program then it will generate an error like
"__setslice__ dot defined". Any way when somebody is writing
x[i:j], where x is an instance of an object, it gets an error
if the class of x does not implement __???slice__. So when
somebody implements __???slice__ for an object then he/she
has a semantic for x[i:j], even if i, j are not integers.

3. I would be happy if I would be
able to write programs that contains things like:

class collection:
    ...
x = collection()
y = x[property]

were y would become the collection of all elements form x
that satisfy the property, i.e. using a mathematical notation
y would be the collection

  {(index, element) in x | property(index, element)}

In this example {e in X | p(e)} means the collection of all
elements e that belongs to X such that p(e) is true.

With this notation slices are particular cases. For example
x[i:j] would be x[SLICE(i,j)] where

def SLICE(i,j):
    def _SLICE(k,x, i=i, j=j):
        return i <= k < j
    return _SLICE

SLICE is not the slice object.

If we want to get all odd numbers of a list we will write
x[ODD] where

def ODD(i,a):
    return a[i] % 2 == 1

Viorel