问题是您不知道要检查哪个参数,因为它在您要装饰的每个函数中的不同位置。但是,您可以通过使用inspect 模块来检查每个函数的签名,检查以确保它具有具有指定名称的参数,如果有,将形式参数名称映射到传递给的实际参数值每次调用该函数。
有了这些信息,就可以确定与目标参数关联的参数的值,并根据需要对其进行处理——在您的代码和下面的示例中,使用 @ 的值调用 check_abs() 函数987654324@ 参数传递并检查函数的返回值。
(注:修改为支持多个命名参数。)
from functools import wraps
import inspect
def check_abs(_abs_dir):
print('check_abs({!r}) called'.format(_abs_dir))
return True
def check_abs_param(*params):
def decorator(function):
sig = inspect.signature(function)
if any(map(lambda param: param not in sig.parameters, params)):
raise NameError('One or more expected parameter names missing from '
'declaration "{}{}:".'.format(function.__name__, sig))
@wraps(function)
def wrapped(*args, **kwargs):
bound = sig.bind(*args, **kwargs) # Map parameter names to argument values.
for param in params:
arg_value = bound.arguments[param] # Get argument value.
if not check_abs(arg_value):
return False if sig.return_annotation == bool else None
return function(*args, **kwargs)
return wrapped
return decorator
# tests
try:
@check_abs_param('_abs_dir')
def check_is_bogus(somearg): # param name does not match decorator
print('check_is_bogus() called\n')
except NameError as exc:
print(exc)
print('NameError exception raised from "check_is_bogus(somearg):" declaration, as '
'expected.\n')
else:
print('Error: Expected exception NOT raised from "check_is_bogus(somearg):" '
'declaration.\n')
@check_abs_param('_abs_dir')
def check_is_file(_abs_dir:str):
print('check_is_file() called\n')
@check_abs_param('_abs_dir')
def create_file_or_folder(_name:str, _abs_dir:str, _is_file:bool):
print('create_file_or_folder() called\n')
@check_abs_param('source_dir_abs', 'dest_dir_abs')
def copy_file_or_folder(source_dir_abs:str, dest_dir_abs:str) -> bool:
print('copy_file_or_folder() called\n')
#check_is_bogus('first_dir') # can't call, definition failed
check_is_file('second_dir')
create_file_or_folder('name', 'third_dir', 'False')
copy_file_or_folder('source_dir', 'dest_dir')
输出:
One or more expected parameter names missing from declaration "check_is_bogus(somearg):".
NameError exception raised from "check_is_bogus(somearg):" declaration, as expected.
check_abs('second_dir') called
check_is_file() called
check_abs('third_dir') called
create_file_or_folder() called
check_abs('source_dir') called
check_abs('dest_dir') called
copy_file_or_folder() called