Python 3.11 预览:TOML 和 tomllib

2023-10-10

Python 3.11 即将于 2022 年 10 月发布最终版本。新版本目前正在进行 Beta 测试,您可以自行安装它来预览和测试一些新功能,包括支持使用新的tomllib模块。

TOML 是一种在 Python 生态系统中越来越流行的配置文件格式。这是由于采用pyproject.toml作为Python打包中的中心配置文件。其他重要工具,例如黑色的, 米皮, 和py测试,也使用 TOML 进行配置。

在本教程中,您将:

  • 安装您计算机上的 Python 3.11 beta,位于当前安装的 Python 旁边
  • 熟悉基础知识TOML格式
  • 阅读 TOML文件与新的tomllib模块
  • 写入TOML与第三方库并了解为什么此功能不包含tomllib
  • 探索 Python 3.11 的新功能打字功能, 包括SelfLiteralString类型以及可变泛型

Python 3.11 中还有许多其他新功能和改进。查看什么是新的在更新日志中获取最新列表,并阅读其他内容Python 3.11 预览在 Real Python 上了解其他功能。

免费下载: 单击此处下载免费示例代码演示了 Python 3.11 的一些新功能。

Python 3.11 测试版

Python 的新版本于每年 10 月发布。该代码是经过开发和测试的十七个月期间在发布日期之前。新功能在α相。对于 Python 3.11,七个阿尔法版本是在 2021 年 10 月至 2022 年 4 月期间制作的。

首先测试版Python 3.11 的发布发生在凌晨2022 年 5 月 8 日。每个此类预发布均由发布经理协调 — 目前巴勃罗·加林多·萨尔加多——并将来自 Python 核心开发人员和其他志愿者的数百个提交联系在一起。

此次发布还标记的功能冻结对于新版本。换句话说,Python 3.11 中不会添加 Python 3.11.0b1 中尚未存在的新功能。相反,功能冻结和发布日期之间的时间(2022 年 10 月 3 日)用于测试和固化代码。

关于每月一次在此期间贝塔期,Python核心开发者发布新测试版继续展示新功能、测试它们并获得早期反馈。目前,Python 3.11的最新测试版是3.11.0b3,发布于2022 年 6 月 1 日.

笔记:本教程使用Python 3.11的第三个测试版。如果您使用更高版本,您可能会遇到细微的差异。然而,tomllib构建在成熟的库上,您可以预期您在本教程中学到的内容在整个测试阶段和 Python 3.11 的最终版本中都将保持不变。

如果您正在维护自己的 Python 包,那么测试阶段是一个重要的时期,您应该开始使用新版本测试您的包。核心开发人员希望与社区一起在最终版本发布之前找到并修复尽可能多的错误。

很酷的新功能

Python 3.11 的一些亮点包括:

  • 增强的错误消息,这可以帮助您更有效地调试代码
  • 任务组和异常组,它简化了异步代码的使用并允许程序引发和处理多重异常同时
  • TOML支持,它允许您使用标准库解析 TOML 文档
  • 静态类型改进,这让您可以更精确地注释代码
  • 优化,这有望使 Python 3.11 比以前的版本快得多

Python 3.11 有很多值得期待的地方!您已经可以阅读有关增强的错误消息任务组和异常组在早些时候Python 3.11 预览文章。如需全面概述,请查看Python 3.11:值得您尝试的酷炫新功能.

在本教程中,您将重点关注如何使用新的tomllib用于读取和解析 TOML 文件的库。您还将简要了解 Python 3.11 附带的一些类型改进。

安装

要使用本教程中的代码示例,您需要在系统上安装 Python 3.11 版本。在本小节中,您将了解执行此操作的几种不同方法:使用码头工人, 使用pyenv,或从安装来源。选择最适合您和您的系统的一种。

笔记:Beta 版本是即将推出的功能的预览。虽然大多数功能都可以正常运行,但您不应该在生产环境或任何其他潜在错误会造成严重后果的地方依赖任何 Python 3.11 beta 版本。

如果您有权访问码头工人在您的系统上,然后您可以通过拉取并运行来下载最新版本的Python 3.11python:3.11-rc-slim Docker镜像:

$ docker pull python:3.11-rc-slim
3.11-rc-slim: Pulling from library/python
[...]
docker.io/library/python:3.11-rc-slim

$ docker run -it --rm python:3.11-rc-slim

这会让你进入 Python 3.11 REPL。查看在 Docker 中运行 Python 版本有关通过 Docker 使用 Python 的更多信息,包括如何运行脚本。

pyenv该工具非常适合管理系统上不同版本的 Python,如果您愿意,可以使用它来安装 Python 3.11 beta。它有两个不同的版本,一种适用于 Windows,另一种适用于 Linux 和 macOS。使用下面的切换器选择您的平台:

在 Windows 上,您可以使用pyenv-win。首先更新你的pyenv安装:

PS> pyenv update
:: [Info] ::  Mirror: https://www.python.org/ftp/python
[...]

进行更新可确保您可以安装最新版本的 Python。你也可以手动更新 pyenv.

在 Linux 和 macOS 上,您可以使用pyenv。首先更新你的pyenv安装,使用pyenv 更新插入:

$ pyenv update
Updating /home/realpython/.pyenv...
[...]

进行更新可确保您可以安装最新版本的 Python。如果您不想使用更新插件,那么您可以手动更新 pyenv.

使用pyenv install --list检查哪些版本的 Python 3.11 可用。然后,安装最新的:

$ pyenv install 3.11.0b3
Downloading Python-3.11.0b3.tar.xz...
[...]

安装可能需要几分钟时间。安装新的测试版后,您可以创建一个虚拟环境你可以在哪里玩它:

PS> pyenv local 3.11.0b3
PS> python --version
Python 3.11.0b3

PS> python -m venv venv
PS> venv\Scripts\activate

你用pyenv local激活你的Python 3.11版本,然后设置虚拟环境python -m venv.

