繁体   English   中英

如何将装饰器用于具有各种参数的函数?

[英]How can I use decorator for functions those have variety parameters?

只看这些的前两行。

if not check_abs(_abs_dir):
    return False

这些是函数(只看参数和前两行,函数的内容与这个问题无关)。

def check_is_file(_abs_dir:str):
    if not check_abs(_abs_dir):
        return False

    return os.path.isfile(
        norm_case_norm_path(_abs_dir)
    )

def create_file_or_folder(_name:str, _abs_dir:str, _is_file:bool):
    if not check_abs(_abs_dir):
        return False

    abs_dir = join(_abs_dir, _name)
    create = False

    if check_existence(abs_dir):
        if _is_file and not check_is_file(_abs_dir):
            create = True
        if not _is_file and not check_is_folder(_abs_dir):
            create = True
    else:
        create = True

    if create:
        if _is_file:
            open(abs_dir, "a").close()
        elif not _is_file:
            os.makedirs(abs_dir)
        return create

    return create

我该如何制作这些代码

if not check_abs(_abs_dir):
    return False

check_is_file()create_file_or_folder()装饰器? 两种功能都有不同的参数和位置。

问题是你不知道要检查哪个参数,因为它在你要装饰的每个函数中的不同位置。 但是,您可以通过使用inspect模块检查每个函数的签名来执行您想要的操作,检查以确保它具有指定名称的参数,如果是,则将形式参数名称映射到传递给函数的实际参数值每次被召唤。

拥有该信息可以确定与target参数关联的参数的值并根据需要对其进行处理 - 在您的代码和下面的示例中,使用传递的_abs_dir参数的值调用check_abs()函数并检查函数的返回值。

(注意:已修​​改为支持多个命名参数。)

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM