在 Python 中注释“文件类型”的正确方法
Posted
技术标签:
【中文标题】在 Python 中注释“文件类型”的正确方法【英文标题】:The correct way to annotate a "file type" in 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'>
,这根本不清楚。
没有通用的“文件”类型吗?
【问题讨论】:
注解是否必须引用磁盘上的物理文件,或者它还可以包含类似文件的对象,如StringIO
?
相关:***.com/q/38569401,***.com/q/24501462
【参考方案1】:
您可以使用typing.IO
、typing.TextIO
和typing.BinaryIO
来表示不同类型的 I/O 流。引用documentation:
类打字.IO 类打字.TextIO 类打字.BinaryIO
泛型类型
IO[AnyStr]
及其子类TextIO(IO[str])
和BinaryIO(IO[bytes])
代表I/O流的类型,例如 由open()
返回。
【讨论】:
typing.IO
、typing.TextIO
和 typing.BinaryIO
自 3.8 版以来已弃用,每次键入 documentation 时将在 3.12 版中删除。
@lead-free 我相信弃用说明仅适用于 typing.io
命名空间。见this 和this。
虽然目前似乎没有 mypy 会尊重的typing.io
的替代品(io.IOBase
和它的孩子)。
@EugeneYarmash 是对的。以下是来自docs 的实际弃用消息:“typing.io
命名空间 已弃用并将被删除。这些类型应直接从 typing
而是。"【参考方案2】:
我想你想要io.IOBase
,“[t]他是所有 I/O 类的抽象基类,作用于字节流。”
请注意,这也包括内存中的流,例如 io.StringIO
和 io.BytesIO
。请阅读module io
上的文档了解详细信息。
【讨论】:
就像评论一样:虽然这是我可能得到的“最佳”答案。这个问题仍然没有解决。很多事情都依赖于 _io._base 及其衍生产品。_io._base
和 io.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
.以上是关于在 Python 中注释“文件类型”的正确方法的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Python 中使用 ruamel.yaml 从 YAML 文件中获取注释?