繁体   English   中英

在 Python3 中,可以在模块上设置属性时触发函数吗?

[英]In Python3, can you trigger a function when an attribute is set on a module?

我正在尝试调试已删除模块属性的问题(例如,它存在于代码中,但在运行时访问它,有时会产生AttributeError 。)

这是哪个代码,它是哪个模块/属性,实际上并不重要。

重要的是我是否能够编辑模块或对其进行修补,以便在修改属性时触发我控制的功能。 该函数可能是一个断点,也可能只是打印堆栈跟踪、引发异常等,以帮助我查看真正的错误在哪里(毕竟它显然不在试图访问该属性的地方。)

到目前为止我发现了什么:

我发现可以在模块上定义__getattr__

我已经测试了定义__setattr__是否有效:

import module
def mod_set_attr(self, name, value):
    raise AttributeError(f"{name} is not a mutable attribute")
module.__setattr__ = mod_set_attr
module.foo = "bar"

(尝试设置属性时不会抛出AttributeError )。

我还尝试直接在模块上添加属性:

@property
def foo(module):
    return "foo"

@foo.setter
def foo_setter(module, value):
    raise AttributeError("you can't mutate attribute foo")

(仍然没有抛出AttributeError )。

老实说,没想到自己这么快就回答了这个问题,但我找到了办法! 您需要通过将模块包装在一个类中来修补模块,如下所示。

class ModuleWrapper(object):
    def __init__(self, module_to_wrap):
        self._mod = module_to_wrap

    def __getattr__(self, name):
        if name == "_mod":
            return super().__getattr__(name)
        return getattr(self._mod, name)

    def __setattr__(self, name, value):
        if name == "_mod":
            return super().__setattr__(name, value)
        if name == "foo":
            raise AttributeError("foo is not mutable")
        return setattr(self._mod, name, value)

    def __delattr__(self, name):
        if name == "foo":
            raise AttributeError("foo is not mutable")
        return delattr(self._mod, name)

import sys, module

sys.modules["module"] = ModuleWrapper(module)

(对不起if name == "_mod"垃圾邮件,但需要避免构造函数中的无限递归。)

本质上,我们正在从任何地方中断对该模块的 setattr 或 delattr 的任何调用并引发AttributeError 为了确保其他地方可以导入我们封装的模块版本,我们将其添加到sys.modules[module_name]中,这是真正的猴子补丁。

这意味着我们将能够找到删除属性的罪魁祸首并修复它。 🎉

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM