4

The documentation lists many magic methods. But I don't think it is enough. It does not tell me what methods are called when I do for x in c.

To do this, I tried a simple code snippet to print each attribute reference:

class Print(object):
    def __getattribute__(self, item):
        print(item)
        return super().__getattribute__(item)

a = Print()

Sometimes it works:

import pickle
pickle.dumps(a)
# print the following and then raise an error
__reduce_ex__
__reduce__
__getstate__
__class__

Then I know pickle.dump calls these magic methods.

But sometimes it does not work:

for x in a:
    continue
# direct error, no print

Are there any way to tell what magic methods are called in a python statement?

Update:

It seems Cpython bypasses getattribute calls for some special methods for speedup. Check special-method-lookup section for details.

Therefore, the answer seems to be no. We cannot catch each attribute reference.

Just take this example:

class C:
    pass

c = C()
c.__len__ = lambda: 5
len(c)
# TypeError: object of type 'C' has no len()
youkaichao
  • 1,938
  • 1
  • 14
  • 26
  • 3
    Check out [How come an object that implements `__iter__` is not recognized as iterable?](https://stackoverflow.com/q/43935187/674039) – wim Aug 21 '20 at 02:44
  • 2
    ^ and once you understand that, check out the hack in [Detect if a `__getattribute__` call was due to hasattr](https://stackoverflow.com/a/52940910/674039). Also note that pypy is often more well-behaved in these areas, CPython makes all kinds of nasty shortcuts. – wim Aug 21 '20 at 02:54
  • 1
    This previous covers a technique to instrument all functions (/including Special methods/) on a particular object: https://stackoverflow.com/questions/16372229/how-to-catch-any-method-called-on-an-object-in-python – sblom Aug 21 '20 at 03:00

0 Answers0