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

Python monkey patching不生效,如何正确实现get_datetime函数的猴子补丁?

补丁失效的核心原因

1. 模块全局代码执行时机早于补丁执行

Python模块在首次被导入时,会一次性执行文件内所有全局作用域的代码。你在generation.py里的NAME是全局变量,定义时直接调用了get_datetime(),也就是说只要bobs.generation模块被导入过,get_datetime()就已经执行完成了,你后续打补丁根本不会影响已经计算完成的NAME值。
即使你补丁打对了,也只能影响补丁执行之后新的get_datetime()调用,修改不了之前已经算好的全局变量。

2. 补丁内容类型错误

你当前的补丁是直接把get_datetime这个函数引用替换成了一个固定的datetime对象:

monkey_patch.setattr(
    "bobs.generation.get_datetime",
    datetime.datetime(2021, 11, 18),
)

而原逻辑是调用get_datetime()(函数调用)获取时间,你替换成固定对象后如果调用get_datetime()会直接抛出「datetime对象不可调用」的错误,你现在没报错还能拿到now()的结果,说明你的补丁执行的时候,bobs.generation模块早就已经导入完成,甚至get_datetime的引用都已经被用完了,补丁根本没机会生效。

3. 导入后修改源模块引用不生效

from utils.dtutils import get_datetime这个导入操作,会把dtutils里的get_datetime函数引用复制一份到generation模块的命名空间里。如果你的补丁是在generation导入完成后才修改bobs.utils.dtutils.get_datetime,只会影响之后新的导入,不会修改已经存在于generation模块里的独立引用。


修复方案

方案1:调整补丁执行时机,提前到模块导入前

保证你的猴子补丁代码执行在任何导入bobs.generation的代码之前,同时补丁要替换成返回固定时间的函数,而不是直接放时间对象:

# 先打补丁,再导入模块
import datetime
from monkey_patch import setattr

def mock_get_datetime():
    return datetime.datetime(2021, 11, 18)

setattr("bobs.utils.dtutils.get_datetime", mock_get_datetime)

# 补丁打完再导入generation模块,此时全局NAME计算用的就是mock的函数
from bobs.generation import NAME

方案2:调整业务代码逻辑,避免全局作用域提前执行调用

如果没法控制导入顺序,就把全局NAME的计算改成懒加载的形式:

# generation.py 修改后
from utils.dtutils import get_datetime

_NAME = None

def get_name():
    global _NAME
    if _NAME is None:
        _NAME = f"""{KMTER}/{get_datetime().strftime('%Y-%m-%d')}/dadsdge.fs"""
    return _NAME

这样调用get_name()的时候才会执行get_datetime(),只要补丁打在第一次调用get_name()之前就可以生效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 19:24:07