$ pyenv virtualenv 3.11.0b3 311_preview
$ pyenv activate 311_preview
(311_preview) $ python --version
Python 3.11.0b3

在 Linux 和 macOS 上,您可以使用pyenv-virtualenv用于设置虚拟环境并激活它的插件。

您还可以从以下网站上提供的预发行版本之一安装 Pythonpython.org。选择最新预发布并向下滚动到文件页面底部的部分。下载并安装与您的系统相对应的文件。看了解更多信息。

本教程中的大多数示例都依赖于新功能,因此您应该使用 Python 3.11 可执行文件运行它们。运行可执行文件的具体方式取决于您的安装方式。如果您需要帮助,请查看相关教程码头工人, pyenv, 虚拟环境, 或者从源安装.

tomllibPython 3.11 中的 TOML 解析器

Python 是一门成熟的语言。 Python 的第一个公共版本于 1991 年发布,距今已有三十多年了。许多 Python 的独特功能,包括显式异常处理、对空格的依赖以及丰富的数据结构(如列表和字典),甚至在早些年.

不过,Python 第一个版本中缺少的一个功能是共享社区包和模块的便捷方式。这并不奇怪。事实上,Python 大约是在同一时间被发明的。全球资讯网。 1991年底,仅存在十二个网络服务器在全球范围内,他们都没有致力于分发 Python 代码。

随着时间的推移,双方Python互联网变得更受欢迎。一些倡议旨在允许共享 Python 代码。这些特性有机地演变并导致了 Python 的某种程度的发展。混乱的与包装的关系。

这个问题已经通过几个解决方案得到解决包装 PEP(Python 增强提案)在过去的几十年里,情况已经有了很大的改善图书馆维护者终端用户.

一个挑战是构建包依赖于执行setup.py文件,但没有机制可以知道该文件依赖哪些依赖项。这就创造了一种先有鸡还是先有蛋你需要运行的问题setup.py发现如何跑步setup.py.

在实践中,pip—Python 的包管理器 — 假设它应该使用安装工具构建软件包并且安装工具在您的计算机上可用。这使得使用替代构建系统变得更加困难,例如掠过诗歌.

为了解决这个问题,公众号 518介绍了pyproject.toml配置文件,指定 Python 项目构建依赖项。 PEP 518 于 2016 年被接受。当时,TOML 仍然是一种相当新的格式,并且没有内置支持在 Python 或其标准库中解析 TOML。

随着 TOML 格式的成熟和使用pyproject.toml文件已经解决,Python 3.11 添加了对解析 TOML 文件的支持。在本节中,您将详细了解 TOML 格式是什么以及如何使用新的tomllib解析 TOML 文档,以及为什么tomllib不支持写入TOML文件。

学习基本 TOML

汤姆·普雷斯顿-维尔纳第一的宣布 汤姆的浅显易懂的语言——俗称TOML——并发布版本0.1.02013 年制定了其规范。从一开始,TOML 的目标就是提供一种“由于语义明显而易于阅读的最小配置文件格式”(来源)。稳定的版本1.0.0TOML 规范于 2021 年 1 月发布。

TOML 文件是UTF-8编码的、区分大小写的文本文件。 TOML 中的主要构建块是键值对,其中键与值之间用等号分隔(=):

version = 3.11

在这个最小的 TOML 文档中,version是一个具有对应值的键3.11。 TOML 中的值具有类型。3.11被解释为浮点数。您可以利用的其他基本类型是字符串, 布尔值, 整数,和日期:

version = 3.11
release_manager = "Pablo Galindo Salgado"
is_beta = true
beta_release = 3
release_date = 2022-06-01

此示例显示了大多数此类类型。除了具有小写布尔值和特殊的日期文字之外,其语法与 Python 的语法类似。 TOML 键值对的基本形式类似于 Python 变量赋值,因此它们应该看起来很熟悉。有关这些和其他相似之处的更多详细信息,请查看TOML文档.

TOML 文档的核心是键值对的集合。您可以通过将它们包装在数组和表中来向这些对添加一些结构。一个大批是一个值列表,类似于 Python列表。 A桌子是一个嵌套的键值对集合,类似于Pythondict.

您可以使用方括号来包裹数组的元素。一个表是通过以下方式启动的:[key]命名表的行:

[python]
version = 3.11
release_manager = "Pablo Galindo Salgado"
is_beta = true
beta_release = 3
release_date = 2022-06-01
peps = [657, 654, 678, 680, 673, 675, 646, 659]

[toml]
version = 1.0
release_date = 2021-01-12

该 TOML 文档可以用 Python 表示如下:

{
    "python": {
        "version": 3.11,
        "release_manager": "Pablo Galindo Salgado",
        "is_beta": True,
        "beta_release": 3,
        "release_date": datetime.date(2022, 6, 1),
        "peps": [657, 654, 678, 680, 673, 675, 646, 659],
    },
    "toml": {
        "version": 1.0,
        "release_date": datetime.date(2021, 1, 12),
    },
}

[python]TOML 中的 key 在 Python 中由 a 表示"python"字典中的 key 指向包含 TOML 部分中所有键值对的嵌套字典。 TOML表可以任意嵌套,一个TOML文档可以包含多个TOML表。

TOML 语法的简短介绍到此结束。尽管 TOML 在设计上具有相当简单的语法,但仍有一些细节在此未涵盖。要深入了解,请查看Python 和 TOML:新的好朋友或者TOML规范.

除了语法之外,您还应该考虑如何解释 TOML 文件中的值。 TOML文档通常用于配置。最终,其他一些应用程序会使用 TOML 文档中的信息。因此,该应用程序对 TOML 文件的内容有一些期望。这意味着 TOML 文档可能有两种不同类型的错误:

  1. 语法错误:TOML 文档不是有效的 TOML。 TOML 解析器通常会捕获这一点。
  2. 架构错误:TOML 文档是有效的 TOML,但其结构不是应用程序所期望的。应用程序本身必须处理这个问题。

