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

ecfsfe2w  于 5个月前  发布在  其他
关注(0)|答案(6)|浏览(75)

我想对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,但这使类型注解的意义无效。

ryhaxcpt

ryhaxcpt1#

通常情况下,当事情表现得很奇怪的时候,这是一个符号,typeshed并没有准确地Map到运行时。如果你在typeshed中查看_csv,你会看到类型名为_writer。所以你应该把注解改为_csv._writer

emeijp43

emeijp432#

我在使用类型化defs时遇到了问题,最后使用了以下代码:

class Writer(Protocol):
    def writerow(self, row: Iterable[Any]) -> Any:
        ...

    def writerows(self, rows: Iterable[Iterable[Any]]) -> None:
        ...

Reader = Iterator[Any]

个字符

cbeh67ev

cbeh67ev3#

简短的回答是没有办法直接访问类型。阅读C source of the _csv module将显示readerwriter的类型没有暴露。即使在Pypy中,_csv模块是用Python实现的,也没有暴露类型。
因此,如果您需要使用它,您将需要使用一种变通方法,通过示例化编写器的临时示例并获取其类型。

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


另一种解决方案(也包括编写自己的类型模块)是遵循typing模块的例子,在它的iore类型定义中。

frebpwbc

frebpwbc4#

一种解决方案是编写一个表示类型的抽象类。这也是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'))


这个解决方案有点冗长,但它确实完成了这项工作。

bq8i3lrv

bq8i3lrv5#

它没有文档记录,但我能够在Python 3.10的_csv.Writer中找到它。

>>> import csv
>>> from _csv import Writer
>>> 
>>> repr(_csv.Writer)
"<class '_csv.writer'>"
>>> 
>>> writer = csv.writer(file)
>>> isinstance(writer, Writer)
True

字符串
我会避免在生产软件中使用这个,因为考虑到其他注解,该符号的名称似乎已经随着时间的推移而改变。

piv4azn7

piv4azn76#

我看到原来的类继承自Iterator,所以我可以这样做:

from typing import Iterator

with open(spec_file) as csv_file:
            spec_csv: Iterator = csv.reader(csv_file)

字符串
然后用mypy看:

Success: no issues found in 1 source file

相关问题