0

I have recently come across MethodType which allows to do arguably hacky but fun stuff like:

from types import MethodType
class MyClass():
    def __init__(self, n : int):
        self.list_of_items = list(range(n))
    def __getitem__(self, idx):
        return self.list_of_items[idx]
    def foo(self):
        return "foo"

def bar(self):
    return "bar"
a = MyClass(10)
a.foo = MethodType(bar, a)
a.foo()
## prints bar
a[0]
# 0 (int) is printed

But what if I wanted to dynamically decorate the __getitem__ of a in a similar spirit ? The first idea that comes to mind is to do:

def new_getitem(self, idx):
    return str(self.__getitem__(idx))
a.__getitem__ = MethodType(new_getitem, a)

However this has two problems first 1. __getitem__ isn't changed in the sense that [] syntax is not modified.

a[0]
# 0 (int) is printed

Which might be explained by some funny business happening in the init of the instance to tie [] to __getitem__ What is worst is that explicitly calling __getitem__:

a.__getitem__(0)

runs into infinite recursion as we are redefining __getitem__ infinitely.

I was wondering if there was a syntax allowing to perform this hack so that:

a[0] = "0" (string)

I am open to any solution that allows to dynamically affect the instance's [] (using MethodType is not a requirement).

jeandut
  • 2,471
  • 4
  • 29
  • 56
  • and if you change it to: `def new_getitem(self, idx): return str(self[idx])` ? – RomanPerekhrest Sep 01 '23 at 13:01
  • @RomanPerekhrest nice idea ! 2. is solved no infinite recursion anymore now but [] syntax is unaffected because of 1. Aka a.__getitem__(0) works but not a[0]. – jeandut Sep 01 '23 at 13:04
  • In fact if we successfully solved 1. with your fix we would probably end up recursing infinitely as what we want is to actually change self[idx] in the end. I thought of using deepcopies but it felt unnatural and prone to even more complex problems. – jeandut Sep 01 '23 at 13:12
  • I would not do that at all. Overriding `a.__getitem__` on the fly is not reliable. Want to change the behavior of `__getitem__` - make it here `def __getitem__(self, idx) ...` or create another method for secondary representation of your data – RomanPerekhrest Sep 01 '23 at 13:17
  • Yeah I mean it's hacky for sure and not good practice I agree with you. The simplest way is to make __getitem__ behave differently according to an attribute of the self from the get go and just change this attribute dynamically but it's not always possible if you have no power over the class/instance and I was just wondering if it was possible. – jeandut Sep 01 '23 at 13:26
  • Aaaah: https://stackoverflow.com/questions/57413453/is-it-possible-to-override-getitem-at-instance-level-in-python – jeandut Sep 01 '23 at 22:24

0 Answers0