Декоратор для проверки любых функций аннотации - PullRequest
0 голосов
/ 30 ноября 2018

Я хочу разработать декоратор для проверки любого типа аннотации функции, и если он имеет подобный тип, тогда запустите функцию.может питон сделать такую ​​вещь ??если Python может, пожалуйста, помогите мне!

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Если я правильно понимаю идею, возможно, этот код поможет вам:

from types import FunctionType

def check(f: FunctionType):
    def wrapper(*args, **kwargs):
        result = True

        # check args
        keys = tuple(f.__annotations__.keys())
        for ar in enumerate(args):
            if not isinstance(ar[1], f.__annotations__.get(keys[ar[0]])):
                result = False
                break

        if result:
            # check kwargs
            for k, v in kwargs.items():
                if not isinstance(v, f.__annotations__.get(k)):
                    result = False
                    break

        if result:
            f(*args, **kwargs)

    return wrapper

Пример использования:

@check
def foo(a: str, b: int = None):
    print(f"a  = {a}")
    print(f"b  = {b}")


# Example 1: a=324, b=32:
foo(234, b=32)
# result: function not executed

# Example 2: a="abc", b="zzz":
foo("abc", b="zzz")
# result: function not executed

# Example 3: a="qwe", b= not set:
foo("qwe")
# result: function executed, output:
# a  = qwe
# b  = None

# Example 4: a="abc", b=99:
foo("abc", 99)
# result: function executed, output:
# a  = abc
# b  = 99

Декоратор проверяет типы аргументов, и если все впорядок, он выполняет функцию, в противном случае он ничего не делает.

0 голосов
/ 30 ноября 2018

как то так.

import inspect
import functools


def check(func):
    msg = "Expected type {etype} for {para} got {got}"
    para = inspect.signature(func).parameters
    keys = tuple(para.keys())

    @functools.wraps(func)
    def wrapper(*args,**kwargs):
        def do_check(anno,value,para):
            if not isinstance(value, anno):
                raise TypeError(msg.format(etype=anno,
                    para=para,
                    got=type(value)))

        for i,value in  enumerate(args):
            anno = para[keys[i]].annotation
            do_check(anno, value, keys[i])

        for arg_name,value in  kwargs.items():
            anno = para[arg_name].annotation
            do_check(anno, value, arg_name)

        ret = func(*args,**kwargs)
        if "return" in func.__annotations__:
            anno = func.__annotations__["return"]
            do_check(anno, ret, "return")
        return ret
    return wrapper

@check
def test(a:int,b:str) -> str:
    return 'aaa'

@check
def test2(a:int,b:str) -> str:
    return 123
...