【问题标题】:How can I use decorator for functions those have variety parameters?如何将装饰器用于具有多种参数的函数?
【发布时间】:2017-02-26 03:08:58
【问题描述】:

只看前两行。

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() 的装饰器?这两个函数有不同的参数和位置。

【问题讨论】:

    标签: python python-3.x decorator


    【解决方案1】:

    问题是您不知道要检查哪个参数,因为它在您要装饰的每个函数中的不同位置。但是,您可以通过使用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
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 2014-07-21
    • 2020-03-22
    • 2014-04-18
    • 2021-11-21
    • 1970-01-01
    • 2017-06-21
    • 2012-11-05
    相关资源
    最近更新 更多