关于mock.patch的side_effect传对象存参数的技术疑问
mock.patch's side_effect to Capture Function Arguments? Great question—let’s break this down clearly:
First, your initial understanding isn’t wrong, but there’s a key detail in the unittest.mock docs that’s easy to miss: while side_effect does support exceptions and iterables as special cases, it also accepts any callable object as its value. This is exactly what your instructor is referring to, and the approach is totally feasible.
Here’s why it works:
When you set side_effect to a callable (and in Python, an object becomes callable if it implements the __call__ method), every time the mocked function is invoked, it will redirect that call to your object’s __call__ method—passing along all the arguments that were sent to the original function. You can then capture and store those arguments directly in the object’s attributes.
Example Implementation
Let’s turn this into concrete code to see it in action:
import unittest.mock as mock # Define a class whose instances can capture function arguments class ArgumentRecorder: def __init__(self): # Initialize a list to store all call details self.recorded_calls = [] def __call__(self, *args, **kwargs): # Capture positional and keyword arguments from each call self.recorded_calls.append({ "positional_args": args, "keyword_args": kwargs }) # Optional: return a value to mimic the original function's output return "mocked_return_value" # Usage in a test scenario my_object = ArgumentRecorder() with mock.patch('your_module.function_to_be_mocked', side_effect=my_object): # Call the mocked function with different arguments your_module.function_to_be_mocked("hello", 42) your_module.function_to_be_mocked(name="Alice", age=30) # Check the captured arguments print(my_object.recorded_calls) # Output: # [ # {'positional_args': ('hello', 42), 'keyword_args': {}}, # {'positional_args': (), 'keyword_args': {'name': 'Alice', 'age': 30}} # ]
Key Notes:
- This approach is fully compliant with
unittest.mock’s design—side_effectexplicitly supports callables, which includes custom objects with__call__methods. - Compared to using the mock object’s built-in
call_args_listattribute, this custom object gives you more flexibility: you can add logic to validate arguments, transform them, or trigger other actions when the mocked function is called. - If you need to replicate the original function’s return behavior, you can adjust the
__call__method to return appropriate values (or even raise exceptions if needed).
So to answer your core question: yes, your instructor’s solution is absolutely viable—it leverages Python’s callable object feature and the full capabilities of mock.patch’s side_effect parameter that might have been overlooked in the initial doc scan.
内容的提问来源于stack exchange,提问作者Yan Chikama

