如何对csv.writer返回的对象进行类型注释?

时间:2018-07-10 11:45:52

标签: python mypy

我想将类型注释应用于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,但这会使类型注释的含义无效。

4 个答案:

答案 0 :(得分:2)

简短的回答是无法直接访问类型。读取C source of the _csv module将显示Booleanreader的类型未公开。即使在使用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'))