Dynamically Implementing Class-Like Behavior in Modules Using getattr
In some scenarios, it may be desirable to mimic the behavior of __getattr__ on a class but for an entire module. This allows for dynamic creation of class instances and invocation of their methods based on attribute lookups on the module.
However, attempting to define a __getattr__ method directly on a module faces two obstacles:
Wrapper-Based Solution
One approach is to create a wrapper around the module. Sys.modules is tolerant of different object types, so we can wrap the module inside a class and assign it to sys.modules[__name__]. This allows for dynamic behavior without modifying the module itself. This technique, however, applies only to module-level access.
Guido van Rossum's Hack
Another solution suggested by Guido van Rossum involves replacing the actual module in sys.modules with an instance of a class defined within the module. The import machinery does this final substitution step, enabling this hack. The following example demonstrates this approach:
# module foo.py
import sys
class Foo:
def funct1(self, *args):
def funct2(self, *args):
sys.modules[__name__] = Foo()
Now, the functions defined in the module can be accessed via the instance of Foo.
Considerations
When using these techniques, other module elements may be inaccessible after the sys.modules assignment. Define all necessary functionality within the replacement class to avoid losing module content.
__all__ Attribute
When using from module import *, define __all__ in the replacement class to handle this type of import statement. Omit attributes like __module__ and __qualname__ from __all__.
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3