Python:用于跨具有不同输入的函数进行keyvalue错误验证的修饰符

2024-04-25 08:59:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我想找一个装饰师来验证论点。问题是,为了D.R.Y的利益,我希望在各种函数上使用它,这些函数具有不同的必选参数和键值参数组合。下面做这样的事情,哪种方式最像Python?我甚至可以,或者我应该为每个输入组合做一个装饰器吗?你知道吗

def my_decorator(func):
    def func_wrapper(x, y, a, b, c, d):
        # Check that inputs are valid
        if a <= 0 or b <= 0 or c <= 0 or d <= 0:
            raise Exception("a, b, c, & d must be positive")
        if x < 0 or y < 0:
            raise Exception("x & y must be non-negative")
        return func(some_inputs)
    return func_wrapper

@my_decorator
def my_fun_1(x, a=None, b=None):
    return x ** (a + b)

@my_decorator
def my_fun_2(x, y, c=None):
    return x + y - c

...

@my_decorator
def my_fun_n(y, b=None, d=None):
    return y ** (b - d)

提前谢谢!你知道吗


Tags: or函数none参数returnifmydef
1条回答
网友
1楼 · 发布于 2024-04-25 08:59:32

我对代码留下了评论。如果清楚的话就告诉我。另外,我把它放在here下载

以下是我从装饰师那里学到的两个惊人的资源。 Amazing tutorial还有这个very easy to follow tutorial

import functools
import sys


def argument_range_validator(_func=None, **deco_kwargs):
    def argument_range_validator_decorator(func):

        if not __debug__:
            """
            Making sure this doesn't run when we're not debugging, e.g on production. comment this is you're not running the code in debug mode
            """
            return func
        else:
            @functools.wraps(func)
            def argument_range_validator_wrapper(*args, **kwargs):
                code = func.__code__ if sys.version_info[0] == 3 else func.func_code
                all_args = code.co_varnames[:code.co_argcount]
                local_variable = locals()

                """
                below is one solution to make a dictionary of items
                # value_dictionary = dict()
                # value_dictionary = local_variable['kwargs']
                # i = 0
                # for each in all_args:
                #     if each not in value_dictionary:
                #         value_dictionary[each] = local_variable['args'][i]
                #         i += 1

                and then pass value_dictionary to return func(**value_dictionary)
                """

                """
                Below is just the above commented code with a compressed code
                """
                positional_args = [each for each in list(all_args) if each not in list(local_variable['kwargs'].keys())]
                value_dictionary = local_variable['kwargs']
                positional_args_dictionary = dict(zip(positional_args, local_variable['args']))
                value_dictionary_args = {**value_dictionary, **positional_args_dictionary}

                """
                one way for validating arguments is to add conditions here. 
                I didn't add them here because I've also used factory, so I didn't need to check here.
                Here we can have some validations. For example you can single out functions and their arguments:

                if func.__name__ == 'test_func_1' and a<10:
                    throw some error!

                or maybe we just have generic rules and regardless of the function we want to check them:

                if pass is None:
                    throw some error!
                """
                for (argument, (condition_one, condition_two)) in deco_kwargs.items():

                    if argument in positional_args:
                        if positional_args_dictionary[argument] not in range(condition_one, condition_two):
                            """throw some exception, passing and just printing below for the sake of execution now"""
                            print(f"{positional_args_dictionary[argument]} was not in the acceptable range for {argument}!")

                    elif argument in local_variable['kwargs'].keys():
                        if value_dictionary[argument] not in range(condition_one, condition_two):
                            """throw some exception, passing and just printing below for the sake of execution now"""
                            print(f"{value_dictionary[argument]} was not in the acceptable range for {argument}!")

                return func(**value_dictionary_args)
            return argument_range_validator_wrapper

    if _func is None:
        return argument_range_validator_decorator
    else:
        return argument_range_validator_decorator(_func)

"""
1, 2, 3 will be passed as positional arguments to this function 
"""
@argument_range_validator(a=(2,10))
def test_func_1(a, b, c):
    x = a + b
    y = c
    print(f"{x} inside test_func_1")
    print(f"{y} inside test_func_1")


"""
(2, a=1, b=3) will be passed to this function and it's decorator will have no arguments
"""
@argument_range_validator
def test_func_2(a, b, c):
    x = a
    y = b
    z = c
    print(f"{x} inside test_func_2")
    print(f"{y} inside test_func_2")
    print(f"{z} inside test_func_2")

"""
Passing (2, c=3) to this one with no decorator arguments
"""
@argument_range_validator
def test_func_3(b, c, a=1):
    x = a
    y = b
    z = c
    print(f"{x} = a inside test_func_3")
    print(f"{y} = b inside test_func_3")
    print(f"{z} = c inside test_func_3")


"""
Neither the function nor the decorator will have any arguments for this test
"""
@argument_range_validator
def test_func_4():
    print(f"{test_func_4.__name__} says Hi!")


"""
Both the function and the decorator have arguments for this test
"""
@argument_range_validator(age=(18, 70), department=(40, 48))
def test_func_for_personnel(name, age, last_name, department):
    print(f"{name} {last_name} is {age} years old. She works at building No. {department}")


if __name__ == '__main__':

    test_func_1(1, 2, 3)
    test_func_2(2, a=1, b=3)
    test_func_3(2, c=3)
    test_func_4()
    test_func_for_personnel('Nasrin', 31, department=39, last_name='Shirali')

相关问题 更多 >