代码之家  ›  专栏  ›  技术社区  ›  MrLeeh

如何键入csv.writer返回的annotate对象?

  •  7
  • MrLeeh  · 技术社区  · 6 年前

    我要将类型批注应用于返回的对象 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 但这会使类型注释的意义失效。

    3 回复  |  直到 6 年前
        1
  •  0
  •   ethanhs    6 年前

    通常情况下,当事情变得很奇怪时,这是一个符号类型化并不能精确映射到运行时。如果你看csv in typeshed 您将看到类型是命名的 _writer .它也在 csv .所以您应该将注释更改为 csv._writer .

        2
  •  2
  •   Edward Minnix    6 年前

    简短的回答是,无法直接访问类型。阅读 C source of the _csv module 将显示 reader writer 不暴露。即使在 Pypy 如果在python中实现了csv模块,则不会公开类型。

    因此,如果需要使用它,则需要通过实例化编写器的临时实例并获取它的类型来使用一个变通方法。

    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 模块的类型定义 io re .

        3
  •  2
  •   MrLeeh    6 年前

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

    这个解决方案有点冗长,但它可以完成这项工作。