clarete / forbiddenfruit

Patch built-in python objects
https://clarete.li/forbiddenfruit/
GNU General Public License v3.0
826 stars 52 forks source link

overriding __getitem__ seems to have no effect #33

Open xcsp3team opened 5 years ago

xcsp3team commented 5 years ago

Hi,

Thank you for your useful module.

In my case, I would like to override __getitem__, but that does not seems to be working. I have installed forbiddenfruit 0.1.3 and I run python 3.5.2.

For the following piece of code (test.py):

from forbiddenfruit import *

def my_getitem(self, key):
    print("my_getitem : self ", self)
    print("my_getitem : key ", key)
    return self.__getitem__(key)

curse(list, "__getitem__", my_getitem)

def my_contains(self, other):
    print("my_contains : self ", self)
    print("my_contains : other ", other)
    return self.__contains__(other)

curse(list, "__contains__", my_contains)

l = [1, 2, 3, 4]

print("l:", l)
print(l[0])
print(2 in l)
print(l.__getitem__(2))

I obtain (python3 test.py):

l: [1, 2, 3, 4]
1
my_contains : self  [1, 2, 3, 4]
my_contains : other  2
True
3

So, while __contains__ is well intercepted, this is not the case for __getitem__. I wonder if this is something that is missing in forbiddenfruit or if this is something related to the language. Best, christophe

Jongy commented 3 years ago

This is related to the language - in many areas of the CPython codebase, "shortcuts" are being made if strict type checks match.

For example, this is the implementation of BINARY_SUBSCR - the opcode implementing x[y] - for CPython v2.7.18. You can clearly see that it has special treatment for lists - objects that match PyList_CheckExact(o), which is equivalent to type(o) is list. COMPARE_OP (in) which implements x in y does not have shortcuts for lists, therefore "it works" for you.

In recent CPython versions I don't see the code in ceval.c implementing the shortcut for subscripting, so it might have been moved somewhere else down the call chain, or removed completely. Generally, while forbiddenfruit allows for it, depending on overriding of basic operators of builtin types is not consistent across CPython versions. AFAIK, these things can change.