python - 2 和 3 组合代码库中 `__str__` 的类型是什么?

标签 python mypy

我正在尝试转换这个 py2 类:

class Example(object):
    def __unicode__(self):
        return unicode(42)   # unicode(self.id)

    def __str__(self):
        return unicode(self).encode('u8')

    __repr__ = __str__

到组合的 2/3 版本,类型为:

import sys
from typing import Text
from builtins import str as text

class Example(object):

    def _as_unicode(self):  # type: () -> Text
        return text(42)

    __unicode__ = _as_unicode

    def _as_bytes(self):  # type: () -> bytes
        return self._as_unicode().encode('utf-8')

    def __str__(self):  # type: () -> str
        if sys.version_info.major == 2:
            return self._as_bytes()      # line 17
        else:
            return self._as_unicode()    # line 19

    __repr__ = __str__

这会产生以下错误:

c:\tmp> py -3 -m  mypy example.py
example.py:17: error: Incompatible return value type (got "bytes", expected "str")

c:\tmp> py -3 -m  mypy example.py -2
example.py:19: error: Incompatible return value type (got "unicode", expected "str")

有没有办法让mypy相信__str__的类型是copacet? (有没有更好的方法以 2 + 3 兼容的方式编写此代码?)

最佳答案

这里正确的方法实际上不是尝试找到某种可以桥接两个 Python 版本的类型,而是让 mypy 了解您的分支仅在某些版本的 Python 上运行。

为此,请将 sys.version_info.major == 2 更改为如下所示的检查 sys.version_info[0] == 2,例如:

import sys
from typing import Text
from builtins import str as text

class Example(object):

    def _as_unicode(self):  # type: () -> Text
        return text(42)

    def _as_bytes(self):  # type: () -> bytes
        return self._as_unicode().encode('utf-8')

    def __str__(self):  # type: () -> str
        if sys.version_info[0] == 2:
            return self._as_bytes()
        else:
            return self._as_unicode()

    __unicode__ = _as_unicode
    __repr__ = __str__

这最终完全回避了你的问题。例如。由于在 Python 2.7 模式下进行类型检查时“else”分支被标记为无法访问,因此 mypy 不会尝试分析该分支,因此不会报告错误。

如果您愿意,您可以更进一步,只需围绕 __str__ 的整个定义执行一个 if-else:

import sys
from typing import Text
from builtins import str as text

class Example(object):

    def _as_unicode(self):  # type: () -> Text
        return text(42)

    def _as_bytes(self):  # type: () -> bytes
        return self._as_unicode().encode('utf-8')

    if sys.version_info[0] == 2:
        __str__ = _as_bytes
    else:
        __str__ = _as_unicode

    __unicode__ = _as_unicode
    __repr__ = __str__

这里有一些 more info on the version and platform checks mypy 支持。

事实上 mypy 不具体理解 sys.version_info.major 的形式可能是一个疏忽。您可以尝试在 mypy's issue tracker 上提交有关此问题的问题(尽管我不知道这个优先级有多高,因为有简单的解决方法),或者尝试通过修改 consider_sys_version_info 函数 in mypy/reachability.py 来自行添加对此的支持。 .

关于python - 2 和 3 组合代码库中 `__str__` 的类型是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57483303/

相关文章:

python - 使用 Python mechanize 登录网站?

python - 了解 python subprocess.check_output 的第一个参数和 shell=True

python - 错误 : Unsupported format, 或损坏的文件:预期的 BOF 记录

python - 如何告诉 mypy 包含 stub 文件

python - VSCode 是否支持用于 IntelliSense 的 Python .pyi 文件?

python - 从函数中提取包含变量的字典

python多处理从多处理队列访问数据不读取所有数据

python - 使用 MyPy 验证 `Dict` 与 `TypedDict`

mypy:如何忽略 mixin 中的 "missing attribute"错误

python - 如何在不明确列出类型的情况下确保参数具有相同的类型?