具有类型的单一调度方法
Posted
技术标签:
【中文标题】具有类型的单一调度方法【英文标题】:singledispatchmethod with typing types 【发布时间】:2020-10-23 07:32:35 【问题描述】:在 Python 3.8 中,创建了一个用于创建多态函数的新装饰器 @singledispatchmethod,它根据提供的类型提示将 Python 重定向到您的方法的正确实现。
但是,我似乎无法使用打字模块中的复杂类型,请您告诉我我的示例有什么问题吗?
from typing import List
from functools import singledispatchmethod
class test:
@singledispatchmethod
def a(self, a):
return NotImplemented
@a.register
def _(self, a : str):
print(type(a))
# Uncomment to run the example
# @a.register
# def _(self, a: List[str]):
# print(type(a))
def b(self, b: List[str]):
print(type(b))
test().a(["A"])
test().b(["A"])
如果第二个下划线函数的注释被取消注释,a函数会出现以下错误,即使b函数没有发生这种错误:
TypeError: Invalid annotation for 'a'. typing.List[str] is not a class.
我做错了什么?
【问题讨论】:
看起来像singledispatch
定义中的另一个错误。 register
方法显式检查参数的注解是否是 type
的实例,而类型提示则不是这样。
@chepner 你知道这是否在任何地方的错误跟踪器中,还是 OP 刚刚发现了一个新的 stdlib 错误?
也许是这个? bugs.python.org/issue34498
我认为这个问题涵盖了这一点。函数注释一直被允许是任意表达式,即使它们实际上总是类型。 PEP-484 开启了要求注解为类类型的道路,但typing
模块是引入非类型类对象的第一件事。 singledispatch
似乎跟不上这些发展。
感谢您的参考,至少我知道在这种情况下我没有做错任何事情
【参考方案1】:
从 cmets 看来,可能有 potential changes 到 singledispatchmethod
,但如果您对可用的变通方法感兴趣,以允许调度和打字工作,这里有一些选项:
-
使用实际类
list
注册重载,然后为重载提供更具体的类型提示 (see related answer)。
使用像 multimethod
这样的项目来处理更多参数化的 typing
类型。
选项 1:注册 list
并添加更具体的重载类型提示
from functools import singledispatchmethod
from typing import List, overload
class test:
@singledispatchmethod
def overloaded_a(self, a):
return NotImplemented
@overloaded_a.register
def _(self, a: str):
print(type(a))
@overloaded_a.register
def _from_list(self, a: list):
print(type(a))
@overload
def a(self, a: str): ...
@overload
def a(self, a: List[str]): ...
def a(self, *args, **kwargs):
return self.overloaded_a(*args, **kwargs)
def b(self, b: List[str]):
print(type(b))
test().a(["A"])
test().b(["A"])
test().a("this")
# test().a([34]) # mypy error: List item 0 has incompatible type "int"; expected "str"
# test().b("this") # mypy error: Argument 1 to "b" of "test" has incompatible type "str"; expected "List[str]"
选项2:使用multimethod
from typing import List
from multimethod import multimethod as singledispatchmethod
class test:
@singledispatchmethod
def a(self, a):
return NotImplemented
@a.register
def _(self, a: str):
print("str")
print(type(a))
@a.register
def _from_str_list(self, a: List[str]):
print("str list")
print(type(a))
@a.register
def _from_int_list(self, a: List[int]):
print("int list")
print(type(a))
def b(self, b: List[str]):
print(type(b))
test().a(["A"])
test().a([3])
test().b(["A"])
# test().b(3) # mypy error: Argument 1 to "b" of "test" has incompatible type "int"; expected "List[str]"
【讨论】:
以上是关于具有类型的单一调度方法的主要内容,如果未能解决你的问题,请参考以下文章
安卓。具有单一活动方法的 BottomNavigationView