为什么此函数类型注释不正确(错误:泛型类型缺少类型参数)?

Lau*_*che 7 python python-3.x mypy

此函数类型注释是否正确?

import subprocess
from os import PathLike
from typing import Union, Sequence, Any


def run(shell_command: Union[bytes, str, Sequence[Union[bytes, str, PathLike]]], **subprocess_run_kwargs: Any) -> int:
    return subprocess.run(shell_command, check=True, shell=True, **subprocess_run_kwargs).returncode
Run Code Online (Sandbox Code Playgroud)

我猜不是,因为我得到:

he\other.py:6: error: Missing type parameters for generic type

要得到同样的错误,然后将上面的代码保存在 中other.py,然后:

$ pip install mypy

$ mypy --strict other.py
Run Code Online (Sandbox Code Playgroud)

Seo*_*ter 6

如 sanyash 的回答中所述,os.PathLike被定义为泛型类型。您可以查看typeshed repo中的存根。但是,os.PathLike仅在存根文件中是通用的,可导入的实现os不是.

不指定类型 var 参数 ( path: PathLike) 会导致 mypy 错误。指定类型 var 参数 ( path: PathLike[Any]) 会导致 Python 解释器(运行时)错误。

这个确切的问题已在 mypy 存储库中作为#5667 提出。因此PR #5833扩展了 mypy 文档:

添加的部分指出了三种处理方法:

  1. 可以通过特殊from __future__ import annotations导入禁用 Python 解释器(在运行时)对注释的解释,请参见此处。这计划成为 Python 3.10 中的默认设置,并解决一堆与注释相关的问题。

    from __future__ import annotations
    from os import PathLike
    import subprocess
    from typing import Any, Sequence, Union
    
    def run(shell_command: Union[bytes, str, Sequence[Union[bytes, str, PathLike[Any]]]], **subprocess_run_kwargs: Any) -> int:
         return subprocess.run(shell_command, check=True, shell=True, **subprocess_run_kwargs).returncode
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用typing.TYPE_CHECKING依赖于类型检查或Python解释(运行时)是否解释该文件以提供不同的注释。

    from os import PathLike
    import subprocess
    from typing import Any, Sequence, TYPE_CHECKING, Union
    
    if TYPE_CHECKING:
        BasePathLike = PathLike[Any]
    else:
        BasePathLike = PathLike
    
    def run(shell_command: Union[bytes, str, Sequence[Union[bytes, str, BasePathLike]]], **subprocess_run_kwargs: Any) -> int:
        return subprocess.run(shell_command, check=True, shell=True, **subprocess_run_kwargs).returncode
    
    Run Code Online (Sandbox Code Playgroud)
  3. 以字符串形式提供注释。Python 解释器(运行时)不会解释注释,但 mypy 会获取正确的含义。

    import subprocess
    from typing import Any, Sequence, Union
    
    def run(shell_command: Union[bytes, str, Sequence[Union[bytes, str, 'PathLike[Any]']]], **subprocess_run_kwargs: Any) -> int:
        return subprocess.run(shell_command, check=True, shell=True, **subprocess_run_kwargs).returncode
    
    Run Code Online (Sandbox Code Playgroud)


san*_*ash 5

PathLike是泛型类型,因此您需要将其与类型参数一起使用(AnyStr例如):

import subprocess
from os import PathLike
from typing import Union, Sequence, Any, AnyStr


def run(shell_command: Union[bytes, str, Sequence[Union[bytes, str, PathLike[AnyStr]]]], **subprocess_run_kwargs: Any) -> int:
    return subprocess.run(shell_command, check=True, shell=True, **subprocess_run_kwargs).returncode
Run Code Online (Sandbox Code Playgroud)

相关问题:

更新

抱歉,我没有在运行时检查这段代码。通过一些技巧,可以编写一个解决方法:

import subprocess
from os import PathLike as BasePathLike
from typing import Union, Sequence, Any, AnyStr, TYPE_CHECKING
import abc


if TYPE_CHECKING:
    PathLike = BasePathLike
else:
    class FakeGenericMeta(abc.ABCMeta):
        def __getitem__(self, item):
            return self

    class PathLike(BasePathLike, metaclass=FakeGenericMeta):
        pass

def run(shell_command: Union[bytes, str, Sequence[Union[bytes, str, PathLike[AnyStr]]]], **subprocess_run_kwargs: Any) -> int:
    return subprocess.run(shell_command, check=True, shell=True, **subprocess_run_kwargs).returncode
Run Code Online (Sandbox Code Playgroud)

与此解决方法相关的问题: