在Python中拦截并修改函数参数的方法调用,可以通过以下几种技术实现,每种方式各有优缺点和适用场景:
基础概念: 装饰器是在函数调用前/后注入逻辑的语法糖,可直接修改传入的参数。
示例代码:
def modify_args(func):
def wrapper(*args, **kwargs):
# 修改位置参数(例如第一个参数)
new_args = ("modified_" + str(args[0]),) + args[1:]
# 修改关键字参数(例如key为'param'的值)
if 'param' in kwargs:
kwargs['param'] = "modified_" + kwargs['param']
return func(*new_args, **kwargs)
return wrapper
@modify_args
def example_func(a, b, param=None):
print(a, b, param)
example_func("hello", 123, param="world")
# 输出:modified_hello 123 modified_world
优势:
局限:
基础概念: 运行时动态替换函数对象,在调用原函数前拦截参数。
示例代码:
def original_func(param):
print("Original:", param)
def patched_func(*args, **kwargs):
# 修改参数
modified_args = ("intercepted_" + args[0],)
return original_func(*modified_args, **kwargs)
# 替换原函数
original_func = patched_func
original_func("test") # 输出:Original: intercepted_test
优势:
局限:
适用场景: 拦截类中所有方法的参数。
示例代码:
class ArgInterceptor(type):
def __new__(cls, name, bases, attrs):
for attr_name, attr_value in attrs.items():
if callable(attr_value):
attrs[attr_name] = cls.wrap_method(attr_value)
return super().__new__(cls, name, bases, attrs)
@staticmethod
def wrap_method(method):
def wrapped(*args, **kwargs):
# 修改第一个参数(跳过self)
new_args = (args[0], "intercepted_" + str(args[1])) + args[2:]
return method(*new_args, **kwargs)
return wrapped
class MyClass(metaclass=ArgInterceptor):
def my_method(self, param):
print("Param:", param)
obj = MyClass()
obj.my_method("data") # 输出:Param: intercepted_data
优势:
局限:
inspect
和 sys
模块动态拦截任意函数调用:
通过替换 sys.modules
或 inspect
跟踪调用栈(适用于调试)。
示例代码:
import sys
import inspect
def modify_incoming_calls():
frame = inspect.currentframe()
# 获取调用栈并修改参数(需进一步处理帧对象)
# 此处仅为示意,实际需操作帧的f_locals/f_globals
pass
# 需结合具体场景实现
局限:
wrapt
)推荐场景: 需要更稳定的AOP(面向切面编程)支持时。
示例代码:
import wrapt
@wrapt.decorator
def intercept_args(wrapped, instance, args, kwargs):
new_args = ("wrapped_" + args[0],) + args[1:]
return wrapped(*new_args, **kwargs)
@intercept_args
def target_function(param):
print("Received:", param)
target_function("value") # 输出:Received: wrapped_value
优势:
方案:使用Monkey Patching或 wrapt
库,但需注意兼容性风险。
方案:在装饰器中使用 *args
和 **kwargs
分别处理。
建议:装饰器或Monkey Patching会引入额外调用栈,高频场景建议预编译修改后的参数。
根据需求选择合适的方法,优先推荐装饰器或 wrapt
库实现。
没有搜到相关的文章