mkr*_*er1 11 python type-hinting mypy python-typing
io例如,在编写实现类文件接口的类时,我们可以从模块继承抽象基类之一,如调整迭代器以使其行为类似于 Python 中的类文件对象TextIOBase中所示。
另一方面,在类型注释中,我们应该使用派生自typing.IO(例如TextIO)的类来表示此类对象,如文件或类文件对象的类型提示中所示?或Union 中 io.TextIOBase 的类型检查问题。
然而,这似乎并没有像我预期的那样工作:
import io
import sys
import typing
class MyIO(io.TextIOBase):
def write(self, text: str):
pass
def hello(f: typing.TextIO):
f.write('hello')
hello(sys.stdout) # type checks
hello(open('temp.txt', 'w')) # type checks
hello(MyIO()) # does not type check
Run Code Online (Sandbox Code Playgroud)
当在此代码上运行 mypy 时(使用 Python 3.7.3 和 mypy 0.910),我们得到
错误:“hello”的参数 1 具有不兼容的类型“MyIO”;预期“TextIO”
如何MyIO编写该类,使其被接受为类型的函数参数typing.TextIO(而不仅仅是使用typing.cast(typing.TextIO, ...))?
typing.TextIO不能用作基类:
使用时class MyIO(typing.TextIO):
错误:无法使用抽象属性“__enter__”、“__exit__”、...和“writelines”实例化抽象类“MyIO”(抑制了 15 种方法)
使用时class MyIO(io.TextIOBase, typing.TextIO)::
错误:基类“IOBase”中“readlines”的定义与基类“IO”中的定义不兼容
对于其他几种方法也是如此。
重写__new__和注释typing.TextIO为返回类型不起作用:
def __new__(cls, *args, **kwargs) -> typing.TextIO:
return super().__new__(cls, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
结果是
错误:“__new__”的返回类型不兼容(返回“TextIO”,但必须返回“MyIO”的子类型)
错误:返回值类型不兼容(得到“MyIO”,预期为“TextIO”)
或者这已经应该可以工作了,而我使用的 Python 和/或 mypy 版本太旧了?但是,使用--python-version 3.8or3.9或3.10作为 mypy 的选项不会改变任何内容。
改用io.StringIO
import io
import sys
import typing
class MyIO(io.StringIO):
def write(self, text: str):
pass
def hello(f: typing.TextIO):
f.write("hello")
hello(sys.stdout) # type checks
hello(open("temp.txt", "w")) # type checks
hello(MyIO()) # type checks
Run Code Online (Sandbox Code Playgroud)