用于装饰任何功能注释类型的装饰器

时间:2018-11-30 07:16:25

标签: python decorator

我想设计一个装饰器来检查任何函数注释类型,如果它具有相似的类型,则运行函数。 python可以做这个事情吗? 如果Python可以,请帮助我!

def foo (a:int):
    if foo.__annotations__.get('a') == type(a):
        pass

def boo (b:str):
    if boo.__annotations__.get('b') == type(b):
        pass

另一件事是注释是字典类型,我想要这样:

from type import FunctionType
def check (f:FunctionType):
    result = True
    k = [k for k in f.__annotations__.keys()]
    v = [v for v in f.__annotations__.values()]
    for i in range(len(v)):
        if v[i] != type(k[i]): #but we don't access to the type of k[i] out of th f function
            result = False
    return result       

2 个答案:

答案 0 :(得分:1)

类似这样的东西。

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

答案 1 :(得分:1)

如果我正确理解了这个主意,也许这段代码可以为您提供帮助:

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

装饰器检查参数类型,如果一切正常,它将执行该函数,否则不执行任何操作。