Python - 在装饰器

时间:2016-08-03 10:58:44

标签: python annotations python-decorators

假设我有一个带有类型注释的函数:

def f(n: float) -> int:
    if random.random() >= n:
        raise Exception
    return 1

我想装饰这个函数,装饰版本将扩展原始函数的返回值:

def decorator(f):
    def decorated(max_tries: int, delay: int, *a, **kwa):  # annotations?
        for i in range(1, max_tries+1):
            try:
                return True, f(*a, **kwa)
            except Exception:
                log('try %d of %d failed' % (i, max_tries))
                time.sleep(delay)

        return False, None

    return decorated

在此示例中,我想将原始返回类型int更改为(bool, Union[int, None])

我试过了:

def decorator(f):
    @functools.wraps(f)
    def decorated(max_tries: int, delay: int, *a, **kwa):
        for i in range(1, max_tries+1):
            try:
                return True, f(*a, **kwa)
            except Exception:
                log('failed try %d of %d' % (i, max_tries))
                time.sleep(delay)

        return False, None

    ret = f.__annotations__['return']
    decorated.__annotations__['return'] = (bool, Union([ret, None]))

    return decorated

我得到TypeError: Cannot instantiate <class 'typing.UnionMeta'>

有谁知道怎么做?


修改

>>> type(ret)
<class 'typing.UnionMeta'>
>>> isinstance(ret, Union)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Program Files\Python35-32\lib\typing.py", line 563, in __instancecheck__
    raise TypeError("Unions cannot be used with isinstance().")
TypeError: Unions cannot be used with isinstance().

输入模块中的类究竟是什么(例如ListUnion等)?它们在定义函数时是否被实例化?他们为什么不能用手实例化呢?


编辑2:

显然,“实例化”Union的方法是使用与类型注释中相同的表示法:Union[int, None]

def decorator(f):
    @functools.wraps(f)
    def decorated(max_tries: int, delay: int, *a, **kwa):
        for i in range(1, max_tries+1):
            try:
                return True, f(*a, **kwa)
            except Exception:
                log('failed try %d of %d' % (i, max_tries))
                time.sleep(delay)

        return False, None

    ret = f.__annotations__['return']
    decorated.__annotations__['return'] = (bool, Union[ret, None])

    return decorated

现在的问题是将参数max_tries: intdelay: int添加到已修饰函数的注释中,并将这些参数添加到help(decorated_f)中。 对此有何帮助?

0 个答案:

没有答案