Background
I would like to understand how functions are different from typical classes that implement __call__
. They’re clearly not the same in terms of the result produced, but I am ignorant about what goes on behind the scenes.
At some level of analysis I don’t really ‘need’ to know, the stuff I write doesn’t depend on the distinction, but after coding in Python for 10 years I think I ‘want’ to know.
My rough expectation is that they’re both PyCodeObject
at the C level, but beyond that I don’t know where in the code to look. I have not written a lot of C code, so I am hoping someone can explain (in C concepts is fine as I don’t mind learning) what is going on without me resorting to trying to stumble into a setup where I can run GDB to follow a rabbit trail of calls… At least, that’s what I imagine I would see without knowing what I am looking for.
I recently bought CPython Internals, so references to that book would also be useful. I also literally just found the online CPython’s internals, although I am unsure if/where my question would be addressed.
Example
I am considering the difference between
def foo():
pass
and
class Bar:
def __call__(self):
pass
foo = Bar()
We can make some superficial comparisons:
>>> Bar(), foo
(<__main__.Bar object at 0x72341a7a3d40>, <function foo at 0x72341a7adf80>)
>>> dis(Bar())
>>> dis(foo)
1 0 RESUME 0
2 2 RETURN_CONST 0 (None)
>>> set(dir(Bar())) - set(dir(foo))
{'__weakref__'}
>>> set(dir(foo)) - set(dir(Bar()))
{'__annotations__', '__get__', '__closure__', '__builtins__', '__name__', '__type_params__', '__qualname__', '__kwdefaults__', '__code__', '__globals__', '__defaults__'}
Question
What is going on behind the scenes when I define a function vs defining a class with __call__
?