TOML 规范目前不包括可用于验证 TOML 文档结构的模式语言,尽管有几种提案存在。这样的模式将检查给定的 TOML 文档是否包含给定用例的正确表、键和值类型。

作为非正式模式的示例,公众号 517公众号 518说一个pyproject.toml文件应定义build-system表,其中必须包含键requiresbuild-backend。此外,价值requires必须是字符串数组,而值build-backend必须是一个字符串。下面是一个例子满足此模式的 TOML 文档:

# pyproject.toml

[build-system]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

此示例遵循 PEP 517 和 PEP 518 的要求。但是,该验证通常由构建前端完成。

笔记:如果您想了解有关使用 Python 构建自己的包的更多信息,请查看如何将开源 Python 包发布到 PyPI.

您可以自己检查此验证。创建以下错误pyproject.toml文件:

# pyproject.toml

[build-system]
requires = "setuptools>=61.0.0"
backend = "setuptools.build_meta"

这是有效的 TOML,因此任何 TOML 解析器都可以读取该文件。然而,这不是一个有效的build-system根据 PEP 中的要求填写表格。要确认这一点,请安装建造,这是一个符合 PEP 517 的构建前端,并根据您的pyproject.toml文件:

(venv) $ python -m pip install build
(venv) $ python -m build
ERROR Failed to validate `build-system` in pyproject.toml:
      `requires` must be an array of strings

错误消息指出requires必须是一个字符串数组,如 PEP 518 中所指定。使用您的其他版本pyproject.toml归档并记下哪些其他验证build为你做。您可能需要在自己的应用程序中实现类似的验证。

到目前为止,您已经看到了一些 TOML 文档的示例,但是您还没有探索如何在自己的项目中使用它们。在下一小节中,您将了解如何使用新的tomllib封装在标准库中以读取和解析Python 3.11中的TOML文件。

阅读 TOML 的方式tomllib

Python 3.11 在标准库中附带了一个新模块,名为托姆利库。您可以使用tomllib读取和解析任何 TOML v1.0 兼容文档。在本小节中,您将了解如何直接从文件和包含 TOML 文档的字符串加载 TOML。

PEP 680描述tomllib以及导致 TOML 支持被添加到标准库中的一些过程。纳入的两个决定因素tomllibPython 3.11 中的核心角色是pyproject.toml在 Python 打包生态系统中发挥作用,TOML 规范将于 2021 年初达到 1.0 版。

实施tomllib或多或少是直接从通利经过塔内利·胡基宁,他也是 PEP 680 的合著者之一。

tomllib模块非常简单,只包含两个功能:

  1. load()从文件中读取 TOML 文档。
  2. loads()从字符串读取 TOML 文档。

您将首先看到如何使用tomllib阅读以下内容pyproject.toml文件,它是同一文件的简化版本通利项目:

# pyproject.toml

[build-system]
requires = ["flit_core>=3.2.0,<4"]
build-backend = "flit_core.buildapi"

[project]
name = "tomli"
version = "2.0.1"  # DO NOT EDIT THIS LINE MANUALLY. LET bump2version DO IT
description = "A lil' TOML parser"
requires-python = ">=3.7"
readme = "README.md"
keywords = ["toml"]

    [project.urls]
    "Homepage" = "https://github.com/hukkin/tomli"
    "PyPI" = "https://pypi.org/project/tomli"

复制此文档并将其保存在名为pyproject.toml在您的本地文件系统上。您现在可以启动 REPL 会话来探索 Python 3.11 的 TOML 支持:

>>>
>>> import tomllib
>>> with open("pyproject.toml", mode="rb") as fp:
...     tomllib.load(fp)
...
{'build-system': {'requires': ['flit_core>=3.2.0,<4'],
                  'build-backend': 'flit_core.buildapi'},
 'project': {'name': 'tomli',
             'version': '2.0.1',
             'description': "A lil' TOML parser",
             'requires-python': '>=3.7',
             'readme': 'README.md',
             'keywords': ['toml'],
             'urls': {'Homepage': 'https://github.com/hukkin/tomli',
                      'PyPI': 'https://pypi.org/project/tomli'}}}

你用load()通过将文件指针传递给函数来读取和解析 TOML 文件。请注意,文件指针必须指向二进制流。确保这一点的一种方法是使用open()mode="rb",其中b表示二进制模式。

笔记:根据PEP 680,文件必须以二进制模式打开,以便tomllib可以确保 UTF-8 编码在所有系统上都能正确处理。

将原始 TOML 文档与生成的 Python 数据结构进行比较。该文档由 Python 字典表示,其中所有键都是字符串,TOML 中的不同表表示为嵌套字典。观察评论关于version原始文件中的内容将被忽略,并且不属于结果的一部分。

您可以使用loads()加载已在字符串中表示的 TOML 文档。以下示例解析来自上一小节:

>>>
>>> import tomllib
>>> document = """
... [python]
... version = 3.11
... release_manager = "Pablo Galindo Salgado"
... is_beta = true
... beta_release = 3
... release_date = 2022-06-01
... peps = [657, 654, 678, 680, 673, 675, 646, 659]
...
... [toml]
... version = 1.0
... release_date = 2021-01-12
... """

>>> tomllib.loads(document)
{'python': {'version': 3.11,
            'release_manager': 'Pablo Galindo Salgado',
            'is_beta': True,
            'beta_release': 3,
            'release_date': datetime.date(2022, 6, 1),
            'peps': [657, 654, 678, 680, 673, 675, 646, 659]},
 'toml': {'version': 1.0,
          'release_date': datetime.date(2021, 1, 12)}}

类似于load(), loads()返回一个字典。一般来说,表示基于基本的 Python 类型:str, float, int, bool, 也字典, 列表, 和日期时间对象。这tomllib文档包括换算表显示了 TOML 类型在 Python 中的表示方式。

