具有类型类型的 singledispatch 方法

lag*_*lix 9 python python-3.x python-decorators

在 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"])
Run Code Online (Sandbox Code Playgroud)

如果第二个下划线函数的注释被取消注释,则 a 函数会出现以下错误,即使 b 函数不会出现以下错误:

TypeError: Invalid annotation for 'a'. typing.List[str] is not a class.
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

use*_*389 2

从评论来看,听起来可能会有潜在的变化singledispatchmethod,但如果您对允许调度和打字工作的可用解决方法感兴趣,这里有一些选项:

  1. 使用实际类注册重载list,然后为重载提供更具体的类型提示(请参阅相关答案)。
  2. 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]"
Run Code Online (Sandbox Code Playgroud)

选项 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]"
Run Code Online (Sandbox Code Playgroud)