我想将类型注释应用于csv.writer
的返回对象,以符合更大的代码库。不幸的是,我无法弄清楚拟合返回类型。
>>> import csv
>>> writer = csv.writer(open('outfile.csv', 'w'))
>>> type(writer)
<class '_csv.writer'>
如果我尝试使用该类名:
>>> import _csv
>>> writer: _csv.writer = csv.writer(open('outfile.csv', 'w'))
我收到以下mypy错误:
Invalid type "_csv.writer"
有人知道在这种情况下要使用哪种类型。当然,我可以使用typing.Any
,但这会使类型注释的含义无效。
答案 0 :(得分:2)
简短的回答是无法直接访问类型。读取C source of the _csv module将显示Boolean
和reader
的类型未公开。即使在使用Python实现_csv模块的Pypy中,也不会公开类型。
因此,如果需要使用它,则需要使用变通方法,方法是实例化writer的临时实例并获取其类型。
writer
如果您希望将此逻辑分开,建议您在单独的模块中创建类型
import csv
# We'll need a temporary file-like object, so use a tempfile
from tempfile import TemporaryFile
with TemporaryFile() as t:
CSVReader = type(csv.reader(t))
CSVWriter = type(csv.writer(t))
w: CSVWriter = csv.writer('path/to/data.csv')
另一种解决方案(也涉及编写自己的类型模块),是在from csv_types import CSVReader, CSVWriter
和io
的类型定义中遵循typing
模块的示例。 / p>
答案 1 :(得分:2)
一种解决方案是编写一个代表类型的抽象类。对于typing模块中的某些类,也是如此。对于以下的csv.writer()
函数:
class _CSVWriter:
@abstractmethod
def writerow(self, row: List[str]) -> None:
pass
@abstractmethod
def writerows(self, rows: List[List[str]]) -> None:
pass
@abstractproperty
def dialect(self) -> csv.Dialect:
pass
现在可以在writer
对象的类型注释中使用此类。由于返回对象的类型名称仍然为_csv.writer
,因此您仍然会收到类型错误。为避免这种情况,您需要将其强制转换为_CSVWriter
对象。
from typing import cast
writer: _CSVWriter = cast(_CSVWriter, csv.writer(open('test', 'w'))
该解决方案有点冗长,但是可以完成工作。
答案 2 :(得分:0)
通常,当事情变得很奇怪时,它是一个没有正确映射到运行时的符号。如果查看_csv in typeshed,您会看到类型名为_writer
。它还在csv中重新导出。因此,您应该将注释更改为csv._writer
。
答案 3 :(得分:0)
我在输入格式的def时遇到了问题,最终使用了以下内容:
class Writer(Protocol):
def writerow(self, row: Iterable[Any]) -> Any:
...
def writerows(self, rows: Iterable[Iterable[Any]]) -> None:
...
Reader = Iterator[Any]
writer: Writer = csv.writer(open('outfile.csv', 'w'))
reader: Reader = csv.writer(open('outfile.csv', 'w'))