【问题标题】:The correct way to annotate a "file type" in Python在 Python 中注释“文件类型”的正确方法
【发布时间】:2017-06-04 13:42:57
【问题描述】:

根据PEP 484,在现代版本的 Python 中,可以使用函数注释进行静态类型分析。这可以通过打字模块轻松完成。

现在我想知道如何为“文件流”提供“类型提示”。

def myfunction(file: FILETYPE):
    pass

with open(fname) as file:
    myfunction(file)

我将插入什么作为FILETYPE

使用print(type(file)) 会返回<class '_io.TextIOWrapper'>,这根本不清楚。

没有通用的“文件”类型吗?

【问题讨论】:

标签: python python-3.5 type-hinting


【解决方案1】:

您可以使用typing.IOtyping.TextIOtyping.BinaryIO 来表示不同类型的 I/O 流。引用documentation

类打字.IO
类打字.TextIO
类打字.BinaryIO

泛型类型IO[AnyStr]及其子类TextIO(IO[str])BinaryIO(IO[bytes])代表I/O流的类型,例如 由open()返回。

【讨论】:

  • typing.IOtyping.TextIOtyping.BinaryIO 自 3.8 版以来已弃用,每次键入 documentation 时将在 3.12 版中删除。
  • @lead-free 我相信弃用说明仅适用于 typing.io 命名空间。见thisthis
  • 虽然目前似乎没有 mypy 会尊重的typing.io 的替代品(io.IOBase 和它的孩子)。
  • @EugeneYarmash 是对的。以下是来自docs 的实际弃用消息:“typing.io 命名空间 已弃用并将被删除。这些类型应直接从 typing 而是。"
【解决方案2】:

我想你想要io.IOBase,“[t]他是所有 I/O 类的抽象基类,作用于字节流。”

请注意,这也包括内存中的流,例如 io.StringIOio.BytesIO。请阅读module io 上的文档了解详细信息。

【讨论】:

  • 就像评论一样:虽然这是我可能得到的“最佳”答案。这个问题仍然没有解决。很多事情都依赖于 _io._base 及其衍生产品。 _io._baseio.base 都没有“通用”顶层?
  • @paul23 我不明白你的意思。 AFAIK io.IOBase 是对“字节流”的最佳类型提示,并且可以使用标准库创建的每个类似文件的对象都是它的一个实例。如果IOBase 与您对字节流的想法不符,或者您的用例不是一个好的类型提示,您可能需要编辑您的问题并解释原因。
  • 例如,如果您使用 BytesIO 打开内存中的字节流;这源自_BufferedIOBase,它源自_IOBase
  • @paul23 这是怎么回事?万一你没有注意到,io.BytesIO 也继承自 io.IOBase
【解决方案3】:

要么:

from typing import TextIO # or IO or BinaryIO

def myfunction(file: TextIO ):
    pass

这个

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from typing import TextIO # or IO or BinaryIO

def myfunction(file: 'TextIO'):
    pass

第二种方法将避免在执行期间导入类。尽管 python 在执行期间仍然必须导入 TYPE_CHECKING,但最好避免导入仅用于类型提示的类:(1) 不执行(只是解析),以及 (2) 它可以避免循环导入

【讨论】:

  • 鉴于类型提示 PEP 484 的目标之一,我不明白为什么避免导入类型提示是一种好习惯。
【解决方案4】:

typeshed 有一个SupportsRead 协议:

from __future__ import annotations
from typing import TYPE_CHECKING, AnyStr

if TYPE_CHECKING:
    from _typeshed import SupportsRead


def takes_readable_str(fo: SupportsRead[str]):
    return fo.read()

def takes_readable_bytes(fo: SupportsRead[bytes]):
    return fo.read()

def takes_readable_any(fo: SupportsRead[AnyStr]):
    return fo.read()

【讨论】:

  • 我会说不应该使用私有模块_typeshed。该模块不是仅适用于类型检查器工具的开发人员吗?
  • 在这种情况下,我们不是有效地为自己开发自定义类型检查器工具吗? Python 类型检查是可选的,因此 if TYPE_CHECKING.
猜你喜欢
  • 1970-01-01
  • 2020-02-20
  • 2012-11-30
  • 2011-01-22
  • 1970-01-01
  • 2016-11-20
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多