python - __getattr__ 在模块上

标签 python module python-3.x getattr attributeerror

如何在类、模块上实现 __getattr__ 的等价物?

示例

当调用一个模块的静态定义属性中不存在的函数时,我希望在该模块中创建一个类的实例,并在其上调用与在模块上的属性查找中失败的名称相同的方法.

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")

这给出了:

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

最佳答案

您在这里遇到了两个基本问题:

  1. __xxx__ 方法只在类中查找
  2. TypeError: can't set attributes of built-in/extension type 'module'

(1) 意味着任何解决方案都必须跟踪正在检查的模块,否则 每个 模块将具有实例替换行为;和 (2) 意味着 (1) 甚至不可能......至少不是直接的。

幸运的是,sys.modules 对那里的内容并不挑剔,因此包装器将起作用,但仅用于模块访问(即 import somemodule; somemodule.salutation('world'); 相同 -模块访问您几乎必须从替换类中提取方法并将它们添加到 globals() 或者使用类上的自定义方法(我喜欢使用 .export()) 或使用通用函数(例如那些已经作为答案列出的函数)。要记住的一件事:如果包装器每次都创建一个新实例,而全局解决方案不是,那么您最终会得到微妙的不同行为。哦,你不能同时使用这两种方法——只能用一种。


更新

来自 Guido van Rossum :

There is actually a hack that is occasionally used and recommended: a module can define a class with the desired functionality, and then at the end, replace itself in sys.modules with an instance of that class (or with the class, if you insist, but that's generally less useful). E.g.:

# module foo.py

import sys

class Foo:
    def funct1(self, <args>): <code>
    def funct2(self, <args>): <code>

sys.modules[__name__] = Foo()

This works because the import machinery is actively enabling this hack, and as its final step pulls the actual module out of sys.modules, after loading it. (This is no accident. The hack was proposed long ago and we decided we liked enough to support it in the import machinery.)

因此,实现您想要的既定方法是在您的模块中创建一个类,并作为模块的最后一个 Action ,将 sys.modules[__name__] 替换为您的类的实例-- 现在您可以根据需要使用 __getattr__/__setattr__/__getattribute__


注意 1:如果您使用此功能,那么模块中的任何其他内容,例如全局变量、其他函数等,都会在 sys.modules 时丢失分配已完成——因此请确保所需的一切都在替换类中。

注意2:要支持from module import *,你必须在类中定义__all__;例如:

class Foo:
    def funct1(self, <args>): <code>
    def funct2(self, <args>): <code>
    __all__ = list(set(vars().keys()) - {'__module__', '__qualname__'})

根据您的 Python 版本,__all__ 中可能会省略其他名称。如果不需要兼容 Python 2,则可以省略 set()

关于python - __getattr__ 在模块上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2447353/

相关文章:

python - Django OneToOne 字段

python - 在 Amazon Comprehend Medical 中识别单词的不同时态

javascript - 错误: Cannot find module 'dbconstant'

python - Django 模板 : Passing a variable from an include, 进入点符号路径

python - 用标题命名 Pandas 数据框

python - 需要正则表达式来查找字符串中的\n或\r

module - 如何在 Julia 中本地扩展 Base 运算符(在模块中)

c++ - 在C++中是否可以有虚拟类型?

Python请求不会通过get方法中的参数添加查询字符串

python - 如何在Python中创建链表