3.5:类型提示和方法重载

2022-04-18 00:00:00 python python-3.5

问题描述

编辑:我目前误解了这个功能。It's not designed for multiple dispatch:

注意:虽然可以使用此语法提供多分派实现,但其实现需要使用sys._getFrame(),这是不受欢迎的。此外,设计和实现高效的多重分派机制也很困难,这就是为什么之前的尝试被放弃,转而使用函数工具。SingleDispatch()。(见PEP 443,特别是其"替代办法"一节。)在未来,我们可能会提出令人满意的多分派设计,但我们不希望这样的设计受到为存根文件中的类型提示定义的重载语法的限制。也有可能这两个功能将独立开发(因为类型检查器中的重载与运行时的多分派具有不同的用例和要求--例如,后者不太可能支持泛型类型)。

=

我在Java-land已经离开了一段时间,现在我将返回到Python3.5。我想使用新的类型提示功能,但我在方法重载方面遇到了问题。从我对该功能的阅读来看,这应该是支持的。

这是我正在编写的一个快速小类:

licensing.pyi(请注意PYI)

import typing
import gitlab


class LicensingChecker(object):
    @typing.overload
    def __init__(self, url: str, api_key: str) -> None: ...
    @typing.overload
    def __init__(self, gl: gitlab.Gitlab) -> None: ...

    def iter_projects(self) -> typing.Iterator[str]: ...

licensing.py

import gitlab
import string


class LicenseChecker(object):
    def __init__(self, gl):
        self.gl = gl

    def __init__(self, url, api_key):
        self.gl = gitlab.Gitlab(url, api_key)

    def iter_projects(self):
        p = set()
        for i in string.ascii_lowercase:
            for x in self.gl.projects.search(i):
                if x not in p:
                    p.add(x)
                    yield x.name

这是一个玩具示例,但其想法相当传统。我提供了两个构造函数,一个接受已有的GitLab客户端,另一个将实例化它。(此脚本不需要双重构造函数,但我看到了@typing.overload,想看看它是如何工作的。)

PyCharm和Cpython似乎对这段代码很满意,但第一个构造函数无法访问--就像@typing.overload修饰符不起作用:

>>> import gitlab
>>> import licensing
>>> licensing.LicenseChecker(gitlab.Gitlab('https://blah.blah.blah/gitlab', 'hunter2'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() missing 1 required positional argument: 'api_key'

我需要做些什么才能使超载正常工作?目前,我只是调用内置的REPL或IPython。


解决方案

不支持重载。您的第二个__init__正在覆盖第一个,因此出现错误。您需要编写一个带有运行时类型检查的__init__

def __init__(self, arg1, arg2=None):
    if isinstance(arg1, gitlab.Gitlab) and arg2 is None:
        self.gl = arg1
    elif arg1 is not None and arg2 is not None:
        self.gl = gitlab.Gitlab(arg1, arg2)
    else:
        raise TypeError('........')

(有functools.singledispatch可以模拟只有一个参数更改类型的重载,但不适合您的情况)


@typing.overload修饰符只是告诉类型检查器可以有多种参数组合,这并不意味着您现在可以用相同的名称在两个不同的函数中编写实现。发件人:PEP 484:

如上所示的@overload修饰符的用法适用于存根文件。在常规模块中,一系列@overload修饰定义后面必须紧跟一个非@overload修饰定义(对于相同的函数/方法)。@overload修饰的定义仅用于类型检查器,因为它们将被非@overload修饰的定义覆盖,而后者在运行时使用,但应由类型检查器忽略。

相关文章