[英]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.