Python 3 中的 __total__ dunder 属性是什么意思?

What is the meaning of __total__ dunder attribute in Python 3?

在新发布的Python 3.8中有一个新的类型注解typing.TypedDict。它的文档提到

The type info for introspection can be accessed via Point2D.__annotations__ and Point2D.__total__. [....]

虽然 __annotations__ 是众所周知的,已在 PEP 3107 中介绍过,但我找不到关于 __total__ 的任何信息。谁能解释一下它的含义,如果可能的话,可以链接到权威来源吗?

我猜测 __total__ 字段表示实例是否必须完整(默认)或不完整(所有字段都是可选的)。我从 PEP 589 开始搜索,它介绍了 TypedDict 并描述了整体性。它使用了一个 total 参数,为 class 语法重命名 dunder-style 是有意义的。但是,我没有找到这样的重命名是什么时候发生的。

查看 MyPy,它是关心这些注释的实际类型检查器,similar documentation on TypedDict and totality, but again no reference to the dunder syntax. Digging into its implementation led to more confusion, as TypedDictType in types.py 没有总字段,而是分开的 itemsrequired_keys。整体性意味着 items.keys()==required_keys 但实现会做出不同的假设,例如 can_be_false 单独依赖 itemstotal=False 原则上应该意味着 required_keys 是空的。

_TypedDictMeta 的 CPython 源代码至少揭示了 total 参数和 __total__ dunder 是一回事,尽管源代码将 TypedDict 本身描述为 "may be added soon"。

TypedDict 通过 PEP 589 在 Python 3.8 中被接受。从 Python 看来,__total__ 是一个默认设置为 True 的布尔标志:

tot = TypedDict.__total__
print(type(tot))
print(tot)

# <class 'bool'>
# True

如其他帖子所述,有关此方法的详细信息仅限于 docs, but @Yann Vernier's link to the CPython source code strongly suggests __total__ is related to the new total keyword introduced in Python 3.8:

# cypthon/typing.py

class _TypedDictMeta(type):
    def __new__(cls, name, bases, ns, total=True):
        """Create new typed dict class object.
        ...
        """
        ...
        if not hasattr(tp_dict, '__total__'):
            tp_dict.__total__ = total
        ...

它是如何工作的?

概要: 默认情况下,实例化定义的 TypedDict 时需要所有键。 total=False 覆盖此限制并允许可选键。请看下面的演示。

给定

测试目录树:

代码

测试目录中的文件:

# rgb_bad.py

from typing import TypedDict


class Color(TypedDict):
    r: int
    g: int
    b: int
    a: float


blue = Color(r=0, g=0, b=255)                     # missing "a"

# rgb_good.py

from typing import TypedDict


class Color(TypedDict, total=False):
    r: int
    g: int
    b: int
    a: float


blue = Color(r=0, g=0, b=255)                     # missing "a"

演示

如果缺少一个密钥,mypy 会在命令行报错:

> mypy code/rgb_bad.py
code\rgb_bad.py:11: error: Key 'a' missing for TypedDict "Color"
...

设置 total=False 允许可选键:

> mypy code/rgb_good.py
Success: no issues found in 1 source file

另请参阅

  • Tweet 由 R. Hettinger 展示整体性
  • PEP section PEP 589 中的全部内容
  • 关于类型的文章 Section 和 Python 3.8 中的 TypedDict 由 Real Python
  • typing-extensions package 在 Python 3.5、3.6
  • 中使用 TypedDict