如何通过装饰器修改类方法代码,实现类仅允许在指定模块内实例化
错误原因
- 当你定义的类没有显式实现
__init__方法时,会继承Python内置object类的__init__,它是C语言实现的method-wrapper对象,本身没有__code__属性,所以访问直接报错 - 就算你自定义了
__init__,__code__是只读的CodeType对象,也不能直接通过加法拼接字节码,你的原始实现思路本身不成立
正确实现方案
我们可以通过包装原有__init__方法,在实例化初始化阶段校验调用者所在模块的方式实现需求,需要用到inspect模块获取调用栈信息:
import inspect def ModuleSpecificUse(klass=None, module=__name__): def decorator(cls): # 保存类原有的__init__方法 original_init = cls.__init__ def wrapped_init(self, *args, **kwargs): # 取调用栈的上一帧,就是实例化类的代码所在位置 caller_frame = inspect.stack()[1] # 获取调用者所在模块的名称 caller_module_name = caller_frame.frame.f_globals.get("__name__", "") if caller_module_name != module: raise ValueError("cannot use object") # 校验通过后执行原有初始化逻辑 original_init(self, *args, **kwargs) # 替换类的__init__为包装后的方法 cls.__init__ = wrapped_init return cls # 兼容装饰器带括号和不带括号两种写法 if klass is None: return decorator return decorator(klass)
使用示例
你可以按照你原来的方式使用装饰器:
# 假设这段代码定义在foo.py模块中 @ModuleSpecificUse(module="foo") class C: # 类的其他逻辑 pass
- 在
foo.py模块内实例化C(),运行正常 - 在其他任意模块导入
C后实例化,会抛出ValueError: cannot use object,完全符合你的预期需求
内容的提问来源于stack exchange,提问作者Alan Bagel
相关产品推荐
相关产品推荐

