2

I would like this to work:

import types

def new_getattr(self, *args, **kwargs):
    return 2

class A:
    def __init__(self):
        pass

a = A()
a.__getattr__ = types.MethodType(new_getattr, a)
print(a.anything)

Right now, it throws AttributeError: A instance has no attribute 'anything'.

I tried different solutions proposed here and they work, but not for __getattr__.

If I do print(a.__getattr__('anything')), it actually prints 2; the problem is that my __getattr__ method is not called automatically when I do a.anything.


As a side note, in my actual implementation, I cannot modify the definition of the class A, nor can I type its name and do something like A.__getattr__ = ... (which would work) because I need this to be generic and independent of the class name.

Edit: I ended up doing it like this:

a.__class__.__getattr__ = new_getattr.

math.husky
  • 193
  • 1
  • 8

1 Answers1

2

You can not - __dunder__ names are resolved on the type, not per-instance. Custom __getattr__ will need to be defined directly on A.

See Special method lookup section of the datamodel documentation, specifically:

For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.

Note: if you only have a reference to an instance, not the class, it is still possible to monkeypatch the type by assigning a method onto the object returned by type(a). Be warned that this will affect all existing instances, not just the a instance.

wim
  • 338,267
  • 99
  • 616
  • 750