如果您愿意,那么您可以使用loads()通过将其与以下内容结合来从文件中读取 TOMLpathlib:

>>>
>>> import pathlib
>>> import tomllib

>>> path = pathlib.Path("pyproject.toml")
>>> with path.open(mode="rb") as fp:
...     from_load = tomllib.load(fp)
...
>>> from_loads = tomllib.loads(path.read_text())

>>> from_load == from_loads
True

在此示例中,您加载pyproject.toml两者同时使用load()loads()。然后,您确认无论您如何加载文件,Python 表示形式都是相同的。

两个都load()loads()接受一个可选参数:解析浮点。这使您可以控制如何浮点数字解析和表示在Python中。默认情况下,它们被解析并存储为float对象,在大多数 Python 实现中都是 64 位,大约有 16 位十进制数字精确.

如果您需要使用更精确的数字,一种替代方法是使用小数.小数反而:

>>>
>>> import tomllib
>>> from decimal import Decimal
>>> document = """
... small = 0.12345678901234567890
... large = 9999.12345678901234567890
... """

>>> tomllib.loads(document)
{'small': 0.12345678901234568,
 'large': 9999.123456789011}

>>> tomllib.loads(document, parse_float=Decimal)
{'small': Decimal('0.12345678901234567890'),
 'large': Decimal('9999.12345678901234567890')}

在这里,您加载带有两个键值对的 TOML 文档。默认情况下,使用时会失去一点精度load()或者loads()。通过使用Decimal类,您可以保持输入的精度。

如前所述,tomllib模块改编自流行的tomli模块。如果您想使用 TOML 并且tomllib在需要支持旧版本 Python 的代码库上,那么您可以依靠tomli。为此,请在您的需求文件中添加以下行:

tomli >= 1.1.0 ; python_version < "3.11"

这将安装tomli在 3.11 之前的 Python 版本上使用时。在您的源代码中,您可以使用tomllib或者tomli酌情与以下进口:

try:
    import tomllib
except ModuleNotFoundError:
    import tomli as tomllib

此代码将导入tomllib在 Python 3.11 及更高版本上。如果tomllib不可用,那么tomli被导入并别名为tomllib姓名。

您已经了解了如何使用tomllib阅读 TOML 文档。您可能想知道如何编写 TOML 文件。事实证明你不能用以下方式编写 TOMLtomllib。请继续阅读以了解原因并查看一些替代方案。

写入TOML

类似的现有库如jsonpickle包括两者load()dump()函数,后者用于写入数据。这dump()函数,以及相应的dumps(),被故意排除在外tomllib.

根据PEP 680以及围绕它的讨论,这样做有几个原因:

  • 纳入的主要动机tomllib在标准库中是能够生态系统中使用的 TOML 文件。

  • TOML格式被设计成一种人性化的配置格式,因此很多TOML文件都是手动编写的。

  • TOML 格式并不是像 JSON 或 pickle 这样的数据序列化格式,因此与jsonpickleAPI 不是必需的。

  • TOML 文档可能包含写入文件时应保留的注释和格式。这与将 TOML 表示为基本 Python 类型不兼容。

  • 关于如何布局和格式化 TOML 文件有不同的看法。

  • 没有一个核心开发人员表示有兴趣维护一个写入 APItomllib.

一旦将某些内容添加到标准库中,就很难更改或删除,因为有人依赖它。这是一件好事,因为这意味着 Python 基本上保持向后兼容:在 Python 3.10 上运行的 Python 程序很少会在 Python 3.11 上停止工作。

另一个后果是核心团队对于添加新功能持保守态度。如果明确确实有需求,可以稍后添加对编写 TOML 文档的支持。

不过,这并不会让您空手而归。有多种可用的第三方 TOML 编写器。这tomllib文档提到了两个包:

  • 汤姆利-W顾名思义,是tomli可以编写TOML文档。这是一个简单的模块,没有很多控制输出的选项。
  • 汤姆基特是一个用于处理 TOML 文档的强大包,它支持读取和写入。它保留注释、缩进和其他空白。 TOML Kit 的开发和使用是诗歌.

根据您的用例,这些包之一可能会满足您的 TOML 编写需求。

如果您不想添加外部依赖项只是为了编写 TOML 文件,那么您也可以尝试使用自己的编写器。以下示例显示了不完整的 TOML 编写器的示例。它不支持 TOML v1.0 的所有功能,但它支持足以编写pyproject.toml您之前看到的示例:

# tomllib_w.py

from datetime import date

def dumps(toml_dict, table=""):
    document = []
    for key, value in toml_dict.items():
        match value:
            case dict():
                table_key = f"{table}.{key}" if table else key
                document.append(
                    f"\n[{table_key}]\n{dumps(value, table=table_key)}"
                )
            case _:
                document.append(f"{key} = {_dumps_value(value)}")
    return "\n".join(document)

def _dumps_value(value):
    match value:
        case bool():
            return "true" if value else "false"
        case float() | int():
            return str(value)
        case str():
            return f'"{value}"'
        case date():
            return value.isoformat()
        case list():
            return f"[{', '.join(_dumps_value(v) for v in value)}]"
        case _:
            raise TypeError(
                f"{type(value).__name__} {value!r} is not supported"
            )

dumps()函数接受表示 TOML 文档的字典。它通过循环字典中的键值对将字典转换为字符串。您很快就会仔细查看详细信息。首先,您应该检查代码是否有效。打开 REPL 并导入dumps():

>>>
>>> from tomllib_w import dumps
>>> print(dumps({"version": 3.11, "module": "tomllib_w", "stdlib": False}))
version = 3.11
module = "tomllib_w"
stdlib = false

您编写一个包含不同类型值的简单字典。它们被正确地编写为 TOML 类型:数字是普通的,字符串用双引号括起来,布尔值是小写的。

回头看一下代码。大多数 TOML 类型的序列化发生在辅助函数中,_dumps_value()。它用结构模式匹配根据类型构造不同类型的 TOML 字符串value.

