如何解决如何注册类型可以使用Python @singledispatch调用吗?
背景
假设我要实现一个简单的装饰器@notifyme
,当装饰函数被调用时,该装饰器将显示一条消息。我希望装饰器接受一个参数来打印定制的消息。可以省略参数(以及参数周围的括号),在这种情况下,将显示默认消息:
@notifyme('Foo is invoked!')
def foo():
pass
@notifyme # instead of @notifyme()
def bar():
pass
要允许省略括号,我必须提供@notifyme
的两种实现:
-
第一个实现允许用户自定义消息,因此它接受字符串作为参数并返回装饰器:
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
-
第二种实现本身是装饰器,并使用第一种实现打印默认消息:
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],**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 Files\python38\lib\functools.py",line 860,in register
raise TypeError(
TypeError: Invalid annotation for 'func'. typing.Callable is not a class.
我在Python错误跟踪器上发现了this issue,据此看来,自python 3.7以来,这似乎是预期的行为。我当前使用的Python 3.8(或最近发布的Python 3.9)是否存在解决方案或解决方法?
谢谢。
解决方法
https://docs.python.org/zh-cn/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.Callable
与functools.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)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。