[Python-Dev] Why does __getitem__ slot of builtin call sequence methods first?
Travis Oliphant
oliphant at ee.byu.edu
Sun Oct 2 05:17:20 CEST 2005
Guido van Rossum wrote:
>On 10/1/05, Travis Oliphant <oliphant at ee.byu.edu> wrote:
>
>
>>The new ndarray object of scipy core (successor to Numeric Python) is a
>>C extension type that has a getitem defined in both the as_mapping and
>>the as_sequence structure.
>>
>>The as_sequence mapping is just so PySequence_GetItem will work correctly.
>>
>>As exposed to Python the ndarray object has a .__getitem__ wrapper method.
>>
>>Why does this wrapper call the sequence getitem instead of the mapping
>>getitem method?
>>
>>Is there anyway to get at a mapping-style __getitem__ method from Python?
>>
>>
>
>Hmm... I'm sure the answer is in typeobject.c, but that is one of the
>more obfuscated parts of Python's guts. I wrote it four years ago and
>since then I've apparently lost enough brain cells (or migrated them
>from language implementation to to language design service :) that I
>don't understand it inside out any more like I did while I was in the
>midst of it.
>
>However, I wonder if the logic isn't such that if you define both
>sq_item and mp_subscript, __getitem__ calls sq_item; I wonder if by
>removing sq_item it might call mp_subscript? Worth a try, anyway.
>
>
>
Thanks for the tip. I think I figured out the problem, and it was my
misunderstanding of how types inherit in C that was the source of my
problem.
Basically, Python is doing what you would expect, the mp_item is used
for __getitem__ if both mp_item and sq_item are present. However, the
addition of these descriptors (and therefore the resolution of any
comptetion for __getitem__ calls) is done *before* the inheritance of
any slots takes place.
The new ndarray object inherits from a "big" array object that doesn't
define the sequence and buffer protocols (which have the size limiting
int dependencing in their interfaces). The ndarray object has standard
tp_as_sequence and tp_as_buffer slots filled.
Figuring the array object would inherit its tp_as_mapping protocol from
"big" array (which it does just fine), I did not explicitly set that
slot in its Type object. Thus, when PyType_Ready was called on the
ndarray object, the tp_as_mapping was NULL and so __getitem__ mapped to
the sequence-defined version. Later the tp_as_mapping slots were
inherited but too late for __getitem__ to be what I expected.
The easy fix was to initialize the tp_as_mapping slot before calling
PyType_Ready. Hopefully, somebody else searching in the future for an
answer to their problem will find this discussion useful.
Thanks for your help,
-Travis
More information about the Python-Dev
mailing list