组合 2 和 3 代码库中 `__str__` 的类型是什么?
What is the type of `__str__` in a combined 2 and 3 code base?
我正在尝试转换这个 py2 class:
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 (though idk how highly this one would be prioritized, given there are easy workarounds), or perhaps try adding support for this yourself by tinkering with the consider_sys_version_info
function in mypy/reachability.py
.
上提交有关此问题的问题
我正在尝试转换这个 py2 class:
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 (though idk how highly this one would be prioritized, given there are easy workarounds), or perhaps try adding support for this yourself by tinkering with the consider_sys_version_info
function in mypy/reachability.py
.