主要的dumps()函数与字典一起使用。它循环遍历每个键值对。如果该值是另一个字典,那么它会通过添加表头来构造一个 TOML 表,然后递归调用自身来处理表内的键值对。如果该值不是字典,则_dumps_value()用于将键值对正确转换为 TOML。

如前所述,作者不支持完整的 TOML 规范。例如,它不支持 TOML 中提供的所有日期和时间类型,或内联表或数组表等嵌套结构。字符串处理中还存在一些不受支持的边缘情况。然而,这对于许多应用程序来说已经足够了。

例如,您可以尝试加载然后转储pyproject.toml您之前使用过的文件:

>>>
>>> import tomllib
>>> from tomllib_w import dumps
>>> with open("pyproject.toml", mode="rb") as fp:
...     pyproject = tomllib.load(fp)
...
>>> print(dumps(pyproject))

[build-system]
requires = ["flit_core>=3.2.0,<4"]
build-backend = "flit_core.buildapi"

[project]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
requires-python = ">=3.7"
readme = "README.md"
keywords = ["toml"]

[project.urls]
Homepage = "https://github.com/hukkin/tomli"
PyPI = "https://pypi.org/project/tomli"

在这里,您首先阅读pyproject.tomltomllib。然后你用你自己的tomllib_w将 TOML 文档写回控制台的模块。

您可以扩展tomllib_w如果您需要更好的支持来编写 TOML 文档。但是,在大多数情况下,您应该依赖现有的软件包之一,例如tomli_w或者tomlkit, 反而。

虽然您不支持在 Python 3.11 中编写 TOML 文件,但附带的 TOML 解析器对于许多项目都非常有用。展望未来,您可以将 TOML 用于您的配置文件,因为您将获得在 Python 中读取它们的一流支持。

其他新功能

TOML 支持当然值得庆祝,但 Python 3.11 中也出现了一些较小的改进。长期以来发生这种增量变化的一个领域是 Python类型检查景观。

公众号 484引入了类型提示。它们从 Pyhon 3.5 以及每个新的 Python 版本开始可用增加功能到静态类型系统。乌卡斯·兰加在他的文章中谈到了类型检查基调PyCon 美国 2022会议。

Python 3.11 接受了几个新的与类型相关的 PEP。您很快就会了解更多有关Self类型,即LiteralString类型和可变泛型。

笔记:类型检查增强功能有点特殊,因为它们取决于您的 Python 版本和类型检查工具的版本。最新的 Beta 版本支持一些新的 Python 3.11 类型系统功能,但尚未在所有类型检查器中实现。

例如,您可以监控以下状态:迈皮的支持其新功能GitHub 页面.

甚至还有一些与打字相关的新功能,下面不会介绍。公众号 681添加了@dataclass_transform 装饰者,它可以用类似于以下的语义来标记类数据类。此外,PEP 655让您可以标记必填和可选字段类型化字典.

自体型

公众号 673介绍了一个新的自我型动态引用当前类。当您使用返回类实例的方法实现类时,这非常有用。考虑以下二维点的部分实现:极坐标:

# polar_point.py

import math
from dataclasses import dataclass

@dataclass
class PolarPoint:
    r: float
    φ: float

    @classmethod
    def from_xy(cls, x, y):
        return cls(r=math.hypot(x, y), φ=math.atan2(y, x))

您添加.from_xy()构造函数,以便您可以方便地创建PolarPoint来自相应的实例笛卡尔坐标.

笔记:属性名称.r被故意选择为类似于中使用的数学符号公式.

一般来说,是受到推崇的为您的属性使用更长、更具描述性的名称。但是,有时遵循问题域的约定也很有用。随意更换.r.radius.phi或者.angle如果你更喜欢。

Python源代码被编码为UTF-8经过默认。仍然,身份标识比如变量和属性不能使用完整的 Unicode 字母表。例如,您必须远离表情符号在变量和属性名称中。

您可以按如下方式使用新类:

>>>
>>> from polar_point import PolarPoint
>>> point = PolarPoint.from_xy(3, 4)
>>> point
PolarPoint(r=5.0, φ=0.9272952180016122)

>>> from math import cos
>>> point.r * cos(point.φ)
3.0000000000000004

在这里,您首先创建一个代表笛卡尔点 (3, 4) 的点。在极坐标中,该点用半径表示r= 5.0 和角度φ≈ 0.927。您可以转换回笛卡尔坐标系x与公式协调x = r * cos(φ).

现在,您想要添加类型提示.from_xy()。它返回一个PolarPoint目的。但是,您不能直接使用PolarPoint此时作为注释,因为该类尚未完全定义。相反,您可以使用"PolarPoint"带引号或添加公众号 563未来进口推迟评估的注释。

这两种解决方法都有其作用缺点,以及当前推荐是使用一个TypeVar反而。这种方法即使在子类中也可以工作,但它很麻烦并且容易出错。

随着新Self类型,您可以将类型提示添加到您的类中,如下所示:

import math
from dataclasses import dataclass
from typing import Self

@dataclass
class PolarPoint:
    r: float
    φ: float

    @classmethod
    def from_xy(cls, x: float, y: float) -> Self:
        return cls(r=math.hypot(x, y), φ=math.atan2(y, x))

注释-> Self表明.from_xy()将返回当前类的实例。如果您创建一个子类,这也将正常工作PolarPoint.

拥有Self在工具箱中键入将使使用类和面向对象的功能(如继承)向项目添加静态类型变得更加方便。

任意文字字符串类型

Python 3.11 带来的另一种新类型是LiteralString。虽然这个名字可能会让你想起Literal,它是在 Python 3.8 中添加的,主要用例LiteralString有点不同。要理解将其添加到类型系统的动机,首先退后一步考虑一下字符串。

一般来说,Python 并不关心你如何构造字符串:

