带有存根的子类的 Python 2.7 类型提示

Posted

技术标签:

【中文标题】带有存根的子类的 Python 2.7 类型提示【英文标题】:Python 2.7 type hinting for subclasses with stubs 【发布时间】:2018-10-19 16:43:52 【问题描述】:

您可以根据https://www.python.org/dev/peps/pep-0484/#stub-files在 Python 2.7 中对存根文件使用类型提示

但是我不能让它适用于子类中的方法签名。

在存根文件 a.pyi 中:

class A(object):
    def foo(self, timestamp: float): ...

在 Python 2.7 文件 b.py 中

class B(A):
    def foo(self, timestamp):
        print(timestamp)  # Inferred type of timestamp is not float!

PyCharm 2017.3.3 不会将时间戳推断为浮点数。我没有检查 mypy 的行为。

有两种解决方法会导致代码冗余(不是首选)

解决方法 1

在存根文件 b.pyi 中

class B(A):
    def foo(self, timestamp: float): ...

解决方法 2

在 Python 2.7 文件 b.py 中

class B(A):
def foo(self, timestamp):  # type: (float) -> None
    print(timestamp)

【问题讨论】:

【参考方案1】:

如果您不向函数添加类型注释,则表明您不希望符合 PEP-484 的类型检查器检查该函数。

这意味着您需要执行方法 2:显式添加类型提示,以便 Pycharm(和 mypy)知道您希望对该函数进行类型检查。

请注意,您的解决方法 1 并没有真正起作用:如果您添加 *.pyi 文件,您就是在告诉类型检查器完全忽略相应的 *.py 文件。这可能不是您希望在这里发生的事情。

更广泛地说,Pycharm(或 mypy)推断timestamp 始终是float 类型实际上是不正确的:子类型实际上加宽 参数类型是合法的。例如,B 的时间戳方法可能接受浮点数或 strs:

class B(A):
    def timestamp(self, timestamp):
        # type: (Union[float, str]) -> None
        print(timestamp)

或者它可以扩大到接受任何类型:

class B(A):
    def timestamp(self, timestamp):
        # type: (object) -> None
        print(timestamp)

这两个定义都是 A 的有效子类型:它们都匹配 A.timestamp 的签名而不违反 Liskov substitution principle。

因此,由于我们不能轻易地自动推断出子类型的签名应该是什么,因此 Pycharm(和 mypy)不要尝试。

【讨论】:

这是有道理的。我希望通过覆盖一种方法,我建议应用相同的类型。没有考虑扩大。 @Michael0x2a 您对使用 pyi 存根的解决方法 1 的注释似乎与 PyCharm 不正确。类型检查器确实在 py 文件中合并了子 本地类型提示。

以上是关于带有存根的子类的 Python 2.7 类型提示的主要内容,如果未能解决你的问题,请参考以下文章

Python:如何覆盖子类中实例属性的类型提示?

带有列表的 Python 字典,如何在节俭的存根代码中描述它?

Python 类型提示 - 为 dict 子类指定键、值类型

Python 覆盖子类中方法返回的类型提示,无需重新定义方法签名

Python 类型提示:如何判断 X 是 Foo 的子类?

带有熊猫的 Python 类型提示?