Begginer here trying to understand how python works and i came up with this doubt.
Shouldn’t all functions be methods? Here’s the code i used to verify this
my_module.py:
def func():
pass
Main.py:
import inspect
import my_module
print(inspect.ismethod(my_module.func))
Output: False
>Solution :
Because methods are defined on the class. Any given module is an instance of the class module, not the definition of a new class.
Compare to:
class Foo:
pass
f = Foo()
f.stuff = lambda: print('stuff')
f.stuff
is an instance attribute of that particular instance of Foo
, not of Foo
s in general. The descriptor protocol (invoked when looking up an attribute on an instance, and finding it on the class, not the instance) is what converts functions on classes into methods of instances, and since these functions on a given module are all instance attributes of the module object, not the root class it’s an instance of, no descriptor protocol is invoked, and the function doesn’t become a method when called.
All that said, you can make subclasses of the module
type, which would allow a module to have real methods. This is documented under Customizing module attribute access as a fallback in case the special methods they explicitly added support for (e.g. __getattr__
, __dir__
) aren’t enough and you need your module to do other things. Since the __class__
of a module
is reassignable, you can reassign it to some other subclass of the module
class and the methods of that class will receive self
implicitly, so the same subclass can be assigned to multiple modules and provide per-module tailoring of behavior. For example:
import sys
from types import ModuleType
class MethodModule(ModuleType):
def dumb_method(self, x):
return f"This is module named {self.__name__} which received {x!r}"
thismodule = sys.modules[__name__]
thismodule.__class__ = MethodModule
print(thismodule.dumb_method("foo"))
gives the module it’s run within an instance method named dumb_method
which customizes its behavior based on the self
implicitly passed to it (in this case, using self.__name__
to determine the name of the module).