“Why are these method-wrappers created?”
You are looking up attributes of objects, so the attribute lookup
machinery gets invoked.
You have a function object,
thing. When you look up
that’s a runtime attribute lookup, which returns the method-wrapper
That method object itself is an object, so when you look up the
__call__ attribute on that, you again get a method-wrapper.
The details are related to the descriptor protocol, which you will
find explained on the Python website. The attribute lookup machinery
doesn’t make an exception for
__call__, or function objects. Any
attribute lookup goes through the same machinary.
Remember that in Python, everything is an object, including functions,
As for what purpose the method-wrapper serves, without it calling
thing.__call__ would fail unless you wrote the call as:
and provided the “self” parameter by hand. Remember that the
method of function objects are defined on the FunctionType class, which
means that the
__call__ method needs to know which instance is being
“Why are the hex numbers the same for the original function and the
first wrapper but the ids change?”
The hex number 0x000001C6EED3F040 in your example refers back to the
memory location of the original function object each time.
The object IDs are arbitrary ID numbers. The details of whether they
change or not will depend on many factors, such as the specific version
of the interpreter, whether ID numbers can get re-used or not, how
quickly they get re-used, etc. The only rules for IDs are:
In this specific case the numbers change because you are holding onto
the method objects, preventing their IDs from being recyled. Otherwise
you likely would have seen a pattern something like:
1234567890 function thing
where the IDs cycle. Another common pattern (Jython and IronPython)
would be something like:
123 function thing
that is, consecutive ID numbers with no re-use.
“Shouldn’t the wrapper implement __eq__ which considers id of the
originally defined function?”
For what purpose?
__eq__ method, inherited from the base object, compares
object identity. Without some special reason to care about comparing
methods for identity, why would we change that?