You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用setattr装饰其他模块函数失效,如何修正代码?

问题原因分析

你遇到的核心问题是函数引用的拷贝与模块内函数的更新不同步:

  1. 当执行from foo import bar时,主模块的bar变量是对foo模块中原始bar函数的引用拷贝。
  2. mydecorator通过setattr修改了foo模块内的bar函数,但主模块的bar变量仍指向未装饰的原始函数。
  3. 同时,mydecorator内部循环始终检查传入的旧函数引用(主模块的bar),而非foo模块中已更新的装饰后函数,导致每次都判定为未缓存。

修正方案

方案一:让mydecorator每次读取模块内最新函数

修改deco.py,在循环中每次从原模块获取当前的函数实例,而非依赖传入的旧引用:

from functools import lru_cache
import sys

def mydecorator(somefunction):
    func_name = somefunction.__name__
    func_module = sys.modules[somefunction.__module__]
    
    for _ in range(2):
        # 每次从模块中读取最新的函数实例
        current_func = getattr(func_module, func_name)
        if hasattr(current_func, "cache_info"):
            print(f"{func_name} is already cached")
        else:
            print(f"caching {func_name}")
            decorated_func = lru_cache(current_func)
            setattr(func_module, func_name, decorated_func)

运行后输出将符合预期:

caching bar
bar is already cached

注意:此方案仅修正了mydecorator的判断逻辑,主模块的bar变量仍指向原始函数。若后续要在主文件中调用缓存后的bar,需要手动更新主模块的引用。

方案二:同时更新主模块的函数引用

如果希望主模块的bar也直接指向缓存后的函数,可让mydecorator返回装饰后的函数,在主文件中重新赋值:

1. 修改deco.py

from functools import lru_cache
import sys

def mydecorator(somefunction):
    func_name = somefunction.__name__
    func_module = sys.modules[somefunction.__module__]
    
    current_func = getattr(func_module, func_name)
    if hasattr(current_func, "cache_info"):
        print(f"{func_name} is already cached")
        return current_func
    else:
        print(f"caching {func_name}")
        decorated_func = lru_cache(current_func)
        setattr(func_module, func_name, decorated_func)
        return decorated_func

2. 修改主文件

from foo import bar
from deco import mydecorator

def main():
    global bar
    # 重新赋值bar,指向缓存后的函数
    bar = mydecorator(bar)
    # 验证两次状态
    for _ in range(2):
        if hasattr(bar, "cache_info"):
            print(f"{bar.__name__} is already cached")
        else:
            bar = mydecorator(bar)

if __name__ == "__main__":
    main()

此方案既修正了mydecorator的逻辑,也让主模块的bar直接使用缓存后的版本,完全符合预期行为。


内容的提问来源于stack exchange,提问作者Anthony Labarre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 15:07:02