>>>
>>> s1 = "Python"
>>> s2 = "".join(["P", "y", "t", "h", "o", "n"])
>>> s3 = input()
Python

>>> s1 == s2 == s3
True

在此示例中,您创建字符串"Python"以三种不同的方式。首先,将其指定为文字字符串。接下来,连接六个单字符字符串的列表以形成字符串"Python"。最后,你读取字符串从用户输入使用输入().

最终测试表明每个字符串的值是相同的。在大多数应用程序中,您不需要关心特定字符串是如何构造的。但是,有时您需要小心,特别是在处理用户输入时。

SQL注入不幸的是,针对数据库的攻击很常见。这Java Log4j 漏洞类似地利用日志系统执行任意代码。

回到上面的例子。虽然价值观s1s3碰巧是相同的,你对这两个字符串的信任度应该是完全不同的。假设您需要构建一条 SQL 语句来从数据库读取有关用户的信息:

>>>
>>> def get_user_sql(user_id):
...     return f"SELECT * FROM users WHERE user_id = '{user_id}'"
...

>>> user_id = "Bobby"
>>> get_user_sql(user_id)
"SELECT * FROM users WHERE user_id = 'Bobby'"

>>> user_id = input()
Robert'; DROP TABLE users; --

>>> get_user_sql(user_id)
"SELECT * FROM users WHERE user_id = 'Robert'; DROP TABLE users; --'"

这是一个改编版经典的SQL注入示例。恶意用户可以利用编写任意 SQL 代码的能力来造成严重破坏。如果执行了最后一条SQL语句,那么它将删除users桌子。

有许多机制可以防御此类攻击。公众号 675在列表中再添加一个。一个新的类型被添加到typing模块:LiteralString是一种特殊的字符串类型,它是在代码中按字面定义的。

您可以使用LiteralString标记容易受到用户控制字符串影响的函数。例如,执行SQL查询的函数可以注释如下:

from typing import LiteralString

def execute_sql(query: LiteralString):
    # ...

类型检查器将特别注意传递的值的类型query在这个函数中。以下字符串都将被允许作为参数execute_sql:

>>>
>>> execute_sql("SELECT * FROM users")

>>> table = "users"
>>> execute_sql("SELECT * FROM " + table)

>>> execute_sql(f"SELECT * FROM {table}")

最后两个例子没问题,因为query由文字字符串构建。字符串仅被识别为LiteralString如果字符串的所有部分都是按字面定义的。例如,以下示例将不会通过类型检查:

>>>
>>> user_input = input()
users

>>> execute_sql("SELECT * FROM " + user_input)

尽管价值user_input恰好与 的值相同table从之前开始,类型检查器会在这里引发错误。用户控制的值user_input并且可能会将其更改为对您的应用程序不安全的内容。如果您使用以下方法标记这些类型的易受攻击的函数LiteralString、类型检查器将帮助您跟踪需要格外小心的情况。

可变参数泛型类型

A 泛型指定用其他类型参数化的类型,例如字符串列表或由整数、字符串和另一个整数组成的元组。 Python 使用方括号来参数化泛型。您将这两个示例写为list[str]tuple[int, str, int], 分别。

A 可变参数是一个接受可变数量参数的实体。例如,print()是一个可变参数函数在Python中:

>>>
>>> print("abc", 123, "def")
abc 123 def

您可以使用以下方法定义自己的可变参数函数*args 和 **kwargs捕获多个位置和关键字参数。

您可以使用typing.Generic如果你想指定你自己的类是通用的。这是向量(也称为一维数组)的示例:

# vector.py

from typing import Generic, TypeVar

T = TypeVar("T")

class Vector(Generic[T]):
    ...

类型变量 T用作任何类型的替代。您可以使用Vector在类型注释中如下:

>>>
>>> from vector import Vector
>>> position: Vector[float]

在这个特定的例子中,Tfloat。为了使您的代码更清晰、类型更安全,您还可以使用类型别名甚至专用派生类型:

>>>
>>> from typing import NewType
>>> from vector import Vector

>>> Coordinate = NewType("Coordinate", float)
>>> Coordinate(3.11)
3.11
>>> type(Coordinate(3.11))
<class 'float'>

>>> position: Vector[Coordinate]

这里,Coordinate行为就像float在运行时,但静态类型检查将区分Coordinatefloat.

现在,假设您创建了一个更通用的数组类,可以处理可变数量的维度。到现在为止,已经有没有什么好办法指定这样的可变泛型.

公众号 646介绍打字.TypeVarTuple来处理这个用例。这些类型变量元组本质上是包装在元组中的任意数量的类型变量。您可以使用它们来定义具有任意维数的数组:

# ndarray.py

from typing import Generic, TypeVarTuple

Ts = TypeVarTuple("Ts")

class Array(Generic[*Ts]):
    ...

请注意解包运算符的使用(*)。这是语法的必要部分,表明Ts代表可变数量的类型。

笔记:您可以导入TypeVarTupletyping_extensions适用于 3.11 之前的 Python 版本。但是,那*Ts语法不适用于这些版本。作为等效的替代方案,您可以使用Typing_extensions.Unpack和写Unpack[Ts].

您可以使用NewType标记数组中的维度或文字指定精确的形状:

>>>
>>> from typing import Literal, NewType
>>> from ndarray import Array

>>> Height = NewType("Height", int)
>>> Width = NewType("Width", int)
>>> Channels = NewType("Channels", int)
>>> image: Array[Height, Width, Channels]

>>> video_frame: Array[Literal[1920], Literal[1080], Literal[3]]

你注释一下image作为一个三维数组,其维度标记为Height, Width, 和Channels。您不指定任何这些维度的大小。第二个例子,video_frame,用文字值注释。在实践中,这意味着video_frame必须是具体形状为1920×1080×3的数组。

主要动机对于可变参数泛型来说,就像您在上面的示例中看到的那样输入数组。不过,也有其他用例. 数值模拟其他数组库计划实施一旦工具就位,可变泛型就可以了。

