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

如何用Python的Monkeypatch实现类似Mock Side Effect的多返回值功能?

用Python Monkeypatch实现函数多次调用返回不同值

要实现Monkeypatch后让retrieve_files两次调用返回不同值,核心思路是给原函数替换一个能维护调用状态的自定义函数,以此模拟Mock中side_effect的效果,下面是两种简单直接的实现方式:

方法1:用迭代器生成固定返回序列

适合提前确定所有返回值的场景,逻辑简洁,和Mock的side_effect列表行为一致:

import pytest
from your_module import retrieve_files  # 替换成实际包含retrieve_files的模块路径

def test_retrieve_files_twice(monkeypatch):
    # 定义两次调用要返回的不同结果
    return_values = ["dir1_file_list", "dir2_file_list"]
    # 转成迭代器,每次调用取一个值
    value_iterator = iter(return_values)
    
    # 定义替换函数
    def mock_retrieve_files():
        return next(value_iterator)
    
    # 执行Monkeypatch替换原函数
    monkeypatch.setattr("your_module.retrieve_files", mock_retrieve_files)
    
    # 验证两次调用结果
    assert retrieve_files() == "dir1_file_list"
    assert retrieve_files() == "dir2_file_list"

如果调用次数超过迭代器长度,会抛出StopIteration异常,和Mock使用列表作为side_effect的行为完全一致。

方法2:用闭包维护调用计数

适合需要根据调用次数做复杂逻辑判断的场景,比如不同次数返回不同类型数据、模拟错误:

import pytest
from your_module import retrieve_files

def test_retrieve_files_with_counter(monkeypatch):
    call_count = 0
    
    def mock_retrieve_files():
        nonlocal call_count
        call_count += 1
        if call_count == 1:
            return ["file1.txt", "file2.jpg"]
        elif call_count == 2:
            return ["report.pdf", "data.csv"]
        # 超过调用次数可按需处理,比如抛出异常或返回默认值
        raise ValueError("Unexpected third call")
    
    monkeypatch.setattr("your_module.retrieve_files", mock_retrieve_files)
    
    assert retrieve_files() == ["file1.txt", "file2.jpg"]
    assert retrieve_files() == ["report.pdf", "data.csv"]

非pytest环境的通用逻辑

如果不是用pytest的monkeypatch fixture,而是自己手动实现Monkeypatch(比如直接替换模块属性),核心逻辑完全相同——只要把原函数替换成一个能跟踪调用状态的自定义函数即可,状态可以用闭包、类实例或者全局变量维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 20:40:43