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

Python中@patch装饰器无法使用关键字参数的替代方案咨询

解决unittest.mock @patch装饰器下关键字参数调用报错问题

在Python 3.11环境中使用unittest.mock的@patch装饰器时,若被装饰函数通过关键字参数调用会触发TypeError,提示“got multiple values for argument 'arg'”,但位置参数调用正常。

原代码示例

import traceback
from unittest.mock import patch
import os.path

@patch('os.path.isfile')
def being_patched(arg, isfile_mock):
    print(f"Inside being_patched. arg={arg}  isfile_mock={isfile_mock}")

if __name__ == '__main__':
    being_patched(True)              # 正常运行
    print("\n----------\n")
    try:
        being_patched(arg=True)      # 报错
    except TypeError:
        traceback.print_exc()

错误输出

Inside being_patched. arg=True  isfile_mock=<MagicMock name='isfile' id='3181488491344'>

----------

Traceback (most recent call last):
  File "C:\Users\Mike Ulm\PycharmProjects\Exercises\USDataMap\patch_after_kwargs.py", line 13, in <module>
    being_patched(arg=True)
  File "C:\PythonFiles\Python311\Lib\unittest\mock.py", line 1375, in patched
    return func(*newargs, **newkeywargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: being_patched() got multiple values for argument 'arg'

问题原因

@patch装饰器默认会将mock对象作为位置参数注入到被装饰函数的参数列表最前面。当用being_patched(arg=True)调用时,装饰器传入的mock对象会被赋值给第一个参数arg,而你又通过关键字参数给arg传了值,导致同一个参数被重复赋值,触发错误。

解决方案

方案1:调整参数顺序,将mock参数放在最前面

把mock参数移到函数参数列表的首位,装饰器注入的mock会被正确赋值给对应参数,业务参数用关键字传递不会冲突:

import traceback
from unittest.mock import patch
import os.path

@patch('os.path.isfile')
def being_patched(isfile_mock, arg):
    print(f"Inside being_patched. arg={arg}  isfile_mock={isfile_mock}")

if __name__ == '__main__':
    being_patched(True)              # 仍可正常运行
    print("\n----------\n")
    being_patched(arg=True)          # 现在可以正常运行

方案2:使用关键字-only参数接收mock

通过*将mock参数设为关键字-only,同时给@patch指定kwarg参数,让装饰器以关键字参数形式注入mock:

import traceback
from unittest.mock import patch
import os.path

@patch('os.path.isfile', kwarg='isfile_mock')
def being_patched(arg, *, isfile_mock):
    print(f"Inside being_patched. arg={arg}  isfile_mock={isfile_mock}")

if __name__ == '__main__':
    being_patched(True)              # 正常运行
    print("\n----------\n")
    being_patched(arg=True)          # 正常运行

方案3:混合位置与关键字参数调用(不推荐)

若不想修改函数定义,可在调用时先传占位的位置参数,再传关键字参数,但可读性差,不建议使用:

# 原函数定义不变
being_patched(None, arg=True)  # None为占位,实际会被装饰器替换为真实mock对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 11:30:23