[Python-ideas] __getattr__ bouncer for modules
Nathaniel Smith
njs at pobox.com
Sat Apr 16 23:40:14 EDT 2016
On Sat, Apr 16, 2016 at 7:50 PM, Chris Angelico <rosuav at gmail.com> wrote:
> Every now and then there's been talk of making it easier to subclass
> modules, and the most common use case that I can remember hearing
> about is descriptor protocol requiring code on the type. (For
> instance, you can't change a module-level constant into a property
> without moving away from the default ModuleType.)
>
> How bad would it be for the default ModuleType to have a __getattr__
> function which defers to the instance? Something like this:
>
> def __getattr__(self, name):
> if '__getattr__' in self.__dict__:
> return self.__dict__['__getattr__'](name)
> raise AttributeError
>
> The biggest downside I'm seeing is that module attributes double as
> global names, which might mean this would get checked for every global
> name that ends up being resolved from the builtins (which is going to
> be a LOT). But I'm not sure if that's even true.
It's not true :-). Code executing inside the module has 'globals() is
mod.__dict__', so lookups go directly to mod.__dict__ and skip
mod.__getattr__.
However, starting in 3.5 cpython allows __class__ assignment on
modules, so you can implement custom __getattr__ on a module with:
class ModuleWithMyGetattr(types.ModuleType):
def __getattr__(self, name):
# .. whatever you want ...
sys.modules[__name__].__class__ = ModuleWithMyGetattr
The advantage of doing it this way is that you can also implement
other things like __dir__ (so tab completion on your new attributes
will work).
This package backports the functionality to earlier versions of CPython:
https://pypi.python.org/pypi/metamodule
https://github.com/njsmith/metamodule/
Basically just replace the explicit __class__ assignment with
import metamodule
metamodule.install(__name__, ModuleWithMyGetattr)
(See the links above for more details and a worked example.)
-n
--
Nathaniel J. Smith -- https://vorpus.org
More information about the Python-ideas
mailing list