如何注册打字.可通过Python@singledispatch调用



背景

假设我要实现一个简单的装饰器@notifyme,它在调用装饰函数时打印一条消息。我希望装饰器接受一个参数来打印自定义消息;参数(以及参数周围的括号(可以省略,在这种情况下,打印默认消息:

@notifyme('Foo is invoked!')
def foo():
pass
@notifyme  # instead of @notifyme()
def bar():
pass

为了允许省略括号,我必须提供@notifyme:的两个实现

  1. 第一个实现允许用户自定义消息,因此它接受字符串作为参数并返回装饰符:

    def notifyme_customized(message: str) -> Callable[[Callable], Callable]:
    def decorator(func: Callable) -> Callable:
    def decorated_func(*args, **kwargs):
    print(str)
    return func(*args, **kwargs)
    return decorated_func
    return decorator
    
  2. 第二个实现是装饰器本身,并使用第一个实现打印默认消息:

    def notifyme_default(func: Callable) -> Callable:
    return notifyme_customized('The function is invoked.')(func)
    

为了使上面的两个实现使用相同的名称notifyme,我使用functools.singledispatch将对notifyme的调用动态调度到两个实现之一:

# This is a complete minimal reproducible example
from functools import singledispatch
from typing import Callable
@singledispatch
def notifyme(arg):
return NotImplemented
@notifyme.register
def notifyme_customized(message: str) -> Callable[[Callable], Callable]:
def decorator(func: Callable) -> Callable:
def decorated_func(*args, **kwargs):
print(str)
return func(*args, **kwargs)
return decorated_func
return decorator
@notifyme.register
def notifyme_default(func: Callable) -> Callable:
return notifyme_customized('The function is invoked.')(func)

问题

然而,由于代码由Python解释器进行解释,它抱怨typing.Callable是一个无效类型:

Traceback (most recent call last):
File "demo.py", line 20, in <module>
def notifyme_default(func: Callable) -> Callable:
File "C:Program FilesPython38libfunctools.py", line 860, in register
raise TypeError(
TypeError: Invalid annotation for 'func'. typing.Callable is not a class.

我在Python bug跟踪器上发现了这个问题,根据这个问题,它似乎是自Python 3.7以来的预期行为。我目前使用的Python 3.8(或最近发布的Python 3.9(中是否存在解决方案或变通方法?

提前谢谢。

https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable

from collections import abc
@notifyme.register
def notifyme_default(func: abc.Callable) -> Callable:
return notifyme_customized('The function is invoked.')(func)

我无法将typing.Callablefunctools.singledispatch一起使用,但我确实通过使用function类引用找到了解决方法:

from functools import singledispatch
from typing import Callable
function = type(lambda: ())
@singledispatch
def notifyme(arg):
return NotImplemented
@notifyme.register
def notifyme_customized(message: str) -> Callable[[Callable], Callable]:
def decorator(func: Callable) -> Callable:
def decorated_func(*args, **kwargs):
print(str)
return func(*args, **kwargs)
return decorated_func
return decorator
@notifyme.register
def notifyme_default(func: function) -> Callable:
return notifyme_customized('The function is invoked.')(func)

相关内容

  • 没有找到相关文章

最新更新