结论

在本教程中,您了解了 Python 3.11 中可以使用的一些新功能。虽然最终版本将于 2022 年 10 月发布,但您已经可以下载测试版并尝试新功能。在这里,您已经探索了新的tomllib模块并在此过程中更加熟悉 TOML 格式。

您已完成以下操作:

  • 已安装您计算机上的 Python 3.11 beta,位于当前安装的 Python 旁边
  • 阅读 TOML文件与新的tomllib模块
  • 书面TOML使用第三方库并创建自己的函数来编写 TOML 的子集
  • 探索 Python 3.11 的新功能打字功能, 包括SelfLiteralString类型以及可变泛型

您已经在项目中使用 TOML 了吗?尝试新的 TOML 解析器并在下面的评论中分享您的经验。

免费下载: 单击此处下载免费示例代码演示了 Python 3.11 的一些新功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 3.11 预览:TOML 和 tomllib 的相关文章

  • 保存的数据带有不需要的引号

    我使用以下代码将数据框导出到 csv data write format com databricks spark csv options delimiter t codec org apache hadoop io compress Gz
  • 我如何在 ruby​​ 中执行范围正则表达式,例如 awk /start/,/stop/

    我想做一个 AWK 风格的范围正则表达式 如下所示 awk hoststatus file 在 AWK 中 这将打印文件中两个模式之间的所有行 hoststatus host name myhost modified attributes
  • 非常大的数据集的余弦相似度

    我在计算大量 100 维向量之间的余弦相似度时遇到问题 当我使用from sklearn metrics pairwise import cosine similarity I get MemoryError在我的 16 GB 机器上 每个
  • 在 Python 中读取 .docx 文件以查找删除线、项目符号和其他格式

    任何人都可以帮助我在使用 python docx 的 Python 中识别 docx 文件中的段落是否包含带有删除线格式的文本 即它出现但被划掉 或者在开头有一个项目符号点 我正在尝试编写一个脚本来识别文档中的结构并解析内容 到目前为止 我
  • 如何提取图像中的表格

    我想从图像中提取表格 这个 python 模块https pypi org project ExtractTable https pypi org project ExtractTable 与他们的网站https www extractta
  • 在Python中解析制表符分隔的文件

    我正在尝试在 Python 中解析一个制表符分隔的文件 其中与行开头分开的 k 个制表符的数字应该放入第 k 个数组中 除了逐行读取并执行简单解决方案将执行的所有明显处理之外 是否有内置函数可以执行此操作 或者有更好的方法 您可以使用the
  • 将 python 嵌入到我的应用程序中时出现内存泄漏

    以下程序与 python 2 7 13 链接并在 Windows 10 上运行时缓慢但稳定地泄漏内存 include
  • 快速NLTK解析成语法树

    我正在尝试将数百个句子解析为语法树 我需要快速完成 问题是如果我使用 NLTK 那么我需要定义一个语法 而我不知道我只知道它会是英语 我尝试使用this https github com emilmont pyStatParser统计解析器
  • 如何访问 pytest 夹具中的所有标记?

    我正在使用 pytest 我想用标记来标记我的测试 这些标记将指定固定装置要在驱动程序中加载哪个页面 这可以轻松地与行为上下文对象一起使用 但我找不到如何使用 pytest 来做到这一点 以这段代码为例 import pytest pyte
  • Python 中的 Socket.IO 客户端库 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 谁能推荐一个 Python 的 Socket IO 客户端库 我环顾四周 但我能找到的唯一的要么是服务
  • 使用 numpy 数组时出现内存错误 Python

    我原来的list 函数有超过 200 万行代码 当我运行计算 的代码时出现内存错误 有什么办法可以绕过它吗 这list 下面是实际 numpy 数组的一部分 熊猫数据 import pandas as pd import math impo
  • 在 Mac 上安装 python igraph

    我执行了brew install homebrew science igraph当我执行时sudo pip3 install python igraph 我收到以下错误 Cannot find the C core of igraph on
  • Python 视图与复制错误希望我仅在脚本中使用 .loc

    我正在运行一个很长的脚本 其中有一个数据框df 随着脚本运行 构建和修改df我在命令行中一列又一列地收到此错误 尝试在 DataFrame 的切片副本上设置一个值 尝试 使用 loc row indexer col indexer valu
  • 使用 NumPy 查找元组列表第二个元素的中位数

    假设我有一个元组列表 如下所示 list a 1 b 3 c 5 我的目标是使用元组的第二个元素来获取元组列表中位数的第一个元素 在上面的情况下 我想要 b 的输出 因为中位数是 3 我尝试使用 NumPy 和以下代码 但无济于事 impo
  • 维基百科与 Python

    我有这个非常简单的 python 代码来读取 wikipedia api 的 xml import urllib from xml dom import minidom usock urllib urlopen http en wikipe
  • 安装轮子后安装后脚本

    Using from setuptools command install import install 如果我运行 我可以轻松运行自定义安装后脚本python setup py install 这是相当微不足道 https stackov
  • 使用 python mechanize 库登录 https 站点

    我有以下代码 import requests import sys import urllib2 import re import mechanize import cookielib import json import imp prin
  • 在ubuntu 18.04上安装python 2.7

    有没有办法在 Ubuntu 18 04 上安装 Python 2 7 我尝试了这个命令 但它不起作用 sudo apt install python minimal 有没有办法手动安装 我尝试使用 python 2 7 作为不支持 pyth
  • python - lxml:强制执行属性的特定顺序

    我有一个 XML 编写脚本 可以为特定的第 3 方工具输出 XML 我使用原始 XML 作为模板来确保构建所有正确的元素 但最终的 XML 看起来与原始的不同 我以相同的顺序编写属性 但 lxml 按自己的顺序编写它们 我不确定 但我怀疑第
  • Keras 导入错误 Nadam

    我在尝试导入 Keras 模块 Nadam 时遇到导入错误 gt gt gt from keras optimizers import Nadam Traceback most recent call last File

