我正在尝试转换此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__的类型是copacetic的?
(还有一种更好的方法以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上提交有关此问题的问题(尽管idk会优先考虑此问题的优先级,因为有简单的解决方法),或者您可以尝试自己修改consider_sys_version_info函数in mypy/reachability.py来为此添加支持。

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

10-12 21:05