Miklós said:
Michael Hudson said:
Miklós said:
"""
__getitem__(self, key)
Called to implement evaluation of self[key]. For sequence types, the
accepted keys should be integers and slice objects. Note that the special
interpretation of
"""
I think this is talking about implementing __getitem__, not calling it
directly. Historically these things have been quite different, though
they are becoming less so.
Well, I've never been really into the guts of Python ... but could you shed
some light for me on that why these two things are different?
Hmm, that's potentially a large topic. I'll have a go.
At the C implementation level, Python distinguishes sequences (lists,
strings, tuples, arrays, etc) and mappings (dicts, basically).
However, Python-the-language uses the same notation -- brackets, [] --
to access the elements of both sequences and mappings, and there's
only one corresponding special method -- __getitem__.
If you're implementing a sequence in C, you're expected to fill out
the tp_as_sequence structure of the type object, which contains these
fields:
typedef struct {
inquiry sq_length;
binaryfunc sq_concat;
intargfunc sq_repeat;
intargfunc sq_item;
intintargfunc sq_slice;
intobjargproc sq_ass_item;
intintobjargproc sq_ass_slice;
objobjproc sq_contains;
/* Added in release 2.0 */
binaryfunc sq_inplace_concat;
intargfunc sq_inplace_repeat;
} PySequenceMethods;
Notice that "sq_item" -- the function that retrieves an element of the
sequence -- is an "intargfunc", which is:
typedef PyObject *(*intargfunc)(PyObject *, int);
and "sq_slice" is an "intintargfunc", i.e:
typedef PyObject *(*intintargfunc)(PyObject *, int, int);
So, there's no way to actually implement a sequence that directly
handles a slice object! You have to make a mapping instead (the
corresponding function in PyMappingMethods is mp_subscript, a
binaryfunc:
typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
). This is the first reason you can't pass slice objects to
list.__getitem__ in 2.2 -- list just didn't implement mp_subscript.
The other reason is: just what is "list.__getitem__"? If list was
implemented in Python, it would be obvious, it would be an unbound
method. But list *isn't* implementing in Python, list is implemented
in C, so list.__getitem__ is a thing called a method-wrapper. When
you access it, magic happens to find the appropriate C level method
and wrap it up so you can call it from Python. But for __getitem__
specifically, there are two choices, sq_item and mp_subscript! 2.2
prefers sq_item, so even after the list type grew a mp_subscript
function [1].__getitem__(slice(0,1)) failed, because the
method-wrapper for sq_item didn't know what to do with the slice
object. 2.3 prefers mp_subscript over sq_item.
Hope that helped!
Cheers,
mwh