随机推荐

  • 自定义数据类型

    当你通过一个目的到print 它使用以下方法将其转换为字符串str 功能 您可以创建一个 str 自定义对象上的方法来更改输出内容 class Person def init self name age self name name sel
  • Python 内部函数的基础知识

    以下是一些资源 可提供有关本课程所涵盖主题的更多信息 在 Python 中递归思考 真正的Python教程 Python 中的递归 简介 真正的Python教程
  • Python 中的条件语句 (if/elif/else)

    在本分步课程中 您将学习如何在 Python 中使用条件 if 语句 逐步掌握 if 语句 并了解如何在程序中编写复杂的决策代码 参加测验 通过我们的交互式 Python 条件语句 测验来测试您的知识 完成后 您将收到一个分数 以便您可以跟
  • 设置您的 Python CI 项目

    在本视频中 您将学习如何设置用于持续集成 CI 的 Python 项目 因此 创建了 GitHub 存储库 克隆了项目并实现了一些基本的库功能 这是calculator py示例代码中使用的文件 calculator py Calculat
  • ChatterBot:使用 Python 构建聊天机器人

    目录 演示 项目概况 先决条件 第 1 步 使用 Python ChatterBot 创建聊天机器人 第 2 步 开始训练您的聊天机器人 第 3 步 导出 WhatsApp 聊天记录 第 4 步 清理您的聊天导出 第 5 步 使用自定义数据
  • 进行日期和时间算术

    Python 标准库提供了timedelta班级用于表演加减在一个datetime目的 第三方库dateutil有更有用的方法来进行数学计算
  • 运行 Python 脚本

    作为 Python 开发人员需要培养的最重要技能之一是能够运行 Python 脚本和代码 这将是您了解代码是否按计划运行的唯一方法 这甚至是了解您的代码是否有效的唯一方法 本分步课程将指导您完成一系列运行 Python 脚本的方法 具体取决
  • 第 2 节审查

    该视频总结了有关装饰器的第 2 部分 您现在知道如何 创建简单的装饰器并将它们应用到函数中 通过使用应用语法糖 装饰你的功能的符号 重用装饰器并将它们导入到您的程序中 用参数修饰函数 从修饰函数返回值 对Python对象进行内省以及如何使用
  • 通过真正的 Python Slack 社区提升您的技能

    目录 享受生活 保持好奇心 提出问题并尊重他人 找到提问的最佳渠道 Spend Some Time Composing Your Questions 总结您的问题 为您的问题提供背景信息 提供一个最小的可重复示例 提供追溯 请勿交叉发帖 尝
  • 处理时区

    Python 3 9 在时区方面引入了重大变化 添加了zoneinfo数据库 在本课程中 您将学习如何使用ZoneInfo类将时区信息添加到datetime目的 您还将探索不一致的命名标准造成的复杂性 如果您想了解有关圣诞岛 基里蒂马蒂示例
  • PyCon Africa 2019(回顾)

    目录 PyCon Africa 发生了什么 主会议 穆斯塔法 西塞 人工智能产生积极影响的潜力 Meili Triantafyllidi 在柏林 PyLadies 工作 6 年的经验教训 Candy Tricia Khohliwe 网络虚拟
  • 第 142 集:使用 Apache Airflow 协调大型和小型项目

    第 142 集 使用 Apache Airflow 协调大型和小型项目 真正的 Python 播客 2023 年 1 月 27 日54m RSS Apple Podcasts Google Podcasts Spotify More 播客瘾
  • Python 新闻:2023 年 3 月以来的新增内容

    目录 Python 3 12 0 Alpha 6 发布 Python 本地包目录上的 PEP 582 被拒绝 PyCascades 2023 在不列颠哥伦比亚省温哥华举行 PyCon US 2023 招募志愿者 PyPI 发布博客 2022
  • 使用Python或运算符

    Python 中有 3 个布尔运算符 and or 和not 使用它们 您可以测试条件并决定程序将采用哪个执行路径 在本教程中 您将深入了解 Pythonor运算符及其使用方法 在本课程结束时 您将学到 Python 如何or操作员工作 如
  • Python F 字符串:讨厌的细节

    您已经了解了很多有关 F 弦的知识以及它们为何如此出色 在本课程中 您将了解在使用以下内部 f 字符串时要记住哪些细节 引号 词典 牙套 反斜杠
  • Python mmap:使用内存映射进行文件 I/O

    这Python之禅有很多智慧可以提供 一个特别有用的想法是 应该有一种 最好只有一种 明显的方法来做到这一点 然而 在 Python 中完成大多数事情有多种方法 而且通常都有充分的理由 例如 有Python 读取文件的多种方法 包括很少使用
  • Python 图形用户界面编程

    Python 图形用户界面编程 学习路径 技能 图形用户界面 GUI Python支持多种GUI框架或工具包 从传统上与 Python 捆绑在一起的 Tkinter 到许多跨平台解决方案 例如 PyQT 或 wxPython 您可以将其作为
  • 第 78 集:通过图解故事学习 Python

    第 78 集 通过图解故事学习 Python 真正的 Python 播客 2021 年 9 月 17 日48m RSS Apple Podcasts Google Podcasts Spotify More 播客瘾君子 灰蒙蒙 袖珍铸件 投
  • Django 测试(第 1 部分)——最佳实践和示例

    目录 Intro to Testing in Django 测试类型 最佳实践 结构 第三方包 Examples 设置 测试模型 测试视图 测试表格 测试 API 下次 测试至关重要 如果没有正确测试您的代码 您将永远不会知道代码现在或将来
  • Python 3.11 预览:TOML 和 tomllib

    目录 Python 3 11 Beta 很酷的新功能 安装 tomllib TOML Parser in Python 3 11 学习基本 TOML 使用 tomllib 读取 TOML 写入TOML Other New Features