I\'m wondering about the more intricate differences between functions and callable objects. For example, if you do:
def foo1():
return 2 + 4
class foo2:
Functions are also callable objects:
>>> foo1.__call__
>>> callable(foo1)
True
But a class needs to keep track of more information; it doesn't matter here that you gave it a __call__ method. Any class is bigger than a function:
>>> import sys
>>> def foo1():
... return 2 + 4
...
>>> class foo3:
... pass
...
>>> sys.getsizeof(foo1)
136
>>> sys.getsizeof(foo3)
1056
A function object is a distinct object type:
>>> type(foo1)
and is reasonably compact because the meat is not actually in the function object but in other objects referenced by the function object:
>>> sys.getsizeof(foo1.__code__)
144
>>> sys.getsizeof(foo1.__dict__)
240
And that's it really; different types of objects have different sizes because they track different things or use composition to store stuff in other objects.
You can use the type(foo1) return value (or types.FunctionType, which is the same object) to produce new function objects if you so desire:
>>> import types
>>> types.FunctionType(foo1.__code__, globals(), 'somename')
which is basically what the interpreter does whenever a def function(..): ... statement is being executed.
Use __call__ to make custom classes callable when that makes sense to your API. The enum.Enum() class is callable, for example, specifically because using the call syntax gives you a syntax distinct from subscription, which was used for other purposes. And a xmlrpc.client.ServerProxy() object produces method objects that are instances of _Method, because they proxy a remote call, not a local function.