__getattr__ on a module

2019-01-01 06:48发布

How can implement the equivalent of a __getattr__ on a class, on a module?

Example

When calling a function that does not exist in a module's statically defined attributes, I wish to create an instance of a class in that module, and invoke the method on it with the same name as failed in the attribute lookup on the module.

class A(object):
    def salutation(self, accusative):
        print "hello", accusative

# note this function is intentionally on the module, and not the class above
def __getattr__(mod, name):
    return getattr(A(), name)

if __name__ == "__main__":
    # i hope here to have my __getattr__ function above invoked, since
    # salutation does not exist in the current namespace
    salutation("world")

Which gives:

matt@stanley:~/Desktop$ python getattrmod.py 
Traceback (most recent call last):
  File "getattrmod.py", line 9, in <module>
    salutation("world")
NameError: name 'salutation' is not defined

9条回答
深知你不懂我心
2楼-- · 2019-01-01 07:35

Here's my own humble contribution -- a slight embellishment of @Håvard S's highly rated answer, but a bit more explicit (so it might be acceptable to @S.Lott, even though probably not good enough for the OP):

import sys

class A(object):
    def salutation(self, accusative):
        print "hello", accusative

class Wrapper(object):
    def __init__(self, wrapped):
        self.wrapped = wrapped

    def __getattr__(self, name):
        try:
            return getattr(self.wrapped, name)
        except AttributeError:
            return getattr(A(), name)

_globals = sys.modules[__name__] = Wrapper(sys.modules[__name__])

if __name__ == "__main__":
    _globals.salutation("world")
查看更多
听够珍惜
3楼-- · 2019-01-01 07:39

In some circumstances the globals() dictionary can suffice, for example you can instantiate a class by name from the global scope:

from somemodule import * # imports SomeClass

someclass_instance = globals()['SomeClass']()
查看更多
后来的你喜欢了谁
4楼-- · 2019-01-01 07:42

Similar to what @Håvard S proposed, in a case where I needed to implement some magic on a module (like __getattr__), I would define a new class that inherits from types.ModuleType and put that in sys.modules (probably replacing the module where my custom ModuleType was defined).

See the main __init__.py file of Werkzeug for a fairly robust implementation of this.

查看更多
登录 后发表回答