代码之家  ›  专栏  ›  技术社区  ›  Wolfgang Kuehn

Python 2.7带存根的子类的类型暗示

  •  0
  • Wolfgang Kuehn  · 技术社区  · 7 年前

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

    然而,我无法使它适用于子类中的方法签名。

    在存根文件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 回复  |  直到 7 年前
        1
  •  1
  •   Michael0x2a    7 年前

    如果不向函数添加类型注释,则表示不希望PEP-484兼容类型检查器检查该函数。

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

    请注意,您的变通方法1实际上不起作用:如果您添加*。pyi文件,您告诉typechecker完全忽略对应的*。py文件。这可能不是你想在这里发生的事情。

    更广泛地说,Pycharm(或mypy)推断 timestamp 始终为类型 float :子类型实际 拓宽 参数类型。例如,可能的情况是 B 的时间戳方法接受浮点或STR:

    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)不要尝试。