Python-Standard Library


Python 标准库

  • 概述

    • 可用性注释
  • 内置函数

  • 内置常量

    • site 模块添加的常量
  • 内置类型

    • 逻辑值检测
    • 布尔运算 —- and, or, not
    • 比较运算
    • 数字类型 —- int, float, complex
    • 迭代器类型
    • 序列类型 —- list, tuple, range
    • 文本序列类型 —- str
    • 二进制序列类型 —- bytes, bytearray, memoryview
    • 集合类型 —- set, frozenset
    • 映射类型 —- dict
    • 上下文管理器类型
    • Type Annotation Types —- Generic Alias, Union
    • 其他内置类型
    • 特殊属性
  • 内置异常

    • 基类
    • 具体异常
    • 警告
    • 异常层次结构
  • 文本处理服务

    • string —- 常见的字符串操作
    • re —- 正则表达式操作
    • difflib —- 计算差异的辅助工具
    • textwrap —- 文本自动换行与填充
    • unicodedata —- Unicode 数据库
    • stringprep —- 因特网字符串预备
    • readline —- GNU readline 接口
    • rlcompleter —- GNU readline 的补全函数
  • 二进制数据服务

    • struct —- 将字节串解读为打包的二进制数据
    • codecs —- 编解码器注册和相关基类
  • 数据类型

    • datetime —- 基本日期和时间类型
    • zoneinfo —- IANA 时区支持
    • calendar —- 日历相关函数
    • collections —- 容器数据类型
    • collections.abc —- 容器的抽象基类
    • heapq —- 堆队列算法
    • bisect —- 数组二分查找算法
    • array —- 高效的数值数组
    • weakref —- 弱引用
    • types —- 动态类型创建和内置类型名称
    • copy —- 浅层 (shallow) 和深层 (deep) 复制操作
    • pprint —- 数据美化输出
    • reprlib —- 另一种 repr() 实现
    • enum —- 对枚举的支持
    • graphlib —- 操作类似图的结构的功能
  • 数字和数学模块

    • numbers —- 数字的抽象基类

    • math —- 数学函数

    • cmath —- 关于复数的数学函数

    • decimal —- 十进制定点和浮点运算

    • fractions —- 分数

    • random —- 生成伪随机数

    • statistics —- 数学统计函数

概述

“Python 库”中包含了几种不同的组件。

它包含通常被视为语言“核心”中的一部分的数据类型,例如数字和列表。对于这些类型,Python语言核心定义了文字的形式,并对它们的语义设置了一些约束,但没有完全定义语义。(另一方面,语言核心确实定义了语法属性,如操作符的拼写和优先级。)

这个库也包含了内置函数和异常 —- 不需要 import 语句就可以在所有Python代码中使用的对象。有一些是由语言核心定义的,但是许多对于核心语义不是必需的,并且仅在这里描述。

不过这个库主要是由一系列的模块组成。这些模块集可以不同方式分类。有些模块是用 C 编写并内置于 Python 解释器中;另一些模块则是用 Python 编写并以源码形式导入。有些模块提供专用于 Python 的接口,例如打印栈追踪信息;有些模块提供专用于特定操作系统的接口,例如操作特定的硬件;另一些模块则提供针对特定应用领域的接口,例如万维网。有些模块在所有更新和移植版本的 Python 中可用;另一些模块仅在底层系统支持或要求时可用;还有些模块则仅当编译和安装 Python 时选择了特定配置选项时才可用。

内置函数

Python 解释器内置了很多函数和类型,任何时候都能使用。以下按字母顺序给出列表。

  • abs(x)

返回一个数的绝对值。 参数可以是整数、浮点数或任何实现了 __abs__() 的对象。 如果参数是一个复数,则返回它的模。

  • aiter(async_iterable)

返回 asynchronous iterable 的 asynchronous iterator 。相当于调用 x.__aiter__()

  • aiter(x) 本身带有 __aiter__() 方法,返回 x,所以 aiter(aiter(x))aiter(x) 相同。

注意:与 iter() 不同,aiter() 没有两个参数的版本。

3.10 新版功能.

  • all(iterable)

如果 iterable 的所有元素均为真值(或可迭代对象为空)则返回 True 。 等价于:

def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True
  • awaitable anext(async_iterator[, default])

当进入 await 状态时,从给定 asynchronous iterator 返回下一数据项,迭代完毕则返回 default

这是内置函数 next() 的异步版本,类似于:

调用 async_iterator__anext__() 方法,返回一个 awaitable。等待返回迭代器的下一个值。若有给出 default,则在迭代完毕后会返回给出的值,否则会触发 StopAsyncIteration

3.10 新版功能.

  • any(iterable)

如果 iterable 的任一元素为真值则返回 True。 如果可迭代对象为空,返回 False。 等价于:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False
  • ascii(object)

repr() 类似,返回一个字符串,表示对象的可打印形式,但在 repr() 返回的字符串中,非 ASCII 字符会用 \x\u\U 进行转义。生成的字符串类似于 Python 2 中 repr() 的返回结果。

  • bin(x)

将整数转变为以“0b”前缀的二进制字符串。结果是一个合法的 Python 表达式。如果 x 不是 Python 的 int 对象,它必须定义 __index__() 方法,以便返回整数值。下面是一些例子:

>>> bin(3)
'0b11'
>>> bin(-10)
'-0b1010'

若要控制是否显示前缀“0b”,可以采用以下两种方案:

>>> format(14,'#b'), format(14,'b')
('0b1110','1110')
>>> f'{14:#b}', f'{14:b}'
('0b1110','1110')

另见 format() 获取更多信息。

  • class bool([x])

返回布尔值,TrueFalsex 用标准的 真值测试过程 进行转换。如果 x 为 False 或省略,则返回 False;否则返回 Truebool 类是 int 的子类。它不能再被继承。它唯一的实例就是 FalseTrue

在 3.7 版更改: x 现在只能作为位置参数。

  • breakpoint(\args, *kws)

此函数会在调用时将你陷入调试器中。具体来说,它调用 sys.breakpointhook() ,直接传递 argskws 。默认情况下, sys.breakpointhook() 调用 pdb.set_trace() 且没有参数。在这种情况下,它纯粹是一个便利函数,因此您不必显式导入 pdb 且键入尽可能少的代码即可进入调试器。但是, sys.breakpointhook() 可以设置为其他一些函数并被 breakpoint() 自动调用,以允许进入你想用的调试器。

引发一个 审计事件builtins.breakpoint 并附带参数 breakpointhook

3.7 新版功能.

  • class bytearray([source[, encoding[, errors]]])

返回一个新的 bytes 数组。 bytearray 类是一个可变序列,包含范围为 0 <= x < 256 的整数。它有可变序列大部分常见的方法,见 可变序列类型 的描述;同时有 bytes 类型的大部分方法。

可选形参 source 可以用不同的方式来初始化数组:

  • 如果是一个 string*,您必须提供 *encoding 参数(errors 参数仍是可选的);bytearray() 会使用 str.encode() 方法来将 string 转变成 bytes。
  • 如果是一个 integer,会初始化大小为该数字的数组,并使用 null 字节填充。
  • 如果是一个遵循 缓冲区接口 的对象,该对象的只读缓冲区将被用来初始化字节数组。
  • 如果是一个 iterable 可迭代对象,它的元素的范围必须是 0 <= x < 256 的整数,它会被用作数组的初始内容。

如果没有实参,则创建大小为 0 的数组。

  • class bytes([source[, encoding[, errors]]])

返回一个新的“bytes”对象,这是一个不可变序列,包含范围为 0 <= x < 256 的整数。bytesbytearray 的不可变版本——带有同样不改变序列的方法,支持同样的索引、切片操作。

因此,构造函数的实参和 bytearray() 相同。

  • callable(object)

如果参数 object 是可调用的就返回 True,否则返回 False。 如果返回 True,调用仍可能失败,但如果返回 False,则调用 object 将肯定不会成功。 请注意类是可调用的(调用类将返回一个新的实例);如果实例所属的类有 __call__() 则它就是可调用的。

3.2 新版功能: 这个函数一开始在 Python 3.0 被移除了,但在 Python 3.2 被重新加入。

  • chr(i)

返回 Unicode 码位为整数 i 的字符的字符串格式。例如,chr(97) 返回字符串 'a'chr(8364) 返回字符串 '€'。这是 ord() 的逆函数。

实参的合法范围是 0 到 1,114,111(16 进制表示是 0x10FFFF)。如果 i 超过这个范围,会触发 ValueError 异常。

  • @classmethod

把一个方法封装成类方法。

类方法隐含的第一个参数就是类,就像实例方法接收实例作为参数一样。要声明一个类方法,按惯例请使用以下方案:

class C:
@classmethod
def f(cls, arg1, arg2,...):...

@classmethod 这样的形式称为函数的 decorator 。

类方法的调用可以在类上进行 (例如 C.f()) 也可以在实例上进行 (例如 C().f())。 其所属类以外的类实例会被忽略。 如果类方法在其所属类的派生类上调用,则该派生类对象会被作为隐含的第一个参数被传入。

类方法与 C++ 或 Java 中的静态方法不同。

在 3.9 版更改: 类方法现在可以包装其他 描述器 例如 property()

在 3.10 版更改: 类方法现在继承了方法的属性(__module____name____qualname____doc____annotations__),并拥有一个新的__wrapped__ 属性。

  • compile(source, filename, mode, flags=0, dont_inherit=False, optimize=- 1)

source 编译成代码或 AST 对象。代码对象可以被 exec()eval() 执行。source 可以是常规的字符串、字节字符串,或者 AST 对象。

filename 实参需要是代码读取的文件名;如果代码不需要从文件中读取,可以传入一些可辨识的值(经常会使用 '<string>')。

mode 实参指定了编译代码必须用的模式。如果 source 是语句序列,可以是 'exec';如果是单一表达式,可以是 'eval';如果是单个交互式语句,可以是 'single'。(在最后一种情况下,如果表达式执行结果不是 None 将会被打印出来。)

可选参数 flagsdont_inherit 控制应当激活哪个 编译器选项 以及应当允许哪个 future 特性。 如果两者都未提供 (或都为零) 则代码会应用与调用 compile() 的代码相同的旗标来编译。 如果给出了 flags 参数而未给出 dont_inherit (或者为零) 则会在无论如何都将被使用的旗标之外还会额外使用 flags 参数所指定的编译器选项和 future 语句。 如果 dont_inherit 为非零整数,则只使用 flags 参数 — 外围代码中的旗标 (future 特性和编译器选项) 会被忽略。

编译器选项和 future 语句是由比特位来指明的。 比特位可以通过一起按位 OR 来指明多个选项。 指明特定 future 特性所需的比特位可以在 __future__ 模块的 _Feature 实例的 compiler_flag 属性中找到。 编译器旗标 可以在 ast 模块中查找带有 PyCF_ 前缀的名称。

optimize 实参指定编译器的优化级别;默认值 -1 选择与解释器的 -O 选项相同的优化级别。显式级别为 0 (没有优化;__debug__ 为真)、1 (断言被删除, __debug__ 为假)或 2 (文档字符串也被删除)。

如果编译的源码不合法,此函数会触发 SyntaxError 异常;如果源码包含 null 字节,则会触发 ValueError 异常。

引发一个 审计事件compile 附带参数 source, filename

注解

'single''eval' 模式编译多行代码字符串时,输入必须以至少一个换行符结尾。 这使 code 模块更容易检测语句的完整性。

警告

在将足够大或者足够复杂的字符串编译成 AST 对象时,Python 解释器有可能因为 Python AST 编译器的栈深度限制而崩溃。

在 3.2 版更改: Windows 和 Mac 的换行符均可使用。而且在 'exec' 模式下的输入不必再以换行符结尾了。另增加了 optimize 参数。

在 3.5 版更改: 之前 source 中包含 null 字节的话会触发 TypeError 异常。

3.8 新版功能: ast.PyCF_ALLOW_TOP_LEVEL_AWAIT 现在可在旗标中传入以启用对最高层级 await, async forasync with 的支持。

  • classcomplex([real[, imag]])

返回值为 real + imagj 的复数,或将字符串或数字转换为复数。如果第一个形参是字符串,则它被解释为一个复数,并且函数调用时必须没有第二个形参。第二个形参不能是字符串。每个实参都可以是任意的数值类型(包括复数)。如果省略了 imag,则默认值为零,构造函数会像 intfloat 一样进行数值转换。如果两个实参都省略,则返回 0j

对于一个普通 Python 对象 xcomplex(x) 会委托给 x.__complex__()。 如果 __complex__() 未定义则将回退至 __float__()。 如果 __float__() 未定义则将回退至 __index__()

注解

当从字符串转换时,字符串在 +- 的周围必须不能有空格。例如 complex('1+2j') 是合法的,但 complex('1 + 2j') 会触发 ValueError 异常。

在 3.6 版更改: 您可以使用下划线将代码文字中的数字进行分组。

在 3.8 版更改: 如果 __complex__()__float__() 未定义则回退至 __index__()

  • delattr(object, name)

setattr() 相关的函数。实参是一个对象和一个字符串。该字符串必须是对象的某个属性。如果对象允许,该函数将删除指定的属性。例如 delattr(x, 'foobar') 等价于 del x.foobar

  • classdict(**kwarg)*
  • classdict(*mapping, **kwarg)
  • classdict(*iterable, **kwarg)

创建一个新的字典。dict 对象是一个字典类。

  • dir([object])

如果没有实参,则返回当前本地作用域中的名称列表。如果有实参,它会尝试返回该对象的有效属性列表。

如果对象有一个名为 __dir__() 的方法,那么该方法将被调用,并且必须返回一个属性列表。这允许实现自定义 __getattr__()__getattribute__() 函数的对象能够自定义 dir() 来报告它们的属性。

如果对象未提供 __dir__() 方法,该函数会尽量从对象的 __dict__ 属性和其类型对象中收集信息。得到的列表不一定是完整,如果对象带有自定义 __getattr__() 方法时,结果可能不准确。

默认的 dir() 机制对不同类型的对象行为不同,它会试图返回最相关而不是最全的信息:

  • 如果对象是模块对象,则列表包含模块的属性名称。
  • 如果对象是类型或类对象,则列表包含它们的属性名称,并且递归查找所有基类的属性。
  • 否则,列表包含对象的属性名称,它的类属性名称,并且递归查找它的类的所有基类的属性。

返回的列表按字母表排序。例如:

>>>import struct
>>> dir()# show the names in the module namespace  
['__builtins__','__name__','struct']
>>> dir(struct)# show the names in the struct module 
['Struct','__all__','__builtins__','__cached__','__doc__','__file__',
'__initializing__','__loader__','__name__','__package__',
'_clearcache','calcsize','error','pack','pack_into',
'unpack','unpack_from']
>>>class Shape:
...def __dir__(self):
...return['area','perimeter','location']
>>> s =Shape()
>>> dir(s)
['area','location','perimeter']

注解

因为 dir() 主要是为了便于在交互式时使用,所以它会试图返回人们感兴趣的名字集合,而不是试图保证结果的严格性或一致性,它具体的行为也可能在不同版本之间改变。例如,当实参是一个类时,metaclass 的属性不包含在结果列表中。

  • divmod(a, b)

以两个(非复数)数字为参数,在作整数除法时,返回商和余数。若操作数为混合类型,则适用二进制算术运算符的规则。对于整数而言,结果与 (a // b, a % b) 相同。对于浮点数则结果为(q, a % b),其中 q 通常为 math.floor(a / b),但可能比它小 1。在任何情况下,q * b + a % b 都非常接近 a,如果 a % b 非零,则结果符号与 b 相同,并且 0 <= abs(a % b) < abs(b)

  • enumerate(iterable, start=0)

返回一个枚举对象。iterable 必须是一个序列,或 iterator,或其他支持迭代的对象。 enumerate() 返回的迭代器的 __next__() 方法返回一个元组,里面包含一个计数值(从 start 开始,默认为 0)和通过迭代 iterable 获得的值。

>>> seasons =['Spring','Summer','Fall','Winter']
>>> list(enumerate(seasons))
[(0,'Spring'),(1,'Summer'),(2,'Fall'),(3,'Winter')]
>>> list(enumerate(seasons, start=1))
[(1,'Spring'),(2,'Summer'),(3,'Fall'),(4,'Winter')]

等价于:

def enumerate(sequence, start=0):
    n = start
for elem in sequence:
    yield n, elem
    n +=1
  • eval(expression[, globals[, locals]])

实参是一个字符串,以及可选的 globals 和 locals。globals 实参必须是一个字典。locals 可以是任何映射对象。

表达式解析参数 expression 并作为 Python 表达式进行求值(从技术上说是一个条件列表),采用 globalslocals 字典作为全局和局部命名空间。 如果存在 globals 字典,并且不包含 __builtins__ 键的值,则在解析 expression 之前会插入以该字符串为键以对内置模块 builtins 的字典的引用为值的项。 这样就可以在将 globals 传给 eval() 之前通过向其传入你自己的 __builtins__ 字典来控制可供被执行代码可以使用哪些内置模块。 如果 locals 字典被省略则它默认为 globals 字典。 如果两个字典都被省略,则将使用调用 eval() 的环境中的 globalslocals 来执行该表达式。 注意,eval() 无法访问闭包环境中的 嵌套作用域 (非局部变量)。

返回值就是表达式的求值结果。 语法错误将作为异常被报告。 例如:

>>> x =1
>>>eval('x+1')
2

该函数还可用于执行任意代码对象(比如由 compile() 创建的对象)。 这时传入的是代码对象,而非一个字符串了。如果代码对象已用参数为 mode'exec' 进行了编译,那么 eval() 的返回值将为 None

提示: exec() 函数支持语句的动态执行。 globals()locals() 函数分别返回当前的全局和本地字典,可供传给 eval()exec() 使用。

如果给出的源数据是个字符串,那么其前后的空格和制表符将被剔除。

引发一个 审计事件exec 附带参数 code_object

  • exec(object[, globals[, locals]])

这个函数支持动态执行 Python 代码。 object 必须是字符串或者代码对象。 如果是字符串,那么该字符串将被解析为一系列 Python 语句并执行(除非发生语法错误)。 如果是代码对象,它将被直接执行。 在任何情况下,被执行的代码都应当是有效的文件输入(见参考手册中的“文件输入”一节)。 请注意即使在传递给 exec() 函数的代码的上下文中,nonlocal, yieldreturn 语句也不能在函数定义以外使用。 该函数的返回值是 None

无论在什么情况下,如果省略了可选部分,代码将运行于当前作用域中。如果只提供了 globals*,则必须为字典对象(而不能是字典的子类),同时用于存放全局变量和局部变量。如果提供了 *globalslocals,则将分别用于全局变量和局部变量。locals 可以是任意字典映射对象。请记住,在模块级别,globals 和 locals 是同一个字典。如果 exec 获得两个独立的对象作为 globalslocals,代码执行起来就像嵌入到某个类定义中一样。

如果 globals 字典不包含 __builtins__ 键值,则将为该键插入对内建 builtins 模块字典的引用。因此,在将执行的代码传递给 exec() 之前,可以通过将自己的 __builtins__ 字典插入到 globals 中来控制可以使用哪些内置代码。

引发一个 审计事件exec 附带参数 code_object

注解

内置 globals()locals() 函数各自返回当前的全局和本地字典,因此可以将它们传递给 exec() 的第二个和第三个实参。

注解

默认情况下,locals 的行为如下面 locals() 函数描述的一样:不要试图改变默认的 locals 字典。如果您想在 exec() 函数返回时知道代码对 locals 的变动,请明确地传递 locals 字典。

  • filter(function, iterable)

iterable 中函数 function 返回真的那些元素,构建一个新的迭代器。iterable 可以是一个序列,一个支持迭代的容器,或一个迭代器。如果 functionNone ,则会假设它是一个身份函数,即 iterable 中所有返回假的元素会被移除。

请注意, filter(function, iterable) 相当于一个生成器表达式,当 function 不是 None 的时候为 (item for item in iterable if function(item));function 是 None 的时候为 (item for item in iterable if item)

请参阅 itertools.filterfalse() 了解,只有 function 返回 false 时才选取 iterable 中元素的补充函数。

  • class float([x])

返回从数字或字符串 x 生成的浮点数。

如果参数是个字符串,则应包含一个十进制数字,前面可选带上符号,也可选前后带有空白符。符号可以是‘+’'-''+' 符号对值没有影响。参数也可以是一个代表 NaN(非数字)或正负无穷大的字符串。更确切地说,在去除前导和尾部的空白符后,输入参数必须符合以下语法:

sign          ::="+"|"-"
infinity      ::="Infinity"|"inf"
nan           ::="nan"
numeric_value ::=floatnumber|infinity|nan
numeric_string::=[sign]numeric_value

这里的 floatnumber 是指 Python 的浮点数格式,在 浮点数字面值 中有介绍。大小写没有关系,所以“inf”、“Inf”、“INFINITY”、“iNfINity”都可接受为正无穷的拼写形式。

另一方面,如果实参是整数或浮点数,则返回具有相同值(在 Python 浮点精度范围内)的浮点数。如果实参在 Python 浮点精度范围外,则会触发 OverflowError

对于一个普通 Python 对象 xfloat(x) 会委托给 x.__float__()。 如果 __float__() 未定义则将回退至 __index__()

如果没有实参,则返回 0.0

示例:

>>>float('+1.23')
1.23
>>>float('   -12345\n')
-12345.0
>>>float('1e-003')
0.001
>>>float('+1E6')
1000000.0
>>>float('-Infinity')
-inf

在 3.6 版更改: 您可以使用下划线将代码文字中的数字进行分组。

在 3.7 版更改: x 现在只能作为位置参数。

在 3.8 版更改: 如果 __float__() 未定义则回退至 __index__()

  • format(value[, format_spec])

value 转换为“格式化后”的形式,格式由 format_spec 进行控制。format_spec 的解释方式取决于 value 参数的类型;但大多数内置类型使用一种标准的格式化语法: 格式规格迷你语言。

默认的 format_spec 是一个空字符串,它通常给出与调用 str(value) 相同的结果。

调用 format(value, format_spec) 会转换成 type(value).__format__(value, format_spec) ,所以实例字典中的 __format__() 方法将不会调用。如果方法搜索回退到 object 类但 format_spec 不为空,或者如果 format_spec 或返回值不是字符串,则会触发 TypeError 异常。

在 3.4 版更改: 当 format_spec 不是空字符串时, object().__format__(format_spec) 会触发 TypeError

  • class frozenset([iterable])

返回一个新的 frozenset 对象,它包含可选参数 iterable 中的元素。 frozenset 是一个内置的类。

  • getattr(object, name[, default])

返回对象命名属性的值。name 必须是字符串。如果该字符串是对象的属性之一,则返回该属性的值。例如, getattr(x, 'foobar') 等同于 x.foobar。如果指定的属性不存在,且提供了 default 值,则返回它,否则触发 AttributeError

注解

由于 私有名称混合 发生在编译时,因此必须 手动混合私有属性(以两个下划线打头的属性)名称以使使用 getattr() 来提取它。

  • globals()

返回表示当前全局符号表的字典。这总是当前模块的字典(在函数或方法中,不是调用它的模块,而是定义它的模块)。

  • hasattr(object, name)

该实参是一个对象和一个字符串。如果字符串是对象的属性之一的名称,则返回 True,否则返回 False。(此功能是通过调用 getattr(object, name) 看是否有 AttributeError 异常来实现的。)

  • hash(object)

返回该对象的哈希值(如果它有的话)。哈希值是整数。它们在字典查找元素时用来快速比较字典的键。相同大小的数字变量有相同的哈希值(即使它们类型不同,如 1 和 1.0)。

注解

如果对象实现了自己的 __hash__() 方法,请注意,hash() 根据机器的字长来截断返回值。

  • help([object])

启动内置的帮助系统(此函数主要在交互式中使用)。如果没有实参,解释器控制台里会启动交互式帮助系统。如果实参是一个字符串,则在模块、函数、类、方法、关键字或文档主题中搜索该字符串,并在控制台上打印帮助信息。如果实参是其他任意对象,则会生成该对象的帮助页。

请注意,如果在调用 help() 时,目标函数的形参列表中存在斜杠(/),则意味着斜杠之前的参数只能是位置参数。

该函数通过 site 模块加入到内置命名空间。

在 3.4 版更改: pydocinspect 的变更使得可调用对象的签名信息更加全面和一致。

  • hex(x)

将整数转换为以“0x”为前缀的小写十六进制字符串。如果 x 不是 Python int 对象,则必须定义返回整数的 __index__() 方法。一些例子:

>>> hex(255)
'0xff'
>>> hex(-42)
'-0x2a'

如果要将整数转换为大写或小写的十六进制字符串,并可选择有无“0x”前缀,则可以使用如下方法:

>>>'%#x'%255,'%x'%255,'%X'%255
('0xff','ff','FF')
>>> format(255,'#x'), format(255,'x'), format(255,'X')
('0xff','ff','FF')
>>> f'{255:#x}', f'{255:x}', f'{255:X}'
('0xff','ff','FF')

注解

如果要获取浮点数的十六进制字符串形式,请使用 float.hex() 方法。

  • id(object)

返回对象的“标识值”。该值是一个整数,在此对象的生命周期中保证是唯一且恒定的。两个生命期不重叠的对象可能具有相同的 id() 值。

CPython implementation detail: This is the address of the object in memory.

引发一个 审计事件builtins.id,附带参数 id

  • input([prompt])

如果存在 prompt 实参,则将其写入标准输出,末尾不带换行符。接下来,该函数从输入中读取一行,将其转换为字符串(除了末尾的换行符)并返回。当读取到 EOF 时,则触发 EOFError。例如:

>>> s = input('--> ')
-->MontyPython's Flying Circus
>>> s  
"Monty Python's FlyingCircus"

如果加载了 readline 模块,input() 将使用它来提供复杂的行编辑和历史记录功能。

引发一个 审计事件builtins.input 附带参数 prompt

在成功读取输入之后引发一个审计事件 builtins.input/result 附带结果。

  • class int([x])

  • class int(x, base=10)

返回一个基于数字或字符串 x 构造的整数对象,或者在未给出参数时返回 0。 如果 x 定义了 __int__()int(x) 将返回 x.__int__()。 如果 x 定义了 __index__(),它将返回 x.__index__()。 如果 x 定义了 __trunc__(),它将返回 x.__trunc__()。 对于浮点数,它将向零舍入。

如果 x 不是数字,或者有 base 参数,x 必须是字符串、bytes、表示进制为 base 的 整数字面值 的 bytearray 实例。该文字前可以有 +- (中间不能有空格),前后可以有空格。一个进制为 n 的数字包含 0 到 n-1 的数,其中 az (或 AZ )表示 10 到 35。默认的 base 为 10 ,允许的进制有 0、2-36。2、8、16 进制的数字可以在代码中用 0b/0B0o/0O0x/0X 前缀来表示。进制为 0 将安照代码的字面量来精确解释,最后的结果会是 2、8、10、16 进制中的一个。所以 int('010', 0) 是非法的,但 int('010')int('010', 8) 是合法的。

在 3.4 版更改: 如果 base 不是 int 的实例,但 base 对象有 base.__index__ 方法,则会调用该方法来获取进制数。以前的版本使用 base.__int__ 而不是 base.__index__

在 3.6 版更改: 您可以使用下划线将代码文字中的数字进行分组。

在 3.7 版更改: x 现在只能作为位置参数。

在 3.8 版更改: 如果 __int__() 未定义则回退至 __index__()

  • isinstance(object, classinfo)

如果 object 参数是 classinfo 参数的实例,或其(直接、间接或 virtual )子类的实例,则返回 True。 如果 object 不是给定类型的对象,则总是返回 False。如果 classinfo 是类型对象的元组(或由该类元组递归生成)或多个类型的 Union Type,那么当 object 是其中任一类型的实例时就会返回 True。如果 classinfo 不是某个类型或类型元组,将会触发 TypeError 异常。

在 3.10 版更改: classinfo 可以是一个 Union Type。

  • issubclass(class, classinfo)

Return True if class is a subclass (direct, indirect, or virtual) of classinfo. A class is considered a subclass of itself. classinfo may be a tuple of class objects or a Union Type, in which case return True if class is a subclass of any entry in classinfo. In any other case, a TypeError exception is raised.

在 3.10 版更改: classinfo 可以是一个 Union Type。

  • iter(object[, sentinel])

返回一个 iterator 对象。根据是否存在第二个实参,第一个实参的解释是非常不同的。如果没有第二个实参,object 必须是支持迭代协议(有 __iter__() 方法)的集合对象,或必须支持序列协议(有 __getitem__() 方法,且数字参数从 0 开始)。如果它不支持这些协议,会触发 TypeError。如果有第二个实参 sentinel*,那么 *object 必须是可调用的对象。这种情况下生成的迭代器,每次迭代调用它的 __next__() 方法时都会不带实参地调用 object*;如果返回的结果是 *sentinel 则触发 StopIteration,否则返回调用结果。

适合 iter() 的第二种形式的应用之一是构建块读取器。 例如,从二进制数据库文件中读取固定宽度的块,直至到达文件的末尾:

from functools importpartial
with open('mydata.db','rb')as f:
for block in iter(partial(f.read,64), b''):
        process_block(block)
  • len(s)

返回对象的长度(元素个数)。实参可以是序列(如 string、bytes、tuple、list 或 range 等)或集合(如 dictionary、set 或 frozen set 等)。

CPython implementation detail:len 对于大于 sys.maxsize 的长度如 range(2 ** 100) 会引发 OverflowError

  • classlist([iterable])

虽然被称为函数,list 实际上是一种可变序列类型。

  • locals()

更新并返回表示当前本地符号表的字典。 在函数代码块但不是类代码块中调用 locals() 时将返回自由变量。 请注意在模块层级上,locals()globals() 是同一个字典。

注解

不要更改此字典的内容;更改不会影响解释器使用的局部变量或自由变量的值。

  • map(function, iterable, )

返回一个将 function 应用于 iterable 中每一项并输出其结果的迭代器。 如果传入了额外的 iterable 参数,function 必须接受相同个数的实参并被应用于从所有可迭代对象中并行获取的项。 当有多个可迭代对象时,最短的可迭代对象耗尽则整个迭代就将结束。 对于函数的输入已经是参数元组的情况。

  • max(iterable, **[, key, default*])

  • max(arg1, arg2, \args[, key*])

返回可迭代对象中最大的元素,或者返回两个及以上实参中最大的。

如果只提供了一个位置参数,它必须是非空 iterable,返回可迭代对象中最大的元素;如果提供了两个及以上的位置参数,则返回最大的位置参数。

有两个可选只能用关键字的实参。key 实参指定排序函数用的参数,如传给 list.sort() 的。default 实参是当可迭代对象为空时返回的值。如果可迭代对象为空,并且没有给 default ,则会触发 ValueError

如果有多个最大元素,则此函数将返回第一个找到的。这和其他稳定排序工具如 sorted(iterable, key=keyfunc, reverse=True)[0]heapq.nlargest(1, iterable, key=keyfunc) 保持一致。

3.4 新版功能: keyword-only 实参 default

在 3.8 版更改: key 可以为 None

  • class memoryview(object)

返回由给定实参创建的“内存视图”对象。

  • min(iterable, **[, key, default*])

  • min(arg1, arg2, \args[, key*])

返回可迭代对象中最小的元素,或者返回两个及以上实参中最小的。

如果只提供了一个位置参数,它必须是 iterable,返回可迭代对象中最小的元素;如果提供了两个及以上的位置参数,则返回最小的位置参数。

有两个可选只能用关键字的实参。key 实参指定排序函数用的参数,如传给 list.sort() 的。default 实参是当可迭代对象为空时返回的值。如果可迭代对象为空,并且没有给 default ,则会触发 ValueError

如果有多个最小元素,则此函数将返回第一个找到的。这和其他稳定排序工具如 sorted(iterable, key=keyfunc)[0]heapq.nsmallest(1, iterable, key=keyfunc) 保持一致。

3.4 新版功能: keyword-only 实参 default

在 3.8 版更改: key 可以为 None

  • next(iterator[, default])

通过调用 iterator__next__() 方法获取下一个元素。如果迭代器耗尽,则返回给定的 default,如果没有默认值则触发 StopIteration

  • classobject

返回一个不带特征的新对象。object 是所有类的基类。它带有所有 Python 类实例均通用的方法。本函数不接受任何参数。

注解

由于 object 没有 __dict__,因此无法将任意属性赋给 object 的实例。

  • oct(x)

将一个整数转变为一个前缀为“0o”的八进制字符串。结果是一个合法的 Python 表达式。如果 x 不是 Python 的 int 对象,那它需要定义 __index__() 方法返回一个整数。一些例子:

>>> oct(8)
'0o10'
>>> oct(-56)
'-0o70'

若要将整数转换为八进制字符串,并可选择是否带有“0o”前缀,可采用如下方法:

>>>'%#o'%10,'%o'%10
('0o12','12')
>>> format(10,'#o'), format(10,'o')
('0o12','12')
>>> f'{10:#o}', f'{10:o}'
('0o12','12')
  • open(file, mode=’r’, buffering=- 1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

打开 file 并返回对应的 file object。 如果该文件不能被打开,则引发 OSError

file 是一个 path-like object,表示将要打开的文件的路径(绝对路径或者相对当前工作目录的路径),也可以是要封装文件对应的整数类型文件描述符。(如果给出的是文件描述符,则当返回的 I/O 对象关闭时它也会关闭,除非将 closefd 设为 False 。)

mode 是可选的字符串,用于指定打开文件的模式。默认值是 'r' ,表示以文本模式打开并读取文件。其他常见模式有:写入模式 'w' (已存在文件会被清空)、独占创建模式 'x' 、追加写入模式 'a' (在 某些 Unix 系统中,无论当前文件指针在什么位置,所有 的写入操作都会追加到文件末尾)。在文本模式,如果未指定 encoding ,则会根据当前平台决定编码格式:调用 locale.getpreferredencoding(False) 获取当前地区的编码。若要读写原生字节格式,请使用二进制模式且不要指定 encoding。可用的模式有:

字符 含意
‘r’ 读取(默认)
‘w’ 写入,并先截断文件
‘x’ 排它性创建,如果文件已存在则失败
‘a’ 打开文件用于写入,如果文件存在则在末尾追加
‘b’ 二进制模式
‘t’ 文本模式(默认)
‘+’ 打开用于更新(读取与写入)

默认模式为 'r' (打开文件用于读取文本,与 'rt' 同义)。'w+''w+b' 模式将打开文件并清空内容。而 'r+''r+b' 模式将打开文件但不清空内容。

正如在 概述 中提到的,Python区分二进制和文本I/O。以二进制模式打开的文件(包括 mode 参数中的 'b' )返回的内容为 bytes 对象,不进行任何解码。在文本模式下(默认情况下,或者在 mode 参数中包含 't' )时,文件内容返回为 str ,首先使用指定的 encoding (如果给定)或者使用平台默认的的字节编码解码。

另外还有一种模式字符 'U' 可用,不过它已失效,并视作弃用。以前它会在文本模式中启用 universal newlines,这在 Python 3.0 已成为默认行为。详情请参阅 newline 形参的文档。

注解

Python不依赖于底层操作系统的文本文件概念;所有处理都由Python本身完成,因此与平台无关。

buffering 是一个可选的整数,用于设置缓冲策略。传递0以切换缓冲关闭(仅允许在二进制模式下),1选择行缓冲(仅在文本模式下可用),并且>1的整数以指示固定大小的块缓冲区的大小(以字节为单位)。如果没有给出 buffering 参数,则默认缓冲策略的工作方式如下:

  • 二进制文件以固定大小的块进行缓冲;使用启发式方法选择缓冲区的大小,尝试确定底层设备的“块大小”或使用 io.DEFAULT_BUFFER_SIZE。在许多系统上,缓冲区的长度通常为4096或8192字节。
  • “交互式”文本文件( isatty() 返回 True 的文件)使用行缓冲。其他文本文件使用上述策略用于二进制文件。

encoding 是用于解码或编码文件的编码的名称。这应该只在文本模式下使用。默认编码是依赖于平台的(不 管 locale.getpreferredencoding() 返回何值),但可以使用任何Python支持的 text encoding 。有关支持的编码列表,请参阅 codecs 模块。

errors 是一个可选的字符串参数,用于指定如何处理编码和解码错误 - 这不能在二进制模式下使用。可以使用各种标准错误处理程序,但是使用 codecs.register_error() 注册的任何错误处理名称也是有效的。标准名称包括:

  • 如果存在编码错误,'strict' 会引发 ValueError 异常。 默认值 None 具有相同的效果。
  • 'ignore' 忽略错误。请注意,忽略编码错误可能会导致数据丢失。
  • 'replace' 会将替换标记(例如 '?' )插入有错误数据的地方。
  • 'surrogateescape' 将把任何不正确的字节表示为 U+DC80 至 U+DCFF 范围内的下方替代码位。 当在写入数据时使用 surrogateescape 错误处理句柄时这些替代码位会被转回到相同的字节。 这适用于处理具有未知编码格式的文件。
  • 只有在写入文件时才支持 'xmlcharrefreplace'。编码不支持的字符将替换为相应的XML字符引用 &#nnn;
  • 'backslashreplace' 用Python的反向转义序列替换格式错误的数据。
  • 'namereplace' (也只在编写时支持)用 \N{...} 转义序列替换不支持的字符。

newline 控制 universal newlines 模式如何生效(它仅适用于文本模式)。它可以是 None'''\n''\r''\r\n'。它的工作原理:

  • 从流中读取输入时,如果 newlineNone,则启用通用换行模式。输入中的行可以以 '\n''\r''\r\n' 结尾,这些行被翻译成 '\n' 在返回呼叫者之前。如果它是 '',则启用通用换行模式,但行结尾将返回给调用者未翻译。如果它具有任何其他合法值,则输入行仅由给定字符串终止,并且行结尾将返回给未调用的调用者。
  • 将输出写入流时,如果 newlineNone,则写入的任何 '\n' 字符都将转换为系统默认行分隔符 os.linesep。如果 newline'''\n',则不进行翻译。如果 newline 是任何其他合法值,则写入的任何 '\n' 字符将被转换为给定的字符串。

如果 closefdFalse 且给出的不是文件名而是文件描述符,那么当文件关闭时,底层文件描述符将保持打开状态。如果给出的是文件名,则 closefd 必须为 True (默认值),否则将触发错误。

可以通过传递可调用的 opener 来使用自定义开启器。然后通过使用参数( fileflags )调用 opener 获得文件对象的基础文件描述符。 opener 必须返回一个打开的文件描述符(使用 os.open as opener 时与传递 None 的效果相同)。

新创建的文件是 不可继承的。

下面的示例使用 os.open() 函数的 dir_fd 的形参,从给定的目录中用相对路径打开文件:

>>>import os
>>> dir_fd = os.open('somedir', os.O_RDONLY)
>>>def opener(path, flags):
...return os.open(path, flags, dir_fd=dir_fd)
...
>>>with open('spamspam.txt','w', opener=opener)as f:
...print('This will be written to somedir/spamspam.txt', file=f)
...
>>> os.close(dir_fd)# don't leak a file descriptor

open() 函数所返回的 file object 类型取决于所用模式。 当使用 open() 以文本模式 ('w', 'r', 'wt', 'rt' 等) 打开文件时,它将返回 io.TextIOBase (特别是 io.TextIOWrapper) 的一个子类。 当使用缓冲以二进制模式打开文件时,返回的类是 io.BufferedIOBase 的一个子类。 具体的类会有多种:在只读的二进制模式下,它将返回 io.BufferedReader;在写入二进制和追加二进制模式下,它将返回 io.BufferedWriter,而在读/写模式下,它将返回 io.BufferedRandom。 当禁用缓冲时,则会返回原始流,即 io.RawIOBase 的一个子类 io.FileIO

引发一个 审计事件open 附带参数 file, mode, flags

modeflags 参数可以在原始调用的基础上被修改或传递。

在 3.3 版更改:

  • 增加了 opener 形参。
  • 增加了 'x' 模式。
  • 过去触发的 IOError,现在是 OSError 的别名。
  • 如果文件已存在但使用了排它性创建模式( 'x' ),现在会触发 FileExistsError

在 3.4 版更改:

  • 文件现在禁止继承。

Deprecated since version 3.4, removed in version 3.10: 'U' 模式。

在 3.5 版更改:

  • 如果系统调用被中断,但信号处理程序没有触发异常,此函数现在会重试系统调用,而不是触发 InterruptedError 异常 (原因详见 PEP 475)。
  • 增加了 'namereplace' 错误处理接口。

在 3.6 版更改:

  • 增加对实现了 os.PathLike 对象的支持。
  • 在 Windows 上,打开一个控制台缓冲区将返回 io.RawIOBase 的子类,而不是 io.FileIO
  • ord(c)

对表示单个 Unicode 字符的字符串,返回代表它 Unicode 码点的整数。例如 ord('a') 返回整数 97ord('€') (欧元符号)返回 8364 。这是 chr() 的逆函数。

  • pow(base, exp[, mod])

返回 baseexp 次幂;如果 mod 存在,则返回 baseexp 次幂对 mod 取余(比 pow(base, exp) % mod 更高效)。 两参数形式 pow(base, exp) 等价于乘方运算符: base**exp

The arguments must have numeric types. With mixed operand types, the coercion rules for binary arithmetic operators apply. For int operands, the result has the same type as the operands (after coercion) unless the second argument is negative; in that case, all arguments are converted to float and a float result is delivered. For example, pow(10, 2) returns 100, but pow(10, -2) returns 0.01.

对于 int 操作数 baseexp,如果给出 *mod,则 *mod 必须为整数类型并且 mod 必须不为零。 如果给出 mod 并且 exp 为负值,则 base 必须相对于 mod 不可整除。 在这种情况下,将会返回 pow(inv_base, -exp, mod),其中 inv_basebase 的倒数对 mod 取余。

下面的例子是 38 的倒数对 97 取余:

>>> pow(38,-1, mod=97)
23
>>>23*38%97==1
True

在 3.8 版更改: 对于 int 操作数,三参数形式的 pow 现在允许第二个参数为负值,即可以计算倒数的余数。

在 3.8 版更改: 允许关键字参数。 之前只支持位置参数。

  • print(\objects, sep=’ ‘, end=’\n’, file=sys.stdout, flush=False*)

objects 打印输出至 file 指定的文本流,以 sep 分隔并在末尾加上 end*。 *sependfileflush 必须以关键字参数的形式给出。

所有非关键字参数都会被转换为字符串,就像是执行了 str() 一样,并会被写入到流,以 sep 且在末尾加上 end*。 *sepend 都必须为字符串;它们也可以为 None,这意味着使用默认值。 如果没有给出 objects,则 print() 将只写入 end

file 参数必须是一个具有 write(string) 方法的对象;如果参数不存在或为 None,则将使用 sys.stdout。 由于要打印的参数会被转换为文本字符串,因此 print() 不能用于二进制模式的文件对象。 对于这些对象,应改用 file.write(...)

输出是否缓存通常取决于 file*,但如果 *flush 关键字参数为 True,输出流会被强制刷新。

在 3.3 版更改: 增加了 flush 关键字参数。

  • class property(fget=None, fset=None, fdel=None, doc=None)

返回 property 属性。

fget 是获取属性值的函数。 fset 是用于设置属性值的函数。 fdel 是用于删除属性值的函数。并且 doc 为属性对象创建文档字符串。

一个典型的用法是定义一个托管属性 x:

class C:
def __init__(self):
    self._x =None
def getx(self):
    return self._x
def setx(self, value):
    self._x = value
def delx(self):
    delself._x
    x =property(getx, setx, delx,"I'm the 'x' property.")

如果 cC 的实例,c.x 将调用 getter,c.x = value 将调用 setter, del c.x 将调用 deleter。

如果给出,doc 将成为该 property 属性的文档字符串。 否则该 property 将拷贝 fget 的文档字符串(如果存在)。 这令使用 property() 作为 decorator 来创建只读的特征属性可以很容易地实现:

class Parrot:
def __init__(self):
    self._voltage =100000
@property
def voltage(self):
    """Get the current voltage."""
    return self._voltage

以上 @property 装饰器会将 voltage() 方法转化为一个具有相同名称的只读属性的 “getter”,并将 voltage 的文档字符串设置为 “Get the current voltage.”

特征属性对象具有 getter, setter 以及 deleter 方法,它们可用作装饰器来创建该特征属性的副本,并将相应的访问函数设为所装饰的函数。 这最好是用一个例子来解释:

class C:
def __init__(self):
    self._x =None
@property
def x(self):
    """I'm the 'x' property."""
    return self._x
@x.setter
def x(self, value):
    self._x = value
@x.deleter
def x(self):
    delself._x

上述代码与第一个例子完全等价。 注意一定要给附加函数与原始的特征属性相同的名称 (在本例中为 x。)

返回的特征属性对象同样具有与构造器参数相对应的属性 fget, fsetfdel

在 3.5 版更改: 特征属性对象的文档字符串现在是可写的。

  • classrange(stop)

  • classrange(start, stop[, step])

虽然被称为函数,但 range 实际上是一个不可变的序列类型。

  • repr(object)

返回对象的可打印形式字符串。对于很多类型而言,本函数试图返回的字符串,会与将对象传给 eval() 所生成的结果相同;不然,结果就是一个尖括号包裹的字符串,包含了对象类型名称及其附加信息,附加信息通常包括对象的名称和内存地址。通过定义 __repr__() 方法,类可以控制本函数将为实例返回的内容。

  • reversed(seq)

返回一个反向的 iterator。 seq 必须是一个具有 __reversed__() 方法的对象或者是支持该序列协议(具有从 0 开始的整数类型参数的 __len__() 方法和 __getitem__() 方法)。

  • round(number[, ndigits])

返回 number 舍入到小数点后 ndigits 位精度的值。 如果 ndigits 被省略或为 None,则返回最接近输入值的整数。

对于支持 round() 方法的内置类型,结果值会舍入至最接近的 10 的负 ndigits 次幂的倍数;如果与两个倍数同样接近,则选用偶数。因此,round(0.5)round(-0.5) 均得出 0round(1.5) 则为 2ndigits 可为任意整数值(正数、零或负数)。如果省略了 ndigits 或为 None ,则返回值将为整数。否则返回值与 number 的类型相同。

对于一般的 Python 对象 number, round 将委托给 number.__round__

注解

对浮点数执行 round() 的行为可能会令人惊讶:例如,round(2.675, 2) 将给出 2.67 而不是期望的 2.68。 这不算是程序错误:这一结果是由于大多数十进制小数实际上都不能以浮点数精确地表示。

  • classset([iterable])

返回一个新的 set 对象,可以选择带有从 iterable 获取的元素。 set 是一个内置类型。

  • setattr(object, name, value)

本函数与 getattr() 相对应。其参数为一个对象、一个字符串和一个任意值。字符串可以为某现有属性的名称,或为新属性。只要对象允许,函数会将值赋给属性。如 setattr(x, 'foobar', 123) 等价于 x.foobar = 123

注解

由于 私有名称混合 发生在编译时,因此必须手动混合私有属性(以两个下划线打头的属性)名称以便使用 setattr() 来设置它。

  • classslice(stop)

  • classslice(start, stop[, step])

返回一个 slice 对象,代表由 range(start, stop, step) 指定索引集的切片。 其中参数 startstep 的默认值为 None。切片对象具有只读数据属性 startstopstep,只是返回对应的参数值(或默认值)。这几个属性没有其他明确的功能;不过 NumPy 和其他第三方扩展会用到。在使用扩展索引语法时,也会生成切片对象。例如: a[start:stop:step]a[start:stop, i]。 另一种方案是返回迭代器对象。

  • sorted(iterable, **, key=None, reverse=False*)

根据 iterable 中的项返回一个新的已排序列表。

具有两个可选参数,它们都必须指定为关键字参数。

key 指定带有单个参数的函数,用于从 iterable 的每个元素中提取用于比较的键 (例如 key=str.lower)。 默认值为 None (直接比较元素)。

reverse 为一个布尔值。 如果设为 True,则每个列表元素将按反向顺序比较进行排序。

使用 functools.cmp_to_key() 可将老式的 cmp 函数转换为 key 函数。

内置的 sorted() 确保是稳定的。 如果一个排序确保不会改变比较结果相等的元素的相对顺序就称其为稳定的 —- 这有利于进行多重排序(例如先按部门、再按薪级排序)。

The sort algorithm uses only < comparisons between items. While defining an __lt__() method will suffice for sorting, PEP 8 recommends that all six rich comparisons be implemented. This will help avoid bugs when using the same data with other ordering tools such as max() that rely on a different underlying method. Implementing all six comparisons also helps avoid confusion for mixed type comparisons which can call reflected the __gt__() method.

  • @staticmethod

将方法转换为静态方法。

静态方法不会接收隐式的第一个参数。要声明一个静态方法,请使用此语法

class C:
@staticmethod
def f(arg1, arg2,...):...

@staticmethod 这样的形式称为函数的 decorator 。

静态方法既可以由类中调用(如 C.f()),也可以由实例中调用(如```C().f())。此外,还可以作为普通的函数进行调用(如f()``)。

Python 的静态方法与 Java 或 C++ 类似。,可用于创建另一种类构造函数。

像所有装饰器一样,也可以像常规函数一样调用 staticmethod ,并对其结果执行某些操作。比如某些情况下需要从类主体引用函数并且您希望避免自动转换为实例方法。对于这些情况,请使用此语法:

def regular_function():
...
class C:
    method = staticmethod(regular_function)

在 3.10 版更改: 静态方法继承了方法的多个属性(__module____name____qualname____doc____annotations__),还拥有一个新的__wrapped__ 属性,并且现在还可以作为普通函数进行调用。

  • classstr(object=’’)

  • classstr(object=b’’, encoding=’utf-8’, errors=’strict’)

返回一个 str 版本的 object

str 是内置字符串 class 。

  • sum(iterable, /, start=0)

start 开始自左向右对 iterable 的项求和并返回总计值。 iterable 的项通常为数字,而 start 值则不允许为字符串。

对某些用例来说,存在 sum() 的更好替代。 拼接字符串序列的更好更快方式是调用 ''.join(sequence)

在 3.8 版更改: start 形参可用关键字参数形式来指定。

  • classsuper([type[, object-or-type]])

返回一个代理对象,它会将方法调用委托给 type 的父类或兄弟类。 这对于访问已在类中被重载的继承方法很有用。

object-or-type 确定用于搜索的 method resolution order。 搜索会从 type 之后的类开始。

举例来说,如果 object-or-type__mro__D -> B -> C -> A -> object 并且 type 的值为 B,则 super() 将会搜索 C -> A -> object

object-or-type__mro__ 属性列出了 getattr()super() 所共同使用的方法解析搜索顺序。 该属性是动态的,可以在任何继承层级结构发生更新的时候被改变。

如果省略第二个参数,则返回的超类对象是未绑定的。 如果第二个参数为一个对象,则 isinstance(obj, type) 必须为真值。 如果第二个参数为一个类型,则 issubclass(type2, type) 必须为真值(这适用于类方法)。

super 有两个典型用例。 在具有单继承的类层级结构中,super 可用来引用父类而不必显式地指定它们的名称,从而令代码更易维护。 这种用法与其他编程语言中 super 的用法非常相似。

第二个用例是在动态执行环境中支持协作多重继承。 此用例为 Python 所独有而不存在于静态编码语言或仅支持单继承的语言当中。 这使用实现“菱形图”成为可能,即有多个基类实现相同的方法。 好的设计强制要求这样的方法在每个情况下都具有相同的调用签名(因为调用顺序是在运行时确定的,也因为这个顺序要适应类层级结构的更改,还因为这个顺序可能包括在运行时之前未知的兄弟类)。

对于以上两个用例,典型的超类调用看起来是这样的:

class C(B):
def method(self, arg):
super().method(arg)# This does the same thing as:
# super(C, self).method(arg)

除了方法查找之外,super() 也可用于属性查找。 一个可能的应用场合是在上级或同级类中调用 描述器。

请注意 super() 是作为显式加点属性查找的绑定过程的一部分来实现的,例如 super().__getitem__(name)。 它做到这一点是通过实现自己的 __getattribute__() 方法,这样就能以可预测的顺序搜索类,并且支持协作多重继承。 对应地,super() 在像 super()[name] 这样使用语句或操作符进行隐式查找时则未被定义。

还要注意的是,除了零个参数的形式以外,super() 并不限于在方法内部使用。 两个参数的形式明确指定参数并进行相应的引用。 零个参数的形式仅适用于类定义内部,因为编译器需要填入必要的细节以正确地检索到被定义的类,还需要让普通方法访问当前实例。

对于有关如何使用 super() 来如何设计协作类的实用建议。

  • classtuple([iterable])

虽然被称为函数,但 tuple 实际上是一个不可变的序列类型

  • classtype(object)

  • classtype(name, bases, dict, **kwds)

传入一个参数时,返回 object 的类型。 返回值是一个 type 对象,通常与 object.__class__ 所返回的对象相同。

推荐使用 isinstance() 内置函数来检测对象的类型,因为它会考虑子类的情况。

传入三个参数时,返回一个新的 type 对象。 这在本质上是 class 语句的一种动态形式,name 字符串即类名并会成为 __name__ 属性;bases 元组包含基类并会成为 __bases__ 属性;如果为空则会添加所有类的终极基类 objectdict 字典包含类主体的属性和方法定义;它在成为 __dict__ 属性之前可能会被拷贝或包装。 下面两条语句会创建相同的 type 对象:

>>>class X:
...     a =1
...
>>> X = type('X',(), dict(a=1))

提供给三参数形式的关键字参数会被传递给适当的元类机制 (通常为 __init_subclass__()),相当于类定义中关键字 (除了 metaclass) 的行为方式。

在 3.6 版更改: type 的子类如果未重载 type.__new__,将不再能使用一个参数的形式来获取对象的类型。

  • vars([object])

返回模块、类、实例或任何其它具有 __dict__ 属性的对象的 __dict__ 属性。

模块和实例这样的对象具有可更新的 __dict__ 属性;但是,其它对象的 __dict__ 属性可能会设为限制写入(例如,类会使用 types.MappingProxyType 来防止直接更新字典)。

不带参数时,vars() 的行为类似 locals()。 请注意,locals 字典仅对于读取起作用,因为对 locals 字典的更新会被忽略。

如果指定了一个对象但它没有 __dict__ 属性(例如,当它所属的类定义了 __slots__ 属性时)则会引发 TypeError 异常。

  • zip(\iterables, strict=False*)

在多个迭代器上并行迭代,从每个迭代器返回一个数据项组成元组。

示例:

>>>for item in zip([1,2,3],['sugar','spice','everything nice']):
...print(item)
...
(1,'sugar')
(2,'spice')
(3,'everything nice')

更正式的说法: zip() 返回元组的迭代器,其中第 i 个元组包含的是每个参数迭代器的第 i 个元素。

不妨换一种方式认识 zip() :它会把行变成列,把列变成行。这类似于 矩阵转置 。

zip() 是延迟执行的:直至迭代时才会对元素进行处理,比如 for 循环或放入 list 中。

值得考虑的是,传给 zip() 的可迭代对象可能长度不同;有时是有意为之,有时是因为准备这些对象的代码存在错误。Python 提供了三种不同的处理方案:

  • 默认情况下,zip() 在最短的迭代完成后停止。较长可迭代对象中的剩余项将被忽略,结果会裁切至最短可迭代对象的长度:

    >>> list(zip(range(3),['fee','fi','fo','fum']))
    [(0,'fee'),(1,'fi'),(2,'fo')]
  • 通常 zip() 用于可迭代对象等长的情况下。这时建议用 strict=True 的选项。输出与普通的 zip() 相同:。

    >>> list(zip(('a','b','c'),(1,2,3), strict=True))
    [('a',1),('b',2),('c',3)]

    与默认行为不同的是,它会检查可迭代对象的长度是否相同,如果不相同则触发 ValueError

    >>> list(zip(range(3),['fee','fi','fo','fum'], strict=True))
    Traceback(most recent call last):
    ...
    ValueError: zip() argument 2is longer than argument 1

    如果未指定 strict=True 参数,所有导致可迭代对象长度不同的错误都会被抑制,这可能会在程序的其他地方表现为难以发现的错误。

  • 为了让所有的可迭代对象具有相同的长度,长度较短的可用常量进行填充。这可由 itertools.zip_longest() 来完成。

极端例子是只有一个可迭代对象参数,zip() 会返回一个一元组的迭代器。如果未给出参数,则返回一个空的迭代器。

小技巧:

  • 可确保迭代器的求值顺序是从左到右的。这样就能用 zip(*[iter(s)]*n, strict=True) 将数据列表按长度 n 进行分组。这将重复 相同 的迭代器 n 次,输出的每个元组都包含 n 次调用迭代器的结果。这样做的效果是把输入拆分为长度为 n 的块。

  • zip()* 运算符相结合可以用来拆解一个列表:

    >>> x =[1,2,3]
    >>> y =[4,5,6]
    >>> list(zip(x, y))
    [(1,4),(2,5),(3,6)]
    >>> x2, y2 = zip(*zip(x, y))
    >>> x == list(x2) and y == list(y2)
    True

在 3.10 版更改: 增加了 strict 参数。

  • __import__(name, globals=None, locals=None, fromlist=(), level=0)

注解

importlib.import_module() 不同,这是一个日常 Python 编程中不需要用到的高级函数。

此函数会由 import 语句发起调用。 它可以被替换 (通过导入 builtins 模块并赋值给 builtins.__import__) 以便修改 import 语句的语义,但是 强烈 不建议这样做,因为使用导入钩子 (参见 PEP 302) 通常更容易实现同样的目标,并且不会导致代码问题,因为许多代码都会假定所用的是默认实现。 同样也不建议直接使用 __import__() 而应该用 importlib.import_module()

本函数会导入模块 name*,利用 *globalslocals 来决定如何在包的上下文中解释该名称。fromlist 给出了应从 name 模块中导入的对象或子模块的名称。标准的实现代码完全不会用到 locals 参数,只用到了 globals 用于确定 import 语句所在的包上下文。

level 指定是使用绝对还是相对导入。 0 (默认值) 意味着仅执行绝对导入。 level 为正数值表示相对于模块调用 __import__() 的目录,将要搜索的父目录层数 (详情参见 PEP 328)。

name 变量的形式为 package.module 时,通常将会返回最高层级的包(第一个点号之前的名称),而 不是name 命名的模块。 但是,当给出了非空的 fromlist 参数时,则将返回以 name 命名的模块。

例如,语句 import spam 的结果将为与以下代码作用相同的字节码:

spam = __import__('spam', globals(), locals(),[],0)

语句 import spam.ham 的结果将为以下调用:

spam = __import__('spam.ham', globals(), locals(),[],0)

请注意在这里 __import__() 是如何返回顶层模块的,因为这是通过 import 语句被绑定到特定名称的对象。

另一方面,语句 from spam.ham import eggs, sausage as saus 的结果将为

_temp = __import__('spam.ham', globals(), locals(),['eggs','sausage'],0)
eggs = _temp.eggs
saus = _temp.sausage

在这里, spam.ham 模块会由 __import__() 返回。 要导入的对象将从此对象中提取并赋值给它们对应的名称。

如果您只想按名称导入模块(可能在包中),请使用 importlib.import_module()

在 3.3 版更改: level 的值不再支持负数(默认值也修改为0)。

在 3.9 版更改: 当使用了命令行参数 -E-I 时,环境变量 PYTHONCASEOK 现在将被忽略。

内置常量

有少数的常量存在于内置命名空间中。 它们是:

False

bool 类型的假值。 给 False 赋值是非法的并会引发 SyntaxError

True

bool 类型的真值。 给 True 赋值是非法的并会引发 SyntaxError

None

通常被用来代表空值的对象,例如在未向某个函数传入默认参数时。 给 None 赋值是非法的并会引发 SyntaxErrorNoneNoneType 类型的唯一实例。

NotImplemented

应当由双目运算特殊方法(如 __eq__(), __lt__(), __add__(), __rsub__() 等)返回的特殊值,用于表明运算没有针对其他类型的实现;也可由原地双目运算特殊方法(如 __imul__(), __iand__() 等)出于同样的目的而返回。 它不应在布尔运算中被求值。 NotImplementedtypes.NotImplementedType 类型的唯一实例。

注解

当二进制(或就地)方法返回NotImplemented时,解释器将尝试对另一种类型(或其他一些回滚操作,取决于运算符)的反射操作。 如果所有尝试都返回NotImplemented,则解释器将引发适当的异常。 错误返回的NotImplemented将导致误导性错误消息或返回到Python代码中的NotImplemented值。

注解

NotImplementedErrorNotImplemented 不可互换,即使它们有相似的名称和用途。

在 3.9 版更改: 作为布尔值来解读 NotImplemented 已被弃用。 虽然它目前会被解读为真值,但将同时发出 DeprecationWarning。 它将在未来的 Python 版本中引发 TypeError

Ellipsis

与省略号字面值 “...“ 相同。 该特殊值主要是与用户定义的容器数据类型的扩展切片语法结合使用。 Ellipsistypes.EllipsisType 类型的唯一实例。

__debug__

如果 Python 没有以 -O 选项启动,则此常量为真值。

注解

变量名 NoneFalseTrue__ debug__ 无法重新赋值(赋值给它们,即使是属性名,将引发 SyntaxError ),所以它们可以被认为是“真正的”常数。

site 模块添加的常量

site 模块(在启动期间自动导入,除非给出 -S 命令行选项)将几个常量添加到内置命名空间。 它们对交互式解释器 shell 很有用,并且不应在程序中使用。

  • quit(code=None)

  • exit(code=None)

当打印此对象时,会打印出一条消息,例如“Use quit() or Ctrl-D (i.e. EOF) to exit”,当调用此对象时,将使用指定的退出代码来引发 SystemExit

copyright
credits

打印或调用的对象分别打印版权或作者的文本。

license

当打印此对象时,会打印出一条消息“Type license() to see the full license text”,当调用此对象时,将以分页形式显示完整的许可证文本(每次显示一屏)。

内置类型

以下部分描述了解释器中内置的标准类型。

主要内置类型有数字、序列、映射、类、实例和异常。

有些多项集类是可变的。 它们用于添加、移除或重排其成员的方法将原地执行,并不返回特定的项,绝对不会返回多项集实例自身而是返回 None

有些操作受多种对象类型的支持;特别地,实际上所有对象都可以比较是否相等、检测逻辑值,以及转换为字符串(使用 repr() 函数或略有差异的 str() 函数)。 后一个函数是在对象由 print() 函数输出时被隐式地调用的。

逻辑值检测

任何对象都可以进行逻辑值的检测,以便在 ifwhile 作为条件或是作为下文所述布尔运算的操作数来使用。

一个对象在默认情况下均被视为真值,除非当该对象被调用时其所属类定义了 __bool__() 方法且返回 False 或是定义了 __len__() 方法且返回零。 下面基本完整地列出了会被视为假值的内置对象:

  • 被定义为假值的常量: NoneFalse
  • 任何数值类型的零: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • 空的序列和多项集: '', (), [], {}, set(), range(0)

产生布尔值结果的运算和内置函数总是返回 0False 作为假值,1True 作为真值,除非另行说明。 (重要例外:布尔运算 orand 总是返回其中一个操作数。)

布尔运算 —- and, or, not

这些属于布尔运算,按优先级升序排列:

运算 结果: 备注
x or y if x is false, then y, else x (1)
x and y if x is false, then x, else y (2)
not x if x is false, then True, else False (3)

注释:

  1. 这是个短路运算符,因此只有在第一个参数为假值时才会对第二个参数求值。
  2. 这是个短路运算符,因此只有在第一个参数为真值时才会对第二个参数求值。
  3. not 的优先级比非布尔运算符低,因此 not a == b 会被解读为 not (a == b)a == not b 会引发语法错误。

比较运算

在 Python 中有八种比较运算符。 它们的优先级相同(比布尔运算的优先级高)。 比较运算可以任意串连;例如,x < y <= z 等价于 x < y and y <= z,前者的不同之处在于 y 只被求值一次(但在两种情况下当 x < y 结果为假值时 z 都不会被求值)。

此表格汇总了比较运算:

运算 含意
< 严格小于
<= 小于或等于
> 严格大于
>= 大于或等于
== 等于
!= 不等于
is 对象标识
is not 否定的对象标识

除不同的数字类型外,不同类型的对象不能进行相等比较。== 运算符总有定义,但对于某些对象类型(例如,类对象),它等于 is 。其他 <<=>>= 运算符仅在有意义的地方定义。例如,当参与比较的参数之一为复数时,它们会抛出 TypeError 异常。

具有不同标识的类的实例比较结果通常为不相等,除非类定义了 __eq__() 方法。

一个类实例不能与相同类或的其他实例或其他类型的对象进行排序,除非该类定义了足够多的方法,包括 __lt__(), __le__(), __gt__() 以及 __ge__() (而如果你想实现常规意义上的比较操作,通常只要有 __lt__()__eq__() 就可以了)。

isis not 运算符无法自定义;并且它们可以被应用于任意两个对象而不会引发异常。

还有两种具有相同语法优先级的运算 innot in,它们被 iterable 或实现了 __contains__() 方法的类型所支持。

数字类型 —- int, float, complex

存在三种不同的数字类型: 整数, 浮点数复数*。 此外,布尔值属于整数的子类型。 整数具有无限的精度。 浮点数通常使用 C 中的 double 来实现;有关你的程序运行所在机器上浮点数的精度和内部表示法可在 sys.float_info 中查看。 复数包含实部和虚部,分别以一个浮点数表示。 要从一个复数 *z 中提取这两个部分,可使用 z.realz.imag。 (标准库包含附加的数字类型,如表示有理数的 fractions.Fraction 以及以用户定制精度表示浮点数的 decimal.Decimal。)

数字是由数字字面值或内置函数与运算符的结果来创建的。 不带修饰的整数字面值(包括十六进制、八进制和二进制数)会生成整数。 包含小数点或幂运算符的数字字面值会生成浮点数。 在数字字面值末尾加上 'j''J' 会生成虚数(实部为零的复数),你可以将其与整数或浮点数相加来得到具有实部和虚部的复数。

Python 完全支持混合运算:当一个二元算术运算符的操作数有不同数值类型时,”较窄”类型的操作数会拓宽到另一个操作数的类型,其中整数比浮点数窄,浮点数比复数窄。不同类型的数字之间的比较,同比较这些数字的精确值一样。

构造函数 int()float()complex() 可以用来构造特定类型的数字。

所有数字类型(复数除外)都支持下列运算:

运算 结果: 备注 完整文档
x + y xy 的和
x - y xy 的差
x * y xy 的乘积
x / y xy 的商
x // y xy 的商数 (1)
x % y x / y 的余数 (2)
-x x 取反
+x x 不变
abs(x) x 的绝对值或大小 abs()
int(x) x 转换为整数 (3)(6) int()
float(x) x 转换为浮点数 (4)(6) float()
complex(re, im) 一个带有实部 re 和虚部 im 的复数。im 默认为0。 (6) complex()
c.conjugate() 复数 c 的共轭
divmod(x, y) (x // y, x % y) (2) divmod()
pow(x, y) xy 次幂 (5) pow()
x ** y xy 次幂 (5)

注释:

  1. 也称为整数除法。 结果值是一个整数,但结果的类型不一定是 int。 运算结果总是向负无穷的方向舍入: 1//20, (-1)//2-1, 1//(-2)-1(-1)//(-2)0

  2. 不可用于复数。 而应在适当条件下使用 abs() 转换为浮点数。

  3. 从浮点数转换为整数会被舍入或是像在 C 语言中一样被截断。

  4. float 也接受字符串 “nan” 和附带可选前缀 “+” 或 “-“ 的 “inf” 分别表示非数字 (NaN) 以及正或负无穷。

  5. Python 将 pow(0, 0)0 ** 0 定义为 1,这是编程语言的普遍做法。

  6. 接受的数字字面值包括数码 09 或任何等效的 Unicode 字符(具有 Nd 特征属性的代码点)。

    请参阅 https://www.unicode.org/Public/13.0.0/ucd/extracted/DerivedNumericType.txt 查看具有 Nd 特征属性的代码点的完整列表。

所有 numbers.Real 类型 (intfloat) 还包括下列运算:

运算 结果:
math.trunc(x) x 截断为 Integral
round(x[, n\]) x 舍入到 n 位小数,半数值会舍入到偶数。 如果省略 n,则默认为 0。
math.floor(x) <= x 的最大 Integral
math.ceil(x) >= x 的最小 Integral

整数类型的按位运算

按位运算只对整数有意义。 计算按位运算的结果,就相当于使用无穷多个二进制符号位对二的补码执行操作。

二进制按位运算的优先级全都低于数字运算,但又高于比较运算;一元运算 ~ 具有与其他一元算术运算 (+ and -) 相同的优先级。

此表格是以优先级升序排序的按位运算列表:

运算 结果: 备注
`x y` xy 按位
x ^ y xy 按位 异或 (4)
x & y xy 按位 (4)
x << n x 左移 n (1)(2)
x >> n x 右移 n (1)(3)
~x x 逐位取反

注释:

  1. 负的移位数是非法的,会导致引发 ValueError
  2. 左移 n 位等价于乘以 pow(2, n)
  3. 右移 n 位等价于除以 pow(2, n) ,作向下取整除法。
  4. 使用带有至少一个额外符号扩展位的有限个二进制补码表示(有效位宽度为 1 + max(x.bit_length(), y.bit_length()) 或以上)执行这些计算就足以获得相当于有无数个符号位时的同样结果。

整数类型的附加方法

int 类型实现了 numbers.Integral abstract base class。 此外,它还提供了其他几个方法:

int.bit_length()

返回以二进制表示一个整数所需要的位数,不包括符号位和前面的零:

>>> n = -37
>>> bin(n)
'-0b100101'
>>> n.bit_length()
6

更准确地说,如果 x 非零,则 x.bit_length() 是使得 2**(k-1) <= abs(x) < 2**k 的唯一正整数 k。 同样地,当 abs(x) 小到足以具有正确的舍入对数时,则 k = 1 + int(log(abs(x), 2))。 如果 x 为零,则 x.bit_length() 返回 0

等价于:

def bit_length(self):
    s = bin(self)       # binary representation:  bin(-37) --> '-0b100101'
    s = s.lstrip('-0b') # remove leading zeros and minus sign
    return len(s)       # len('100101') --> 6

3.1 新版功能.

int.bit_count()

Return the number of ones in the binary representation of the absolute value of the integer. This is also known as the population count. Example:

>>> n = 19
>>> bin(n)
'0b10011'
>>> n.bit_count()
3
>>> (-n).bit_count()
3

等价于:

def bit_count(self):    
    return bin(self).count("1")

3.10 新版功能.

int.to_bytes(length, byteorder, **, signed=False*)

返回表示一个整数的字节数组。

>>> (1024).to_bytes(2, byteorder='big')
b'\x04\x00'
>>> (1024).to_bytes(10, byteorder='big')
b'\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00'
>>> (-1024).to_bytes(10, byteorder='big', signed=True)
b'\xff\xff\xff\xff\xff\xff\xff\xff\xfc\x00'
>>> x = 1000
>>> x.to_bytes((x.bit_length() + 7) // 8, byteorder='little')
b'\xe8\x03'

整数会使用 length 个字节来表示。 如果整数不能用给定的字节数来表示则会引发 OverflowError

byteorder 参数确定用于表示整数的字节顺序。 如果 byteorder"big",则最高位字节放在字节数组的开头。 如果 byteorder"little",则最高位字节放在字节数组的末尾。 要请求主机系统上的原生字节顺序,请使用 sys.byteorder 作为字节顺序值。

signed 参数确定是否使用二的补码来表示整数。 如果 signedFalse 并且给出的是负整数,则会引发 OverflowErrorsigned 的默认值为 False

3.2 新版功能.

classmethod int.from_bytes(bytes, byteorder, **, signed=False*)

返回由给定字节数组所表示的整数。

>>> int.from_bytes(b'\x00\x10', byteorder='big')
16
>>> int.from_bytes(b'\x00\x10', byteorder='little')
4096
>>> int.from_bytes(b'\xfc\x00', byteorder='big', signed=True)
-1024
>>> int.from_bytes(b'\xfc\x00', byteorder='big', signed=False)
64512
>>> int.from_bytes([255, 0, 0], byteorder='big')
16711680

bytes 参数必须为一个 bytes-like object 或是生成字节的可迭代对象。

byteorder 参数确定用于表示整数的字节顺序。 如果 byteorder"big",则最高位字节放在字节数组的开头。 如果 byteorder"little",则最高位字节放在字节数组的末尾。 要请求主机系统上的原生字节顺序,请使用 sys.byteorder 作为字节顺序值。

signed 参数指明是否使用二的补码来表示整数。

3.2 新版功能.

int.as_integer_ratio()

返回一对整数,其比率正好等于原整数并且分母为正数。 整数的比率总是用这个整数本身作为分子,1 作为分母。

3.8 新版功能.

浮点类型的附加方法

float 类型实现了 numbers.Real abstract base class。 float 还具有以下附加方法。

float.as_integer_ratio()

返回一对整数,其比率正好等于原浮点数并且分母为正数。 无穷大会引发 OverflowError 而 NaN 则会引发 ValueError

float.is_integer()

如果 float 实例可用有限位整数表示则返回 True,否则返回 False:

>>> (-2.0).is_integer()
True
>>> (3.2).is_integer()
False

两个方法均支持与十六进制数字符串之间的转换。 由于 Python 浮点数在内部存储为二进制数,因此浮点数与 十进制数 字符串之间的转换往往会导致微小的舍入错误。 而十六进制数字符串却允许精确地表示和描述浮点数。 这在进行调试和数值工作时非常有用。

float.hex()

以十六进制字符串的形式返回一个浮点数表示。 对于有限浮点数,这种表示法将总是包含前导的 0x 和尾随的 p 加指数。

classmethod float.fromhex(s)

返回以十六进制字符串 s 表示的浮点数的类方法。 字符串 s 可以带有前导和尾随的空格。

请注意 float.hex() 是实例方法,而 float.fromhex() 是类方法。

十六进制字符串采用的形式为:

[sign] ['0x'] integer ['.' fraction] ['p' exponent]

可选的 sign 可以是 +-integerfraction 是十六进制数码组成的字符串,exponent 是带有可选前导符的十进制整数。 大小写没有影响,在 integer 或 fraction 中必须至少有一个十六进制数码。 此语法类似于 C99 标准的 6.4.4.2 小节中所描述的语法,也是 Java 1.5 以上所使用的语法。 特别地,float.hex() 的输出可以用作 C 或 Java 代码中的十六进制浮点数字面值,而由 C 的 %a 格式字符或 Java 的 Double.toHexString 所生成的十六进制数字符串由为 float.fromhex() 所接受。

请注意 exponent 是十进制数而非十六进制数,它给出要与系数相乘的 2 的幂次。 例如,十六进制数字符串 0x3.a7p10 表示浮点数 (3 + 10./16 + 7./16**2) * 2.0**103740.0:

>>> float.fromhex('0x3.a7p10')
3740.0

3740.0 应用反向转换会得到另一个代表相同数值的十六进制数字符串:

>>> float.hex(3740.0)
'0x1.d380000000000p+11'

数字类型的哈希运算

对于可能为不同类型的数字 xy,要求 x == y 时必定 hash(x) == hash(y)。 为了便于在各种数字类型 (包括 int, float, decimal.Decimalfractions.Fraction) 上实现并保证效率,Python 对数字类型的哈希运算是基于为任意有理数定义统一的数学函数,因此该运算对 intfractions.Fraction 的全部实例,以及 floatdecimal.Decimal 的全部有限实例均可用。 从本质上说,此函数是通过以一个固定质数 P 进行 P 降模给出的。 P 的值在 Python 中可以 sys.hash_infomodulus 属性的形式被访问。

CPython implementation detail: 目前所用的质数设定,在 C long 为 32 位的机器上 P = 2**31 - 1 而在 C long 为 64 位的机器上 P = 2**61 - 1

详细规则如下所述:

  • 如果 x = m / n 是一个非负的有理数且 n 不可被 P 整除,则定义 hash(x)m * invmod(n, P) % P,其中 invmod(n, P) 是对 nP 取反。
  • 如果 x = m / n 是一个非负的有理数且 n 可被 P 整除(但 m 不能)则 n 不能对 P 降模,以上规则不适用;在此情况下则定义 hash(x) 为常数值 sys.hash_info.inf
  • 如果 x = m / n 是一个负的有理数则定义 hash(x)-hash(-x)。 如果结果哈希值为 -1 则将其替换为 -2
  • The particular values sys.hash_info.inf and -sys.hash_info.inf are used as hash values for positive infinity or negative infinity (respectively).
  • 对于一个 complexz,会通过计算 hash(z.real) + sys.hash_info.imag * hash(z.imag) 将实部和虚部的哈希值结合起来,并进行降模 2**sys.hash_info.width 以使其处于 range(-2**(sys.hash_info.width - 1), 2**(sys.hash_info.width - 1)) 范围之内。 同样地,如果结果为 -1 则将其替换为 -2

为了阐明上述规则,这里有一些等价于内置哈希算法的 Python 代码示例,可用于计算有理数、floatcomplex 的哈希值:

import sys, math
def hash_fraction(m, n):
    """Compute the hash of a rational number m / n.
    Assumes m and n are integers, with n positive.
    Equivalent to hash(fractions.Fraction(m, n)).
    """
    P = sys.hash_info.modulus
    # Remove common factors of P.  (Unnecessary if m and n already coprime.)
    while m % P == n % P == 0:
        m, n = m // P, n // P
    if n % P == 0:
        hash_value = sys.hash_info.inf
    else:
        # Fermat's Little Theorem: pow(n, P-1, P) is 1, so
        # pow(n, P-2, P) gives the inverse of n modulo P.
        hash_value = (abs(m) % P) * pow(n, P - 2, P) % P
    if m < 0:
        hash_value = -hash_value
    if hash_value == -1:
        hash_value = -2
    return hash_value
def hash_float(x):
    """Compute the hash of a float x."""
    if math.isnan(x):
        return object.__hash__(x)
    elif math.isinf(x):
        return sys.hash_info.inf if x > 0 else -sys.hash_info.inf
    else:
        return hash_fraction(*x.as_integer_ratio())
def hash_complex(z):
    """Compute the hash of a complex number z."""
    hash_value = hash_float(z.real) + sys.hash_info.imag * hash_float(z.imag)
    # do a signed reduction modulo 2**sys.hash_info.width
    M = 2**(sys.hash_info.width - 1)
    hash_value = (hash_value & (M - 1)) - (hash_value & M)
    if hash_value == -1:
        hash_value = -2
    return hash_value

迭代器类型

Python 支持在容器中进行迭代的概念。 这是通过使用两个单独方法来实现的;它们被用于允许用户自定义类对迭代的支持。 将在下文中详细描述的序列总是支持迭代方法。

容器对象要提供迭代支持,必须定义一个方法:

container.__iter__()

返回一个迭代器对象。 该对象需要支持下文所述的迭代器协议。 如果容器支持不同的迭代类型,则可以提供额外的方法来专门地请求不同迭代类型的迭代器。 (支持多种迭代形式的对象的例子有同时支持广度优先和深度优先遍历的树结构。) 此方法对应于 Python/C API 中 Python 对象类型结构体的 tp_iter 槽位。

迭代器对象自身需要支持以下两个方法,它们共同组成了 迭代器协议:

iterator.__iter__()

返回迭代器对象本身。 这是同时允许容器和迭代器配合 forin 语句使用所必须的。 此方法对应于 Python/C API 中 Python 对象类型结构体的 tp_iter 槽位。

iterator.__next__()

从容器中返回下一项。 如果已经没有项可返回,则会引发 StopIteration 异常。 此方法对应于 Python/C API 中 Python 对象类型结构体的 tp_iternext 槽位。

Python 定义了几种迭代器对象以支持对一般和特定序列类型、字典和其他更特别的形式进行迭代。 除了迭代器协议的实现,特定类型的其他性质对迭代操作来说都不重要。

一旦迭代器的 __next__() 方法引发了 StopIteration,它必须一直对后续调用引发同样的异常。 不遵循此行为特性的实现将无法正常使用。

生成器类型

Python 的 generator 提供了一种实现迭代器协议的便捷方式。 如果容器对象 __iter__() 方法被实现为一个生成器,它将自动返回一个迭代器对象(从技术上说是一个生成器对象),该对象提供 __iter__()__next__() 方法。

序列类型 —- list, tuple, range

有三种基本序列类型:list, tuple 和 range 对象。

通用序列操作

大多数序列类型,包括可变类型和不可变类型都支持下表中的操作。 collections.abc.Sequence ABC 被提供用来更容易地在自定义序列类型上正确地实现这些操作。

此表按优先级升序列出了序列操作。 在表格中,st 是具有相同类型的序列,n, i, jk 是整数而 x 是任何满足 s 所规定的类型和值限制的任意对象。

innot in 操作具有与比较操作相同的优先级。 + (拼接) 和 * (重复) 操作具有与对应数值运算相同的优先级。

运算 结果: 备注
x in s 如果 s 中的某项等于 x 则结果为 True,否则为 False (1)
x not in s 如果 s 中的某项等于 x 则结果为 False,否则为 True (1)
s + t st 相拼接 (6)(7)
s * n ns 相当于 s 与自身进行 n 次拼接 (2)(7)
s[i] s 的第 i 项,起始为 0 (3)
s[i:j] sij 的切片 (3)(4)
s[i:j:k] sij 步长为 k 的切片 (3)(5)
len(s) s 的长度
min(s) s 的最小项
max(s) s 的最大项
s.index(x[, i[, j]]) xs 中首次出现项的索引号(索引号在 i 或其后且在 j 之前) (8)
s.count(x) xs 中出现的总次数

相同类型的序列也支持比较。 特别地,tuple 和 list 的比较是通过比较对应元素的字典顺序。 这意味着想要比较结果相等,则每个元素比较结果都必须相等,并且两个序列长度必须相同。

注释:

  1. 虽然 innot in 操作在通常情况下仅被用于简单的成员检测,某些专门化序列 (例如 str, bytesbytearray) 也使用它们进行子序列检测:

    >>> "gg" in "eggs"
    True
  2. 小于 0n 值会被当作 0 来处理 (生成一个与 s 同类型的空序列)。 请注意序列 s 中的项并不会被拷贝;它们会被多次引用。 这一点经常会令 Python 编程新手感到困扰;例如:

    >>> lists = [[]] * 3
    >>> lists
    [[], [], []]
    >>> lists[0].append(3)
    >>> lists
    [[3], [3], [3]]

    具体的原因在于 [[]] 是一个包含了一个空列表的单元素列表,所以 [[]] * 3 结果中的三个元素都是对这一个空列表的引用。 修改 lists 中的任何一个元素实际上都是对这一个空列表的修改。 你可以用以下方式创建以不同列表为元素的列表:

    >>> lists = [[] for i in range(3)]
    >>> lists[0].append(3)
    >>> lists[1].append(5)
    >>> lists[2].append(7)
    >>> lists
    [[3], [5], [7]]
  3. 如果 ij 为负值,则索引顺序是相对于序列 s 的末尾: 索引号会被替换为 len(s) + ilen(s) + j。 但要注意 -0 仍然为 0

  4. sij 的切片被定义为所有满足 i <= k < j 的索引号 k 的项组成的序列。 如果 ij 大于 len(s),则使用 len(s)。 如果 i 被省略或为 None,则使用 0。 如果 j 被省略或为 None,则使用 len(s)。 如果 i 大于等于 j,则切片为空。

  5. sij 步长为 k 的切片被定义为所有满足 0 <= n < (j-i)/k 的索引号 x = i + n*k 的项组成的序列。 换句话说,索引号为 i, i+k, i+2*k, i+3*k,以此类推,当达到 j 时停止 (但一定不包括 j)。 当 k 为正值时,ij 会被减至不大于 len(s)。 当 k 为负值时,ij 会被减至不大于 len(s) - 1。 如果 ij 被省略或为 None,它们会成为“终止”值 (是哪一端的终止值则取决于 k 的符号)。 请注意,k 不可为零。 如果 kNone,则当作 1 处理。

  6. 拼接不可变序列总是会生成新的对象。 这意味着通过重复拼接来构建序列的运行时开销将会基于序列总长度的乘方。 想要获得线性的运行时开销,你必须改用下列替代方案之一:

    • 如果拼接 str 对象,你可以构建一个列表并在最后使用 str.join() 或是写入一个 io.StringIO 实例并在结束时获取它的值
    • 如果拼接 bytes 对象,你可以类似地使用 bytes.join()io.BytesIO,或者你也可以使用 bytearray 对象进行原地拼接。 bytearray 对象是可变的,并且具有高效的重分配机制
    • 如果拼接 tuple 对象,请改为扩展 list
    • 对于其它类型,请查看相应的文档
  7. 某些序列类型 (例如 range) 仅支持遵循特定模式的项序列,因此并不支持序列拼接或重复。

  8. xs 中找不到时 index 会引发 ValueError。 不是所有实现都支持传入额外参数 ij。 这两个参数允许高效地搜索序列的子序列。 传入这两个额外参数大致相当于使用 s[i:j].index(x),但是不会复制任何数据,并且返回的索引是相对于序列的开头而非切片的开头。

不可变序列类型

不可变序列类型普遍实现而可变序列类型未实现的唯一操作就是对 hash() 内置函数的支持。

这种支持允许不可变类型,例如 tuple 实例被用作 dict 键,以及存储在 setfrozenset 实例中。

尝试对包含有不可哈希值的不可变序列进行哈希运算将会导致 TypeError

可变序列类型

以下表格中的操作是在可变序列类型上定义的。 collections.abc.MutableSequence ABC 被提供用来更容易地在自定义序列类型上正确实现这些操作。

表格中的 s 是可变序列类型的实例,t 是任意可迭代对象,而 x 是符合对 s 所规定类型与值限制的任何对象 (例如,bytearray 仅接受满足 0 <= x <= 255 值限制的整数)。

运算 结果: 备注
s[i] = x s 的第 i 项替换为 x
s[i:j] = t sij 的切片替换为可迭代对象 t 的内容
del s[i:j] 等同于 s[i:j] = []
s[i:j:k] = t s[i:j:k] 的元素替换为 t 的元素 (1)
del s[i:j:k] 从列表中移除 s[i:j:k] 的元素
s.append(x) x 添加到序列的末尾 (等同于 s[len(s):len(s)] = [x])
s.clear() s 中移除所有项 (等同于 del s[:]) (5)
s.copy() 创建 s 的浅拷贝 (等同于 s[:]) (5)
s.extend(t)s += t t 的内容扩展 s (基本上等同于 s[len(s):len(s)] = t)
s *= n 使用 s 的内容重复 n 次来对其进行更新 (6)
s.insert(i, x) 在由 i 给出的索引位置将 x 插入 s (等同于 s[i:i] = [x])
s.pop() or s.pop(i) 提取在 i 位置上的项,并将其从 s 中移除 (2)
s.remove(x) 删除 s 中第一个 s[i] 等于 x 的项目。 (3)
s.reverse() 就地将列表中的元素逆序。 (4)

注释:

  1. t 必须与它所替换的切片具有相同的长度。

  2. 可选参数 i 默认为 -1,因此在默认情况下会移除并返回最后一项。

  3. 当在 s 中找不到 xremove() 操作会引发 ValueError

  4. 当反转大尺寸序列时 reverse() 方法会原地修改该序列以保证空间经济性。 为提醒用户此操作是通过间接影响进行的,它并不会返回反转后的序列。

  5. 包括 clear()copy() 是为了与不支持切片操作的可变容器 (例如 dictset) 的接口保持一致。 copy() 不是 collections.abc.MutableSequence ABC 的一部分,但大多数具体的可变序列类都提供了它。

    3.3 新版功能: clear()copy() 方法。

  6. n 值为一个整数,或是一个实现了 __index__() 的对象。 n 值为零或负数将清空序列。 序列中的项不会被拷贝;它们会被多次引用,正如 通用序列操作 中有关 s * n 的说明。

列表

列表是可变序列,通常用于存放同类项目的集合(其中精确的相似程度将根据应用而变化)。

class list([iterable])

可以用多种方式构建列表:

  • 使用一对方括号来表示空列表: []
  • 使用方括号,其中的项以逗号分隔: [a], [a, b, c]
  • 使用列表推导式: [x for x in iterable]
  • 使用类型的构造器: list()list(iterable)

构造器将构造一个列表,其中的项与 iterable 中的项具有相同的的值与顺序。 iterable 可以是序列、支持迭代的容器或其它可迭代对象。 如果 iterable 已经是一个列表,将创建并返回其副本,类似于 iterable[:]。 例如,list('abc') 返回 ['a', 'b', 'c']list( (1, 2, 3) ) 返回 [1, 2, 3]。 如果没有给出参数,构造器将创建一个空列表 []

其它许多操作也会产生列表,包括 sorted() 内置函数。

列表实现了所有 一般 和 可变 序列的操作。 列表还额外提供了以下方法:

  • sort(**, key=None, reverse=False*)

    此方法会对列表进行原地排序,只使用 < 来进行各项间比较。 异常不会被屏蔽 —— 如果有任何比较操作失败,整个排序操作将失败(而列表可能会处于被部分修改的状态)。

    sort() 接受两个仅限以关键字形式传入的参数 (仅限关键字参数):

    key 指定带有一个参数的函数,用于从每个列表元素中提取比较键 (例如 key=str.lower)。 对应于列表中每一项的键会被计算一次,然后在整个排序过程中使用。 默认值 None 表示直接对列表项排序而不计算一个单独的键值。

    可以使用 functools.cmp_to_key() 将 2.x 风格的 cmp 函数转换为 key 函数。

    reverse 为一个布尔值。 如果设为 True,则每个列表元素将按反向顺序比较进行排序。

    当顺序大尺寸序列时此方法会原地修改该序列以保证空间经济性。 为提醒用户此操作是通过间接影响进行的,它并不会返回排序后的序列(请使用 sorted() 显示地请求一个新的已排序列表实例)。

    sort() 方法确保是稳定的。 如果一个排序确保不会改变比较结果相等的元素的相对顺序就称其为稳定的 —- 这有利于进行多重排序(例如先按部门、再接薪级排序)。

    CPython implementation detail: 在一个列表被排序期间,尝试改变甚至进行检测也会造成未定义的影响。 Python 的 C 实现会在排序期间将列表显示为空,如果发现列表在排序期间被改变将会引发 ValueError

元组

元组是不可变序列,通常用于储存异构数据的多项集(例如由 enumerate() 内置函数所产生的二元组)。 元组也被用于需要同构数据的不可变序列的情况(例如允许存储到 setdict 的实例)。

class tuple([iterable])

可以用多种方式构建元组:

  • 使用一对圆括号来表示空元组: ()
  • 使用一个后缀的逗号来表示单元组: a,(a,)
  • 使用以逗号分隔的多个项: a, b, c or (a, b, c)
  • 使用内置的 tuple(): tuple()tuple(iterable)

构造器将构造一个元组,其中的项与 iterable 中的项具有相同的值与顺序。 iterable 可以是序列、支持迭代的容器或其他可迭代对象。 如果 iterable 已经是一个元组,会不加改变地将其返回。 例如,tuple('abc') 返回 ('a', 'b', 'c')tuple( [1, 2, 3] ) 返回 (1, 2, 3)。 如果没有给出参数,构造器将创建一个空元组 ()

请注意决定生成元组的其实是逗号而不是圆括号。 圆括号只是可选的,生成空元组或需要避免语法歧义的情况除外。 例如,f(a, b, c) 是在调用函数时附带三个参数,而 f((a, b, c)) 则是在调用函数时附带一个三元组。

元组实现了所有 一般 序列的操作。

对于通过名称访问相比通过索引访问更清晰的异构数据多项集,collections.namedtuple() 可能是比简单元组对象更为合适的选择。

range 对象

range 类型表示不可变的数字序列,通常用于在 for 循环中循环指定的次数。

class range(stop)

class range(start, stop[, step])

range 构造器的参数必须为整数(可以是内置的 int 或任何实现了 __index__ 特殊方法的对象)。 如果省略 step 参数,其默认值为 1。 如果省略 start 参数,其默认值为 0,如果 step 为零则会引发 ValueError

如果 step 为正值,确定 range r 内容的公式为 r[i] = start + step*i 其中 i >= 0r[i] < stop

如果 step 为负值,确定 range 内容的公式仍然为 r[i] = start + step*i,但限制条件改为 i >= 0r[i] > stop.

如果 r[0] 不符合值的限制条件,则该 range 对象为空。 range 对象确实支持负索引,但是会将其解读为从正索引所确定的序列的末尾开始索引。

元素绝对值大于 sys.maxsize 的 range 对象是被允许的,但某些特性 (例如 len()) 可能引发 OverflowError

一些 range 对象的例子:

>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(range(0, 30, 5))
[0, 5, 10, 15, 20, 25]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> list(range(0))
[]
>>> list(range(1, 0))
[]

range 对象实现了 一般 序列的所有操作,但拼接和重复除外(这是由于 range 对象只能表示符合严格模式的序列,而重复和拼接通常都会违反这样的模式)。

  • start

    start 形参的值 (如果该形参未提供则为 0)

  • stop

    stop 形参的值

  • step

    step 形参的值 (如果该形参未提供则为 1)

range 类型相比常规 listtuple 的优势在于一个 range 对象总是占用固定数量的(较小)内存,不论其所表示的范围有多大(因为它只保存了 start, stopstep 值,并会根据需要计算具体单项或子范围的值)。

range 对象实现了 collections.abc.Sequence ABC,提供如包含检测、元素索引查找、切片等特性,并支持负索引 :

>>> r = range(0, 20, 2)
>>> r
range(0, 20, 2)
>>> 11 in r
False
>>> 10 in r
True
>>> r.index(10)
5
>>> r[5]
10
>>> r[:5]
range(0, 10, 2)
>>> r[-1]
18

使用 ==!= 检测 range 对象是否相等是将其作为序列来比较。 也就是说,如果两个 range 对象表示相同的值序列就认为它们是相等的。 (请注意比较结果相等的两个 range 对象可能会具有不同的 start, stopstep 属性,例如 range(0) == range(2, 1, 3)range(0, 3, 2) == range(0, 4, 2)。)

在 3.2 版更改: 实现 Sequence ABC。 支持切片和负数索引。 使用 int 对象在固定时间内进行成员检测,而不是逐一迭代所有项。

在 3.3 版更改: 定义 ‘==’ 和 ‘!=’ 以根据 range 对象所定义的值序列来进行比较(而不是根据对象的标识)。

3.3 新版功能: start, stopstep 属性。

参见

  • linspace recipe 演示了如何实现一个延迟求值版本的适合浮点数应用的 range 对象。

文本序列类型 —- str

在 Python 中处理文本数据是使用 str 对象,也称为 字符串。 字符串是由 Unicode 码位构成的不可变 序列。 字符串字面值有多种不同的写法:

  • 单引号: '允许包含有 "双" 引号'
  • 双引号: "允许包含有 '单' 引号"
  • 三重引号: '''三重单引号''', """三重双引号"""

使用三重引号的字符串可以跨越多行 —— 其中所有的空白字符都将包含在该字符串字面值中。

作为单一表达式组成部分,之间只由空格分隔的多个字符串字面值会被隐式地转换为单个字符串字面值。 也就是说,("spam " "eggs") == "spam eggs"

使用 r (“raw”) 前缀来禁用大多数转义序列的处理。

字符串也可以通过使用 str 构造器从其他对象创建。

由于不存在单独的“字符”类型,对字符串做索引操作将产生一个长度为 1 的字符串。 也就是说,对于一个非空字符串 s, s[0] == s[0:1]

不存在可变的字符串类型,但是 str.join()io.StringIO 可以被被用来根据多个片段高效率地构建字符串。

在 3.3 版更改: 为了与 Python 2 系列的向下兼容,再次允许字符串字面值使用 u 前缀。 它对字符串字面值的含义没有影响,并且不能与 r 前缀同时出现。

class str(object=’’)

class str(object=b’’, encoding=’utf-8’, errors=’strict’)

返回 object 的 字符串 版本。 如果未提供 object 则返回空字符串。 在其他情况下 str() 的行为取决于 encodingerrors 是否有给出,具体见下。

如果 encodingerrors 均未给出,str(object) 返回 object.__str__(),这是 object 的“非正式”或格式良好的字符串表示。 对于字符串对象,这是该字符串本身。 如果 object 没有 __str__() 方法,则 str() 将回退为返回 repr(object)

如果 encodingerrors 至少给出其中之一,则 object 应该是一个 bytes-like object (例如 bytesbytearray)。 在此情况下,如果 object 是一个 bytes (或 bytearray) 对象,则 str(bytes, encoding, errors) 等价于 bytes.decode(encoding, errors)。 否则的话,会在调用 bytes.decode() 之前获取缓冲区对象下层的 bytes 对象。

将一个 bytes 对象传入 str() 而不给出 encodingerrors 参数的操作属于第一种情况, 将返回非正式的字符串表示(另请参阅 Python 的 -b 命令行选项)。 例如:

>>> str(b'Zoot!')
"b'Zoot!'"

字符串的方法

字符串实现了所有 一般 序列的操作,还额外提供了以下列出的一些附加方法。

字符串还支持两种字符串格式化样式,一种提供了很大程度的灵活性和可定制性 而另一种是基于 C printf 样式的格式化,它可处理的类型范围较窄,并且更难以正确使用,但对于它可处理的情况往往会更为快速 (printf 风格的字符串格式化)。

标准库的 文本处理服务 部分涵盖了许多其他模块,提供各种文本相关工具(例如包含于 re 模块中的正则表达式支持)。

str.capitalize()

返回原字符串的副本,其首个字符大写,其余为小写。

在 3.8 版更改: 第一个字符现在被放入了 titlecase 而不是 uppercase。 这意味着复合字母类字符将只有首个字母改为大写,而再不是全部字符大写。

str.casefold()

返回原字符串消除大小写的副本。 消除大小写的字符串可用于忽略大小写的匹配。

消除大小写类似于转为小写,但是更加彻底一些,因为它会移除字符串中的所有大小写变化形式。 例如,德语小写字母 'ß' 相当于 "ss"。 由于它已经是小写了,lower() 不会对 'ß' 做任何改变;而 casefold() 则会将其转换为 "ss"

消除大小写算法的描述请参见 Unicode 标准的 3.13 节。

3.3 新版功能.

str.center(width[, fillchar])

返回长度为 width 的字符串,原字符串在其正中。 使用指定的 fillchar 填充两边的空位(默认使用 ASCII 空格符)。 如果 width 小于等于 len(s) 则返回原字符串的副本。

str.count(sub[, start[, end]])

返回子字符串 sub 在 [start, end*] 范围内非重叠出现的次数。 可选参数 *startend 会被解读为切片表示法。

str.encode(encoding=’utf-8’, errors=’strict’)

返回原字符串编码为字节串对象的版本。 默认编码为 'utf-8'。 可以给出 errors 来设置不同的错误处理方案。 errors 的默认值为 'strict',表示编码错误会引发 UnicodeError。 其他可用的值为 'ignore', 'replace', 'xmlcharrefreplace', 'backslashreplace' 以及任何其他通过 codecs.register_error() 注册的值。 要查看可用的编码列表。

By default, the errors argument is not checked for best performances, but only used at the first encoding error. Enable the Python Development Mode, or use a debug build to check errors.

在 3.1 版更改: 加入了对关键字参数的支持。

在 3.9 版更改: The errors is now checked in development mode and in debug mode.

str.endswith(suffix[, start[, end]])

如果字符串以指定的 suffix 结束返回 True,否则返回 Falsesuffix 也可以为由多个供查找的后缀构成的元组。 如果有可选项 start,将从所指定位置开始检查。 如果有可选项 end,将在所指定位置停止比较。

str.expandtabs(tabsize=8)

返回字符串的副本,其中所有的制表符会由一个或多个空格替换,具体取决于当前列位置和给定的制表符宽度。 每 tabsize 个字符设为一个制表位(默认值 8 时设定的制表位在列 0, 8, 16 依次类推)。 要展开字符串,当前列将被设为零并逐一检查字符串中的每个字符。 如果字符为制表符 (\t),则会在结果中插入一个或多个空格符,直到当前列等于下一个制表位。 (制表符本身不会被复制。) 如果字符为换行符 (\n) 或回车符 (\r),它会被复制并将当前列重设为零。 任何其他字符会被不加修改地复制并将当前列加一,不论该字符在被打印时会如何显示。

>>> '01\t012\t0123\t01234'.expandtabs()
'01      012     0123    01234'
>>> '01\t012\t0123\t01234'.expandtabs(4)
'01  012 0123    01234'

str.find(sub[, start[, end]])

返回子字符串 subs[start:end] 切片内被找到的最小索引。 可选参数 startend 会被解读为切片表示法。 如果 sub 未被找到则返回 -1

注解

find() 方法应该只在你需要知道 sub 所在位置时使用。 要检查 sub 是否为子字符串,请使用 in 操作符:

>>> 'Py' in 'Python'
True

str.format(\args, *kwargs)

执行字符串格式化操作。 调用此方法的字符串可以包含字符串字面值或者以花括号 {} 括起来的替换域。 每个替换域可以包含一个位置参数的数字索引,或者一个关键字参数的名称。 返回的字符串副本中每个替换域都会被替换为对应参数的字符串值。

>>> "The sum of 1 + 2 is {0}".format(1+2)
'The sum of 1 + 2 is 3'

请参阅 格式字符串语法 了解有关可以在格式字符串中指定的各种格式选项的说明。

注解

当使用 n 类型 (例如: '{:n}'.format(1234)) 来格式化数字 (int, float, complex, decimal.Decimal 及其子类) 的时候,该函数会临时性地将 LC_CTYPE 区域设置为 LC_NUMERIC 区域以解码 localeconv()decimal_pointthousands_sep 字段,如果它们是非 ASCII 字符或长度超过 1 字节的话,并且 LC_NUMERIC 区域会与 LC_CTYPE 区域不一致。 这个临时更改会影响其他线程。

在 3.7 版更改: 当使用 n 类型格式化数字时,该函数在某些情况下会临时性地将 LC_CTYPE 区域设置为 LC_NUMERIC 区域。

str.format_map(mapping)

类似于 str.format(**mapping),不同之处在于 mapping 会被直接使用而不是复制到一个 dict。 适宜使用此方法的一个例子是当 mapping 为 dict 的子类的情况:

>>> class Default(dict):
...     def __missing__(self, key):
...         return key
...
>>> '{name} was born in {country}'.format_map(Default(name='Guido'))
'Guido was born in country'

3.2 新版功能.

str.index(sub[, start[, end]])

类似于 find(),但在找不到子类时会引发 ValueError

str.isalnum()

如果字符串中的所有字符都是字母或数字且至少有一个字符,则返回 True , 否则返回 False 。 如果 c.isalpha()c.isdecimal()c.isdigit() ,或 c.isnumeric() 之中有一个返回 True ,则字符c是字母或数字。

str.isalpha()

如果字符串中的所有字符都是字母,并且至少有一个字符,返回 True ,否则返回 False 。字母字符是指那些在 Unicode 字符数据库中定义为 “Letter” 的字符,即那些具有 “Lm”、”Lt”、”Lu”、”Ll” 或 “Lo” 之一的通用类别属性的字符。 注意,这与 Unicode 标准中定义的”字母”属性不同。

str.isascii()

如果字符串为空或字符串中的所有字符都是 ASCII ,返回 True ,否则返回 False 。ASCII 字符的码点范围是 U+0000-U+007F 。

3.7 新版功能.

str.isdecimal()

如果字符串中的所有字符都是十进制字符且该字符串至少有一个字符,则返回 True , 否则返回 False 。十进制字符指那些可以用来组成10进制数字的字符,例如 U+0660 ,即阿拉伯字母数字0 。 严格地讲,十进制字符是 Unicode 通用类别 “Nd” 中的一个字符。

str.isdigit()

如果字符串中的所有字符都是数字,并且至少有一个字符,返回 True ,否则返回 False 。 数字包括十进制字符和需要特殊处理的数字,如兼容性上标数字。这包括了不能用来组成 10 进制数的数字,如 Kharosthi 数。 严格地讲,数字是指属性值为 Numeric_Type=Digit 或 Numeric_Type=Decimal 的字符。

str.isidentifier()

如果字符串是有效的标识符,返回 True ,依据语言定义, 标识符和关键字 节。

调用 keyword.iskeyword() 来检测字符串 s 是否为保留标识符,例如 defclass

示例:

>>> from keyword import iskeyword
>>> 'hello'.isidentifier(), iskeyword('hello')
True, False
>>> 'def'.isidentifier(), iskeyword('def')
True, True

str.islower()

如果字符串中至少有一个区分大小写的字符 且此类字符均为小写则返回 True ,否则返回 False

str.isnumeric()

如果字符串中至少有一个字符且所有字符均为数值字符则返回 True ,否则返回 False 。 数值字符包括数字字符,以及所有在 Unicode 中设置了数值特性属性的字符,例如 U+2155, VULGAR FRACTION ONE FIFTH。 正式的定义为:数值字符就是具有特征属性值 Numeric_Type=Digit, Numeric_Type=Decimal 或 Numeric_Type=Numeric 的字符。

str.isprintable()

如果字符串中所有字符均为可打印字符或字符串为空则返回 True ,否则返回 False 。 不可打印字符是在 Unicode 字符数据库中被定义为 “Other” 或 “Separator” 的字符,例外情况是 ASCII 空格字符 (0x20) 被视作可打印字符。 (请注意在此语境下可打印字符是指当对一个字符串发起调用 repr() 时不必被转义的字符。 它们与字符串写入 sys.stdoutsys.stderr 时所需的处理无关。)

str.isspace()

如果字符串中只有空白字符且至少有一个字符则返回 True ,否则返回 False

空白 字符是指在 Unicode 字符数据库 中主要类别为 Zs (“Separator, space”) 或所属双向类为 WS, BS 的字符。

str.istitle()

如果字符串中至少有一个字符且为标题字符串则返回 True ,例如大写字符之后只能带非大写字符而小写字符必须有大写字符打头。 否则返回 False

str.isupper()

如果字符串中至少有一个区分大小写的字符 且此类字符均为大写则返回 True ,否则返回 False

>>> 'BANANA'.isupper()
True
>>> 'banana'.isupper()
False
>>> 'baNana'.isupper()
False
>>> ' '.isupper()
False

str.join(iterable)

返回一个由 iterable 中的字符串拼接而成的字符串。 如果 iterable 中存在任何非字符串值包括 bytes 对象则会引发 TypeError。 调用该方法的字符串将作为元素之间的分隔。

str.ljust(width[, fillchar])

返回长度为 width 的字符串,原字符串在其中靠左对齐。 使用指定的 fillchar 填充空位 (默认使用 ASCII 空格符)。 如果 width 小于等于 len(s) 则返回原字符串的副本。

str.lower()

返回原字符串的副本,其所有区分大小写的字符 均转换为小写。

所用转换小写算法的描述请参见 Unicode 标准的 3.13 节。

str.lstrip([chars])

返回原字符串的副本,移除其中的前导字符。 chars 参数为指定要移除字符的字符串。 如果省略或为 None,则 chars 参数默认移除空白符。 实际上 chars 参数并非指定单个前缀;而是会移除参数值的所有组合:

>>> '   spacious   '.lstrip()
'spacious   '
>>> 'www.example.com'.lstrip('cmowz.')
'example.com'

参见 str.removeprefix() ,该方法将删除单个前缀字符串,而不是全部给定集合中的字符。 例如:

>>> 'Arthur: three!'.lstrip('Arthur: ')
'ee!'
>>> 'Arthur: three!'.removeprefix('Arthur: ')
'three!'

static str.maketrans(x[, y[, z]])

此静态方法返回一个可供 str.translate() 使用的转换对照表。

如果只有一个参数,则它必须是一个将 Unicode 码位序号(整数)或字符(长度为 1 的字符串)映射到 Unicode 码位序号、(任意长度的)字符串或 None 的字典。 字符键将会被转换为码位序号。

如果有两个参数,则它们必须是两个长度相等的字符串,并且在结果字典中,x 中每个字符将被映射到 y 中相同位置的字符。 如果有第三个参数,它必须是一个字符串,其中的字符将在结果中被映射到 None

str.partition(sep)

sep 首次出现的位置拆分字符串,返回一个 3 元组,其中包含分隔符之前的部分、分隔符本身,以及分隔符之后的部分。 如果分隔符未找到,则返回的 3 元组中包含字符本身以及两个空字符串。

str.removeprefix(prefix, /)

如果字符串以 前缀 字符串开头,返回 string[len(prefix):] 。否则,返回原始字符串的副本:

>>> 'TestHook'.removeprefix('Test')
'Hook'
>>> 'BaseTestCase'.removeprefix('Test')
'BaseTestCase'

3.9 新版功能.

str.removesuffix(suffix, /)

如果字符串以 后缀 字符串结尾,并且 后缀 非空,返回 string[:-len(suffix)] 。否则,返回原始字符串的副本:

>>> 'MiscTests'.removesuffix('Tests')
'Misc'
>>> 'TmpDirMixin'.removesuffix('Tests')
'TmpDirMixin'

3.9 新版功能.

str.replace(old, new[, count])

返回字符串的副本,其中出现的所有子字符串 old 都将被替换为 new。 如果给出了可选参数 *count,则只替换前 *count 次出现。

str.rfind(sub[, start[, end]])

返回子字符串 sub 在字符串内被找到的最大(最右)索引,这样 sub 将包含在 s[start:end] 当中。 可选参数 startend 会被解读为切片表示法。 如果未找到则返回 -1

str.rindex(sub[, start[, end]])

类似于 rfind(),但在子字符串 sub 未找到时会引发 ValueError

str.rjust(width[, fillchar])

返回长度为 width 的字符串,原字符串在其中靠右对齐。 使用指定的 fillchar 填充空位 (默认使用 ASCII 空格符)。 如果 width 小于等于 len(s) 则返回原字符串的副本。

str.rpartition(sep)

sep 最后一次出现的位置拆分字符串,返回一个 3 元组,其中包含分隔符之前的部分、分隔符本身,以及分隔符之后的部分。 如果分隔符未找到,则返回的 3 元组中包含两个空字符串以及字符串本身。

str.rsplit(sep=None, maxsplit=- 1)

返回一个由字符串内单词组成的列表,使用 sep 作为分隔字符串。 如果给出了 maxsplit*,则最多进行 *maxsplit 次拆分,从 最右边 开始。 如果 sep 未指定或为 None,任何空白字符串都会被作为分隔符。 除了从右边开始拆分,rsplit() 的其他行为都类似于下文所述的 split()

str.rstrip([chars])

返回原字符串的副本,移除其中的末尾字符。 chars 参数为指定要移除字符的字符串。 如果省略或为 None,则 chars 参数默认移除空白符。 实际上 chars 参数并非指定单个后缀;而是会移除参数值的所有组合:

>>> '   spacious   '.rstrip()
'   spacious'
>>> 'mississippi'.rstrip('ipz')
'mississ'

要删除单个后缀字符串,而不是全部给定集合中的字符。 例如:

>>> 'Monty Python'.rstrip(' Python')
'M'
>>> 'Monty Python'.removesuffix(' Python')
'Monty'

str.split(sep=None, maxsplit=- 1)

返回一个由字符串内单词组成的列表,使用 sep 作为分隔字符串。 如果给出了 maxsplit*,则最多进行 *maxsplit 次拆分(因此,列表最多会有 maxsplit+1 个元素)。 如果 maxsplit 未指定或为 -1,则不限制拆分次数(进行所有可能的拆分)。

如果给出了 sep*,则连续的分隔符不会被组合在一起而是被视为分隔空字符串 (例如 '1,,2'.split(',') 将返回 ['1', '', '2'])。 *sep 参数可能由多个字符组成 (例如 '1<>2<>3'.split('<>') 将返回 ['1', '2', '3'])。 使用指定的分隔符拆分空字符串将返回 ['']

例如:

>>> '1,2,3'.split(',')
['1', '2', '3']
>>> '1,2,3'.split(',', maxsplit=1)
['1', '2,3']
>>> '1,2,,3,'.split(',')
['1', '2', '', '3', '']

如果 sep 未指定或为 None,则会应用另一种拆分算法:连续的空格会被视为单个分隔符,其结果将不包含开头或末尾的空字符串,如果字符串包含前缀或后缀空格的话。 因此,使用 None 拆分空字符串或仅包含空格的字符串将返回 []

例如:

>>> '1 2 3'.split()
['1', '2', '3']
>>> '1 2 3'.split(maxsplit=1)
['1', '2 3']
>>> '   1   2   3   '.split()
['1', '2', '3']

str.splitlines([keepends])

返回由原字符串中各行组成的列表,在行边界的位置拆分。 结果列表中不包含行边界,除非给出了 keepends 且为真值。

此方法会以下列行边界进行拆分。 特别地,行边界是 universal newlines 的一个超集。

表示符 描述
\n 换行
\r 回车
\r\n 回车 + 换行
\v\x0b 行制表符
\f\x0c 换表单
\x1c 文件分隔符
\x1d 组分隔符
\x1e 记录分隔符
\x85 下一行 (C1 控制码)
\u2028 行分隔符
\u2029 段分隔符

在 3.2 版更改: \v\f 被添加到行边界列表

例如:

>>> 'ab c\n\nde fg\rkl\r\n'.splitlines()
['ab c', '', 'de fg', 'kl']
>>> 'ab c\n\nde fg\rkl\r\n'.splitlines(keepends=True)
['ab c\n', '\n', 'de fg\r', 'kl\r\n']

不同于 split(),当给出了分隔字符串 sep 时,对于空字符串此方法将返回一个空列表,而末尾的换行不会令结果中增加额外的行:

>>> "".splitlines()
[]
>>> "One line\n".splitlines()
['One line']

作为比较,split('\n') 的结果为:

>>> ''.split('\n')
['']
>>> 'Two lines\n'.split('\n')
['Two lines', '']

str.startswith(prefix[, start[, end]])

如果字符串以指定的 prefix 开始则返回 True,否则返回 Falseprefix 也可以为由多个供查找的前缀构成的元组。 如果有可选项 start,将从所指定位置开始检查。 如果有可选项 end,将在所指定位置停止比较。

str.strip([chars])

返回原字符串的副本,移除其中的前导和末尾字符。 chars 参数为指定要移除字符的字符串。 如果省略或为 None,则 chars 参数默认移除空白符。 实际上 chars 参数并非指定单个前缀或后缀;而是会移除参数值的所有组合:

>>> '   spacious   '.strip()
'spacious'
>>> 'www.example.com'.strip('cmowz.')
'example'

最外侧的前导和末尾 chars 参数值将从字符串中移除。 开头端的字符的移除将在遇到一个未包含于 chars 所指定字符集的字符时停止。 类似的操作也将在结尾端发生。 例如:

>>> comment_string = '#....... Section 3.2.1 Issue #32 .......'
>>> comment_string.strip('.#! ')
'Section 3.2.1 Issue #32'

str.swapcase()

返回原字符串的副本,其中大写字符转换为小写,反之亦然。 请注意 s.swapcase().swapcase() == s 并不一定为真值。

str.title()

返回原字符串的标题版本,其中每个单词第一个字母为大写,其余字母为小写。

例如:

>>> 'Hello world'.title()
'Hello World'

该算法使用一种简单的与语言无关的定义,将连续的字母组合视为单词。 该定义在多数情况下都很有效,但它也意味着代表缩写形式与所有格的撇号也会成为单词边界,这可能导致不希望的结果:

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"

可以使用正则表达式来构建针对撇号的特别处理:

>>> import re
>>> def titlecase(s):
...     return re.sub(r"[A-Za-z]+('[A-Za-z]+)?",
...                   lambda mo: mo.group(0).capitalize(),
...                   s)
...
>>> titlecase("they're bill's friends.")
"They're Bill's Friends."

str.translate(table)

返回原字符串的副本,其中每个字符按给定的转换表进行映射。 转换表必须是一个使用 __getitem__() 来实现索引操作的对象,通常为 mapping 或 sequence。 当以 Unicode 码位序号(整数)为索引时,转换表对象可以做以下任何一种操作:返回 Unicode 序号或字符串,将字符映射为一个或多个字符;返回 None,将字符从结果字符串中删除;或引发 LookupError 异常,将字符映射为其自身。

你可以使用 str.maketrans() 基于不同格式的字符到字符映射来创建一个转换映射表。

str.upper()

返回原字符串的副本,其中所有区分大小写的字符 均转换为大写。 请注意如果 s 包含不区分大小写的字符或者如果结果字符的 Unicode 类别不是 “Lu” (Letter, uppercase) 而是 “Lt” (Letter, titlecase) 则 s.upper().isupper() 有可能为 False

所用转换大写算法的描述请参见 Unicode 标准的 3.13 节。

str.zfill(width)

返回原字符串的副本,在左边填充 ASCII '0' 数码使其长度变为 width*。 正负值前缀 ('+'/'-') 的处理方式是在正负符号 *之后 填充而非在之前。 如果 width 小于等于 len(s) 则返回原字符串的副本。

例如:

>>> "42".zfill(5)
'00042'
>>> "-42".zfill(5)
'-0042'

printf 风格的字符串格式化

注解

此处介绍的格式化操作具有多种怪异特性,可能导致许多常见错误(例如无法正确显示元组和字典)。 使用较新的 格式化字符串字面值,str.format() 接口或 模板字符串 有助于避免这样的错误。 这些替代方案中的每一种都更好地权衡并提供了简单、灵活以及可扩展性优势。

字符串具有一种特殊的内置操作:使用 % (取模) 运算符。 这也被称为字符串的 格式化插值 运算符。 对于 format % values (其中 format 为一个字符串),在 format 中的 % 转换标记符将被替换为零个或多个 values 条目。 其效果类似于在 C 语言中使用 sprintf()

如果 format 要求一个单独参数,则 values 可以为一个非元组对象。 否则的话,values 必须或者是一个包含项数与格式字符串中指定的转换符项数相同的元组,或者是一个单独映射对象(例如字典)。

转换标记符包含两个或更多字符并具有以下组成,且必须遵循此处规定的顺序:

  1. '%' 字符,用于标记转换符的起始。
  2. 映射键(可选),由加圆括号的字符序列组成 (例如 (somename))。
  3. 转换旗标(可选),用于影响某些转换类型的结果。
  4. 最小字段宽度(可选)。 如果指定为 '*' (星号),则实际宽度会从 values 元组的下一元素中读取,要转换的对象则为最小字段宽度和可选的精度之后的元素。
  5. 精度(可选),以在 '.' (点号) 之后加精度值的形式给出。 如果指定为 '*' (星号),则实际精度会从 values 元组的下一元素中读取,要转换的对象则为精度之后的元素。
  6. 长度修饰符(可选)。
  7. 转换类型。

当右边的参数为一个字典(或其他映射类型)时,字符串中的格式 必须 包含加圆括号的映射键,对应 '%' 字符之后字典中的每一项。 映射键将从映射中选取要格式化的值。 例如:

>>> print('%(language)s has %(number)03d quote types.' %
...       {'language': "Python", "number": 2})
Python has 002 quote types.

在此情况下格式中不能出现 * 标记符(因其需要一个序列类的参数列表)。

转换旗标为:

旗标 含意
‘#’ 值的转换将使用“替代形式”(具体定义见下文)。
‘0’ 转换将为数字值填充零字符。
‘-‘ 转换值将靠左对齐(如果同时给出 ‘0’ 转换,则会覆盖后者)。
‘ ‘ (空格) 符号位转换产生的正数(或空字符串)前将留出一个空格。
‘+’ 符号字符 (‘+’‘-‘) 将显示于转换结果的开头(会覆盖 “空格” 旗标)。

可以给出长度修饰符 (h, lL),但会被忽略,因为对 Python 来说没有必要 — 所以 %ld 等价于 %d

转换类型为:

转换符 含意 备注
‘d’ 有符号十进制整数。
‘i’ 有符号十进制整数。
‘o’ 有符号八进制数。 (1)
‘u’ 过时类型 — 等价于 ‘d’ (6)
‘x’ 有符号十六进制数(小写)。 (2)
‘X’ 有符号十六进制数(大写)。 (2)
‘e’ 浮点指数格式(小写)。 (3)
‘E’ 浮点指数格式(大写)。 (3)
‘f’ 浮点十进制格式。 (3)
‘F’ 浮点十进制格式。 (3)
‘g’ 浮点格式。 如果指数小于 -4 或不小于精度则使用小写指数格式,否则使用十进制格式。 (4)
‘G’ 浮点格式。 如果指数小于 -4 或不小于精度则使用大写指数格式,否则使用十进制格式。 (4)
‘c’ 单个字符(接受整数或单个字符的字符串)。
‘r’ 字符串(使用 repr() 转换任何 Python 对象)。 (5)
‘s’ 字符串(使用 str() 转换任何 Python 对象)。 (5)
‘a’ 字符串(使用 ascii() 转换任何 Python 对象)。 (5)
‘%’ 不转换参数,在结果中输出一个 ‘%’ 字符。

注释:

  1. 此替代形式会在第一个数码之前插入标示八进制数的前缀 ('0o')。

  2. 此替代形式会在第一个数码之前插入 '0x''0X' 前缀(取决于是使用 'x' 还是 'X' 格式)。

  3. 此替代形式总是会在结果中包含一个小数点,即使其后并没有数码。

    小数点后的数码位数由精度决定,默认为 6。

  4. 此替代形式总是会在结果中包含一个小数点,末尾各位的零不会如其他情况下那样被移除。

    小数点前后的有效数码位数由精度决定,默认为 6。

  5. 如果精度为 N,输出将截短为 N 个字符。

  6. 参见 PEP 237

由于 Python 字符串显式指明长度,%s 转换不会将 '\0' 视为字符串的结束。

在 3.1 版更改: 绝对值超过 1e50 的 %f 转换不会再被替换为 %g 转换。

二进制序列类型 —- bytes, bytearray, memoryview

操作二进制数据的核心内置类型是 bytesbytearray。 它们由 memoryview 提供支持,该对象使用 缓冲区协议 来访问其他二进制对象所在内存,不需要创建对象的副本。

array 模块支持高效地存储基本数据类型,例如 32 位整数和 IEEE754 双精度浮点值。

bytes 对象

bytes 对象是由单个字节构成的不可变序列。 由于许多主要二进制协议都基于 ASCII 文本编码,因此 bytes 对象提供了一些仅在处理 ASCII 兼容数据时可用,并且在许多特性上与字符串对象紧密相关的方法。

class bytes([source[, encoding[, errors]]])

首先,表示 bytes 字面值的语法与字符串字面值的大致相同,只是添加了一个 b 前缀:

  • 单引号: b'同样允许嵌入 "双" 引号'
  • 双引号: b"同样允许嵌入 '单' 引号"
  • 三重引号: b'''三重单引号''', b"""三重双引号"""

bytes 字面值中只允许 ASCII 字符(无论源代码声明的编码为何)。 任何超出 127 的二进制值必须使用相应的转义序列形式加入 bytes 字面值。

像字符串字面值一样,bytes 字面值也可以使用 r 前缀来禁用转义序列处理。

虽然 bytes 字面值和表示法是基于 ASCII 文本的,但 bytes 对象的行为实际上更像是不可变的整数序列,序列中的每个值的大小被限制为 0 <= x < 256 (如果违反此限制将引发 ValueError)。 这种限制是有意设计用以强调以下事实,虽然许多二进制格式都包含基于 ASCII 的元素,可以通过某些面向文本的算法进行有用的操作,但情况对于任意二进制数据来说通常却并非如此(盲目地将文本处理算法应用于不兼容 ASCII 的二进制数据格式往往将导致数据损坏)。

除了字面值形式,bytes 对象还可以通过其他几种方式来创建:

  • 指定长度的以零值填充的 bytes 对象: bytes(10)
  • 通过由整数组成的可迭代对象: bytes(range(20))
  • 通过缓冲区协议复制现有的二进制数据: bytes(obj)

由于两个十六进制数码精确对应一个字节,因此十六进制数是描述二进制数据的常用格式。 相应地,bytes 类型具有从此种格式读取数据的附加类方法:

  • classmethod fromhex(string)

    bytes 类方法返回一个解码给定字符串的 bytes 对象。 字符串必须由表示每个字节的两个十六进制数码构成,其中的 ASCII 空白符会被忽略。

    >>> bytes.fromhex('2Ef0 F1f2  ')
    b'.\xf0\xf1\xf2'

    在 3.7 版更改: bytes.fromhex() 现在会忽略所有 ASCII 空白符而不只是空格符。

存在一个反向转换函数,可以将 bytes 对象转换为对应的十六进制表示。

  • hex([sep[, bytes_per_sep]])

    返回一个字符串对象,该对象包含实例中每个字节的两个十六进制数字。

    >>> b'\xf0\xf1\xf2'.hex()
    'f0f1f2'

    如果你希望令十六进制数字符串更易读,你可以指定单个字符分隔符作为 sep 形参包含于输出中。 默认会放在每个字节之间。 第二个可选的 bytes_per_sep 形参控制间距。 正值会从右开始计算分隔符的位置,负值则是从左开始。

    >>> value = b'\xf0\xf1\xf2'
    >>> value.hex('-')
    'f0-f1-f2'
    >>> value.hex('_', 2)
    'f0_f1f2'
    >>> b'UUDDLRLRAB'.hex(' ', -4)
    '55554444 4c524c52 4142'

    3.5 新版功能.

    在 3.8 版更改: bytes.hex() 现在支持可选的 sepbytes_per_sep 形参以在十六进制输出的字节之间插入分隔符。

由于 bytes 对象是由整数构成的序列(类似于元组),因此对于一个 bytes 对象 bb[0] 将为一个整数,而 b[0:1] 将为一个长度为 1 的 bytes 对象。 (这与文本字符串不同,索引和切片所产生的将都是一个长度为 1 的字符串)。

bytes 对象的表示使用字面值格式 (b'...'),因为它通常都要比像 bytes([46, 46, 46]) 这样的格式更好用。 你总是可以使用 list(b) 将 bytes 对象转换为一个由整数构成的列表。

注解

针对 Python 2.x 用户的说明:在 Python 2.x 系列中,允许 8 位字符串( 2.x 所提供的最接近内置二进制数据类型的对象)与 Unicode 字符串进行各种隐式转换。 这是为了实现向下兼容的变通做法,以适应 Python 最初只支持 8 位文本而 Unicode 文本是后来才被加入这一事实。 在 Python 3.x 中,这些隐式转换已被取消 —— 8 位二进制数据与 Unicode 文本间的转换必须显式地进行,bytes 与字符串对象的比较结果将总是不相等。

bytearray 对象

bytearray 对象是 bytes 对象的可变对应物。

class bytearray([source[, encoding[, errors]]])

bytearray 对象没有专属的字面值语法,它们总是通过调用构造器来创建:

  • 创建一个空实例: bytearray()
  • 创建一个指定长度的以零值填充的实例: bytearray(10)
  • 通过由整数组成的可迭代对象: bytearray(range(20))
  • 通过缓冲区协议复制现有的二进制数据: bytearray(b'Hi!')

由于 bytearray 对象是可变的,该对象除了 bytes 和 bytearray 操作 中所描述的 bytes 和 bytearray 共有操作之外,还支持 可变 序列操作。

由于两个十六进制数码精确对应一个字节,因此十六进制数是描述二进制数据的常用格式。 相应地,bytearray 类型具有从此种格式读取数据的附加类方法:

  • classmethod fromhex(string)

    bytearray 类方法返回一个解码给定字符串的 bytearray 对象。 字符串必须由表示每个字节的两个十六进制数码构成,其中的 ASCII 空白符会被忽略。

    >>> bytearray.fromhex('2Ef0 F1f2  ')
    bytearray(b'.\xf0\xf1\xf2')

    在 3.7 版更改: bytearray.fromhex() 现在会忽略所有 ASCII 空白符而不只是空格符。

存在一个反向转换函数,可以将 bytearray 对象转换为对应的十六进制表示。

  • hex([sep[, bytes_per_sep]])

    返回一个字符串对象,该对象包含实例中每个字节的两个十六进制数字。

    >>> bytearray(b'\xf0\xf1\xf2').hex()
    'f0f1f2'

    3.5 新版功能.

    在 3.8 版更改: 与 bytes.hex() 相似, bytearray.hex() 现在支持可选的 sepbytes_per_sep 参数以在十六进制输出的字节之间插入分隔符。

由于 bytearray 对象是由整数构成的序列(类似于列表),因此对于一个 bytearray 对象 bb[0] 将为一个整数,而 b[0:1] 将为一个长度为 1 的 bytearray 对象。 (这与文本字符串不同,索引和切片所产生的将都是一个长度为 1 的字符串)。

bytearray 对象的表示使用 bytes 对象字面值格式 (bytearray(b'...')),因为它通常都要比 bytearray([46, 46, 46]) 这样的格式更好用。 你总是可以使用 list(b) 将 bytearray 对象转换为一个由整数构成的列表。

bytes 和 bytearray 操作

bytes 和 bytearray 对象都支持 通用 序列操作。 它们不仅能与相同类型的操作数,也能与任何 bytes-like object 进行互操作。 由于这样的灵活性,它们可以在操作中自由地混合而不会导致错误。 但是,操作结果的返回值类型可能取决于操作数的顺序。

注解

bytes 和 bytearray 对象的方法不接受字符串作为其参数,就像字符串的方法不接受 bytes 对象作为其参数一样。 例如,你必须使用以下写法:

a = "abc"
b = a.replace("a", "f")

和:

a = b"abc"
b = a.replace(b"a", b"f")

某些 bytes 和 bytearray 操作假定使用兼容 ASCII 的二进制格式,因此在处理任意二进数数据时应当避免使用。 这些限制会在下文中说明。

注解

使用这些基于 ASCII 的操作来处理未以基于 ASCII 的格式存储的二进制数据可能会导致数据损坏。

bytes 和 bytearray 对象的下列方法可以用于任意二进制数据。

bytes.count(sub[, start[, end]])

bytearray.count(sub[, start[, end]])

返回子序列 sub 在 [start, end*] 范围内非重叠出现的次数。 可选参数 *startend 会被解读为切片表示法。

要搜索的子序列可以是任意 bytes-like object 或是 0 至 255 范围内的整数。

在 3.3 版更改: 也接受 0 至 255 范围内的整数作为子序列。

bytes.removeprefix(prefix, /)

bytearray.removeprefix(prefix, /)

如果二进制数据以 前缀 字符串开头,返回 bytes[len(prefix):] 。否则,返回原始二进制数据的副本:

>>> b'TestHook'.removeprefix(b'Test')
b'Hook'
>>> b'BaseTestCase'.removeprefix(b'Test')
b'BaseTestCase'

前缀可以是任意 bytes-like object。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

3.9 新版功能.

bytes.removesuffix(suffix, /)

bytearray.removesuffix(suffix, /)

如果二进制数据以 后缀 字符串结尾,并且 后缀 非空,返回 bytes[:-len(suffix)] 。否则,返回原始二进制数据的副本:

>>> b'MiscTests'.removesuffix(b'Tests')
b'Misc'
>>> b'TmpDirMixin'.removesuffix(b'Tests')
b'TmpDirMixin'

后缀可以是任意 bytes-like object。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

3.9 新版功能.

bytes.decode(encoding=’utf-8’, errors=’strict’)

bytearray.decode(encoding=’utf-8’, errors=’strict’)

返回从给定 bytes 解码出来的字符串。 默认编码为 'utf-8'。 可以给出 errors 来设置不同的错误处理方案。 errors 的默认值为 'strict',表示编码错误会引发 UnicodeError。 其他可用的值为 'ignore', 'replace' 以及任何其他通过 codecs.register_error() 注册的名称。

By default, the errors argument is not checked for best performances, but only used at the first decoding error. Enable the Python Development Mode, or use a debug build to check errors.

注解

encoding 参数传给 str 允许直接解码任何 bytes-like object,无须创建临时的 bytes 或 bytearray 对象。

在 3.1 版更改: 加入了对关键字参数的支持。

在 3.9 版更改: The errors is now checked in development mode and in debug mode.

bytes.endswith(suffix[, start[, end]])

bytearray.endswith(suffix[, start[, end]])

如果二进制数据以指定的 suffix 结束则返回 True,否则返回 Falsesuffix 也可以为由多个供查找的后缀构成的元组。 如果有可选项 start,将从所指定位置开始检查。 如果有可选项 end,将在所指定位置停止比较。

要搜索的后缀可以是任意 bytes-like object。

bytes.find(sub[, start[, end]])

bytearray.find(sub[, start[, end]])

返回子序列 sub 在数据中被找到的最小索引,sub 包含于切片 s[start:end] 之内。 可选参数 startend 会被解读为切片表示法。 如果 sub 未被找到则返回 -1

要搜索的子序列可以是任意 bytes-like object 或是 0 至 255 范围内的整数。

注解

find() 方法应该只在你需要知道 sub 所在位置时使用。 要检查 sub 是否为子串,请使用 in 操作符:

>>> b'Py' in b'Python'
True

在 3.3 版更改: 也接受 0 至 255 范围内的整数作为子序列。

bytes.index(sub[, start[, end]])

bytearray.index(sub[, start[, end]])

类似于 find(),但在找不到子序列时会引发 ValueError

要搜索的子序列可以是任意 bytes-like object 或是 0 至 255 范围内的整数。

在 3.3 版更改: 也接受 0 至 255 范围内的整数作为子序列。

bytes.join(iterable)

bytearray.join(iterable)

返回一个由 iterable 中的二进制数据序列拼接而成的 bytes 或 bytearray 对象。 如果 iterable 中存在任何非 字节类对象 包括存在 str 对象值则会引发 TypeError。 提供该方法的 bytes 或 bytearray 对象的内容将作为元素之间的分隔。

static bytes.maketrans(from, to)

static bytearray.maketrans(from, to)

此静态方法返回一个可用于 bytes.translate() 的转换对照表,它将把 from 中的每个字符映射为 to 中相同位置上的字符;fromto 必须都是 字节类对象 并且具有相同的长度。

3.1 新版功能.

bytes.partition(sep)

bytearray.partition(sep)

sep 首次出现的位置拆分序列,返回一个 3 元组,其中包含分隔符之前的部分、分隔符本身或其 bytearray 副本,以及分隔符之后的部分。 如果分隔符未找到,则返回的 3 元组中包含原序列以及两个空的 bytes 或 bytearray 对象。

要搜索的分隔符可以是任意 bytes-like object。

bytes.replace(old, new[, count])

bytearray.replace(old, new[, count])

返回序列的副本,其中出现的所有子序列 old 都将被替换为 new。 如果给出了可选参数 *count,则只替换前 *count 次出现。

要搜索的子序列及其替换序列可以是任意 bytes-like object。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.rfind(sub[, start[, end]])

bytearray.rfind(sub[, start[, end]])

返回子序列 sub 在序列内被找到的最大(最右)索引,这样 sub 将包含在 s[start:end] 当中。 可选参数 startend 会被解读为切片表示法。 如果未找到则返回 -1

要搜索的子序列可以是任意 bytes-like object 或是 0 至 255 范围内的整数。

在 3.3 版更改: 也接受 0 至 255 范围内的整数作为子序列。

bytes.rindex(sub[, start[, end]])

bytearray.rindex(sub[, start[, end]])

类似于 rfind(),但在子序列 sub 未找到时会引发 ValueError

要搜索的子序列可以是任意 bytes-like object 或是 0 至 255 范围内的整数。

在 3.3 版更改: 也接受 0 至 255 范围内的整数作为子序列。

bytes.rpartition(sep)

bytearray.rpartition(sep)

sep 最后一次出现的位置拆分序列,返回一个 3 元组,其中包含分隔符之前的部分,分隔符本身或其 bytearray 副本,以及分隔符之后的部分。 如果分隔符未找到,则返回的 3 元组中包含两个空的 bytes 或 bytearray 对象以及原序列的副本。

要搜索的分隔符可以是任意 bytes-like object。

bytes.startswith(prefix[, start[, end]])

bytearray.startswith(prefix[, start[, end]])

如果二进制数据以指定的 prefix 开头则返回 True,否则返回 Falseprefix 也可以为由多个供查找的前缀构成的元组。 如果有可选项 start,将从所指定位置开始检查。 如果有可选项 end,将在所指定位置停止比较。

要搜索的前缀可以是任意 bytes-like object。

bytes.translate(table, /, delete=b’’)

bytearray.translate(table, /, delete=b’’)

返回原 bytes 或 bytearray 对象的副本,移除其中所有在可选参数 delete 中出现的 bytes,其余 bytes 将通过给定的转换表进行映射,该转换表必须是长度为 256 的 bytes 对象。

你可以使用 bytes.maketrans() 方法来创建转换表。

对于仅需移除字符的转换,请将 table 参数设为 None:

>>> b'read this short text'.translate(None, b'aeiou')
b'rd ths shrt txt'

在 3.6 版更改: 现在支持将 delete 作为关键字参数。

以下 bytes 和 bytearray 对象的方法的默认行为会假定使用兼容 ASCII 的二进制格式,但通过传入适当的参数仍然可用于任意二进制数据。 请注意本小节中所有的 bytearray 方法都 不是 原地执行操作,而是会产生新的对象。

bytes.center(width[, fillbyte])

bytearray.center(width[, fillbyte])

返回原对象的副本,在长度为 width 的序列内居中,使用指定的 fillbyte 填充两边的空位(默认使用 ASCII 空格符)。 对于 bytes 对象,如果 width 小于等于 len(s) 则返回原序列的副本。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.ljust(width[, fillbyte])

bytearray.ljust(width[, fillbyte])

返回原对象的副本,在长度为 width 的序列中靠左对齐。 使用指定的 fillbyte 填充空位(默认使用 ASCII 空格符)。 对于 bytes 对象,如果 width 小于等于 len(s) 则返回原序列的副本。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.lstrip([chars])

bytearray.lstrip([chars])

返回原序列的副本,移除指定的前导字节。 chars 参数为指定要移除字节值集合的二进制序列 —— 这个名称表明此方法通常是用于 ASCII 字符。 如果省略或为 None,则 chars 参数默认移除 ASCII 空白符。 chars 参数并非指定单个前缀;而是会移除参数值的所有组合:

>>> b'   spacious   '.lstrip()
b'spacious   '
>>> b'www.example.com'.lstrip(b'cmowz.')
b'example.com'

要移除的二进制序列可以是任意 bytes-like object 。 要删除单个前缀字符串,而不是全部给定集合中的字符,请参见 str.removeprefix() 方法。 例如:

>>> b'Arthur: three!'.lstrip(b'Arthur: ')
b'ee!'
>>> b'Arthur: three!'.removeprefix(b'Arthur: ')
b'three!'

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.rjust(width[, fillbyte])

bytearray.rjust(width[, fillbyte])

返回原对象的副本,在长度为 width 的序列中靠右对齐。 使用指定的 fillbyte 填充空位(默认使用 ASCII 空格符)。 对于 bytes 对象,如果 width 小于等于 len(s) 则返回原序列的副本。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.rsplit(sep=None, maxsplit=- 1)

bytearray.rsplit(sep=None, maxsplit=- 1)

将二进制序列拆分为相同类型的子序列,使用 sep 作为分隔符。 如果给出了 maxsplit*,则最多进行 *maxsplit 次拆分,从 最右边 开始。 如果 sep 未指定或为 None,任何只包含 ASCII 空白符的子序列都会被作为分隔符。 除了从右边开始拆分,rsplit() 的其他行为都类似于下文所述的 split()

bytes.rstrip([chars])

bytearray.rstrip([chars])

返回原序列的副本,移除指定的末尾字节。 chars 参数为指定要移除字节值集合的二进制序列 —— 这个名称表明此方法通常是用于 ASCII 字符。 如果省略或为 None,则 chars 参数默认移除 ASCII 空白符。 chars 参数并非指定单个后缀;而是会移除参数值的所有组合:

>>> b'   spacious   '.rstrip()
b'   spacious'
>>> b'mississippi'.rstrip(b'ipz')
b'mississ'

要移除的二进制序列可以是任意 bytes-like object 。 要删除单个后缀字符串,而不是全部给定集合中的字符,请参见 str.removesuffix() 方法。 例如:

>>> b'Monty Python'.rstrip(b' Python')
b'M'
>>> b'Monty Python'.removesuffix(b' Python')
b'Monty'

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.split(sep=None, maxsplit=- 1)

bytearray.split(sep=None, maxsplit=- 1)

将二进制序列拆分为相同类型的子序列,使用 sep 作为分隔符。 如果给出了 maxsplit 且非负值,则最多进行 maxsplit 次拆分(因此,列表最多会有 maxsplit+1 个元素)。 如果 maxsplit 未指定或为 -1,则不限制拆分次数(进行所有可能的拆分)。

如果给出了 sep*,则连续的分隔符不会被组合在一起而是被视为分隔空子序列 (例如 b'1,,2'.split(b',') 将返回 [b'1', b'', b'2'])。 *sep 参数可能为一个多字节序列 (例如 b'1<>2<>3'.split(b'<>') 将返回 [b'1', b'2', b'3'])。 使用指定的分隔符拆分空序列将返回 [b''][bytearray(b'')],具体取决于被拆分对象的类型。 sep 参数可以是任意 bytes-like object。

例如:

>>> b'1,2,3'.split(b',')
[b'1', b'2', b'3']
>>> b'1,2,3'.split(b',', maxsplit=1)
[b'1', b'2,3']
>>> b'1,2,,3,'.split(b',')
[b'1', b'2', b'', b'3', b'']

如果 sep 未指定或为 None,则会应用另一种拆分算法:连续的 ASCII 空白符会被视为单个分隔符,其结果将不包含序列开头或末尾的空白符。 因此,在不指定分隔符的情况下对空序列或仅包含 ASCII 空白符的序列进行拆分将返回 []

例如:

>>> b'1 2 3'.split()
[b'1', b'2', b'3']
>>> b'1 2 3'.split(maxsplit=1)
[b'1', b'2 3']
>>> b'   1   2   3   '.split()
[b'1', b'2', b'3']

bytes.strip([chars])

bytearray.strip([chars])

返回原序列的副本,移除指定的开头和末尾字节。 chars 参数为指定要移除字节值集合的二进制序列 —— 这个名称表明此方法通常是用于 ASCII 字符。 如果省略或为 None,则 chars 参数默认移除 ASCII 空白符。 chars 参数并非指定单个前缀或后缀;而是会移除参数值的所有组合:

>>> b'   spacious   '.strip()
b'spacious'
>>> b'www.example.com'.strip(b'cmowz.')
b'example'

要移除的字节值二进制序列可以是任意 bytes-like object。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

以下 bytes 和 bytearray 对象的方法会假定使用兼容 ASCII 的二进制格式,不应当被应用于任意二进制数据。 请注意本小节中所有的 bytearray 方法都 不是 原地执行操作,而是会产生新的对象。

bytes.capitalize()

bytearray.capitalize()

返回原序列的副本,其中每个字节将都将被解读为一个 ASCII 字符,并且第一个字节的字符大写而其余的小写。 非 ASCII 字节值将保持原样不变。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.expandtabs(tabsize=8)

bytearray.expandtabs(tabsize=8)

返回序列的副本,其中所有的 ASCII 制表符会由一个或多个 ASCII 空格替换,具体取决于当前列位置和给定的制表符宽度。 每 tabsize 个字节设为一个制表位(默认值 8 时设定的制表位在列 0, 8, 16 依次类推)。 要展开序列,当前列位置将被设为零并逐一检查序列中的每个字节。 如果字节为 ASCII 制表符 (b'\t'),则并在结果中插入一个或多个空格符,直到当前列等于下一个制表位。 (制表符本身不会被复制。) 如果当前字节为 ASCII 换行符 (b'\n') 或回车符 (b'\r'),它会被复制并将当前列重设为零。 任何其他字节会被不加修改地复制并将当前列加一,不论该字节值在被打印时会如何显示:

>>> b'01\t012\t0123\t01234'.expandtabs()
b'01      012     0123    01234'
>>> b'01\t012\t0123\t01234'.expandtabs(4)
b'01  012 0123    01234'

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.isalnum()

bytearray.isalnum()

如果序列中所有字节都是字母类 ASCII 字符或 ASCII 十进制数码并且序列非空则返回 True ,否则返回 False 。 字母类 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。 ASCII 十进制数码就是字节值包含在序列 b'0123456789' 中的字符。

例如:

>>> b'ABCabc1'.isalnum()
True
>>> b'ABC abc1'.isalnum()
False

bytes.isalpha()

bytearray.isalpha()

如果序列中所有字节都是字母类 ASCII 字符并且序列不非空则返回 True ,否则返回 False 。 字母类 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。

例如:

>>> b'ABCabc'.isalpha()
True
>>> b'ABCabc1'.isalpha()
False

bytes.isascii()

bytearray.isascii()

如果序列为空或序列中所有字节都是 ASCII 字节则返回 True ,否则返回 False 。 ASCII 字节的取值范围是 0-0x7F。

3.7 新版功能.

bytes.isdigit()

bytearray.isdigit()

如果序列中所有字节都是 ASCII 十进制数码并且序列非空则返回 True ,否则返回 False 。 ASCII 十进制数码就是字节值包含在序列 b'0123456789' 中的字符。

例如:

>>> b'1234'.isdigit()
True
>>> b'1.23'.isdigit()
False

bytes.islower()

bytearray.islower()

如果序列中至少有一个小写的 ASCII 字符并且没有大写的 ASCII 字符则返回 True ,否则返回 False

例如:

>>> b'hello world'.islower()
True
>>> b'Hello world'.islower()
False

小写 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyz' 中的字符。 大写 ASCII 字符就是字节值包含在序列 b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。

bytes.isspace()

bytearray.isspace()

如果序列中所有字节都是 ASCII 空白符并且序列非空则返回 True ,否则返回 False 。 ASCII 空白符就是字节值包含在序列 b' \t\n\r\x0b\f' (空格, 制表, 换行, 回车, 垂直制表, 进纸) 中的字符。

bytes.istitle()

bytearray.istitle()

如果序列为 ASCII 标题大小写形式并且序列非空则返回 True ,否则返回 False

例如:

>>> b'Hello World'.istitle()
True
>>> b'Hello world'.istitle()
False

bytes.isupper()

bytearray.isupper()

如果序列中至少有一个大写字母 ASCII 字符并且没有小写 ASCII 字符则返回 True ,否则返回 False

例如:

>>> b'HELLO WORLD'.isupper()
True
>>> b'Hello world'.isupper()
False

小写 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyz' 中的字符。 大写 ASCII 字符就是字节值包含在序列 b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。

bytes.lower()

bytearray.lower()

返回原序列的副本,其所有大写 ASCII 字符均转换为对应的小写形式。

例如:

>>> b'Hello World'.lower()
b'hello world'

小写 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyz' 中的字符。 大写 ASCII 字符就是字节值包含在序列 b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.splitlines(keepends=False)

bytearray.splitlines(keepends=False)

返回由原二进制序列中各行组成的列表,在 ASCII 行边界符的位置拆分。 此方法使用 universal newlines 方式来分行。 结果列表中不包含换行符,除非给出了 keepends 且为真值。

例如:

>>> b'ab c\n\nde fg\rkl\r\n'.splitlines()
[b'ab c', b'', b'de fg', b'kl']
>>> b'ab c\n\nde fg\rkl\r\n'.splitlines(keepends=True)
[b'ab c\n', b'\n', b'de fg\r', b'kl\r\n']

不同于 split(),当给出了分隔符 sep 时,对于空字符串此方法将返回一个空列表,而末尾的换行不会令结果中增加额外的行:

>>> b"".split(b'\n'), b"Two lines\n".split(b'\n')
([b''], [b'Two lines', b''])
>>> b"".splitlines(), b"One line\n".splitlines()
([], [b'One line'])

bytes.swapcase()

bytearray.swapcase()

返回原序列的副本,其所有小写 ASCII 字符均转换为对应的大写形式,反之亦反。

例如:

>>> b'Hello World'.swapcase()
b'hELLO wORLD'

小写 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyz' 中的字符。 大写 ASCII 字符就是字节值包含在序列 b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。

不同于 str.swapcase(),在些二进制版本下 bin.swapcase().swapcase() == bin 总是成立。 大小写转换在 ASCII 中是对称的,即使其对于任意 Unicode 码位来说并不总是成立。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.title()

bytearray.title()

返回原二进制序列的标题版本,其中每个单词以一个大写 ASCII 字符为开头,其余字母为小写。 不区别大小写的字节值将保持原样不变。

例如:

>>> b'Hello world'.title()
b'Hello World'

小写 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyz' 中的字符。 大写 ASCII 字符就是字节值包含在序列 b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。 所有其他字节值都不区分大小写。

该算法使用一种简单的与语言无关的定义,将连续的字母组合视为单词。 该定义在多数情况下都很有效,但它也意味着代表缩写形式与所有格的撇号也会成为单词边界,这可能导致不希望的结果:

>>> b"they're bill's friends from the UK".title()
b"They'Re Bill'S Friends From The Uk"

可以使用正则表达式来构建针对撇号的特别处理:

>>> import re
>>> def titlecase(s):
...     return re.sub(rb"[A-Za-z]+('[A-Za-z]+)?",
...                   lambda mo: mo.group(0)[0:1].upper() +
...                              mo.group(0)[1:].lower(),
...                   s)
...
>>> titlecase(b"they're bill's friends.")
b"They're Bill's Friends."

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.upper()

bytearray.upper()

返回原序列的副本,其所有小写 ASCII 字符均转换为对应的大写形式。

例如:

>>> b'Hello World'.upper()
b'HELLO WORLD'

小写 ASCII 字符就是字节值包含在序列 b'abcdefghijklmnopqrstuvwxyz' 中的字符。 大写 ASCII 字符就是字节值包含在序列 b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 中的字符。

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

bytes.zfill(width)

bytearray.zfill(width)

返回原序列的副本,在左边填充 b'0' 数码使序列长度为 width*。 正负值前缀 (b'+'/ b'-') 的处理方式是在正负符号 *之后 填充而非在之前。 对于 bytes 对象,如果 width 小于等于 len(seq) 则返回原序列。

例如:

>>> b"42".zfill(5)
b'00042'
>>> b"-42".zfill(5)
b'-0042'

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

printf 风格的字节串格式化

注解

此处介绍的格式化操作具有多种怪异特性,可能导致许多常见错误(例如无法正确显示元组和字典)。 如果要打印的值可能为元组或字典,请将其放入一个元组中。

字节串对象 (bytes/bytearray) 具有一种特殊的内置操作:使用 % (取模) 运算符。 这也被称为字节串的 格式化插值 运算符。 对于 format % values (其中 format 为一个字节串对象),在 format 中的 % 转换标记符将被替换为零个或多个 values 条目。 其效果类似于在 C 语言中使用 sprintf()

如果 format 要求一个单独参数,则 values 可以为一个非元组对象。否则的话,values 必须或是是一个包含项数与格式字节串对象中指定的转换符项数相同的元组,或者是一个单独的映射对象(例如元组)。

转换标记符包含两个或更多字符并具有以下组成,且必须遵循此处规定的顺序:

  1. '%' 字符,用于标记转换符的起始。
  2. 映射键(可选),由加圆括号的字符序列组成 (例如 (somename))。
  3. 转换旗标(可选),用于影响某些转换类型的结果。
  4. 最小字段宽度(可选)。 如果指定为 '*' (星号),则实际宽度会从 values 元组的下一元素中读取,要转换的对象则为最小字段宽度和可选的精度之后的元素。
  5. 精度(可选),以在 '.' (点号) 之后加精度值的形式给出。 如果指定为 '*' (星号),则实际精度会从 values 元组的下一元素中读取,要转换的对象则为精度之后的元素。
  6. 长度修饰符(可选)。
  7. 转换类型。

当右边的参数为一个字典(或其他映射类型)时,字节串对象中的格式 必须 包含加圆括号的映射键,对应 '%' 字符之后字典中的每一项。 映射键将从映射中选取要格式化的值。 例如:

>>> print(b'%(language)s has %(number)03d quote types.' %
...       {b'language': b"Python", b"number": 2})
b'Python has 002 quote types.'

在此情况下格式中不能出现 * 标记符(因其需要一个序列类的参数列表)。

转换旗标为:

旗标 含意
‘#’ 值的转换将使用“替代形式”(具体定义见下文)。
‘0’ 转换将为数字值填充零字符。
‘-‘ 转换值将靠左对齐(如果同时给出 ‘0’ 转换,则会覆盖后者)。
‘ ‘ (空格) 符号位转换产生的正数(或空字符串)前将留出一个空格。
‘+’ 符号字符 (‘+’‘-‘) 将显示于转换结果的开头(会覆盖 “空格” 旗标)。

可以给出长度修饰符 (h, lL),但会被忽略,因为对 Python 来说没有必要 — 所以 %ld 等价于 %d

转换类型为:

转换符 含意 备注
‘d’ 有符号十进制整数。
‘i’ 有符号十进制整数。
‘o’ 有符号八进制数。 (1)
‘u’ 过时类型 — 等价于 ‘d’ (8)
‘x’ 有符号十六进制数(小写)。 (2)
‘X’ 有符号十六进制数(大写)。 (2)
‘e’ 浮点指数格式(小写)。 (3)
‘E’ 浮点指数格式(大写)。 (3)
‘f’ 浮点十进制格式。 (3)
‘F’ 浮点十进制格式。 (3)
‘g’ 浮点格式。 如果指数小于 -4 或不小于精度则使用小写指数格式,否则使用十进制格式。 (4)
‘G’ 浮点格式。 如果指数小于 -4 或不小于精度则使用大写指数格式,否则使用十进制格式。 (4)
‘c’ 单个字节(接受整数或单个字节对象)。
‘b’ 字节串(任何遵循 缓冲区协议 或是具有 **bytes**() 的对象)。 (5)
‘s’ ‘s’‘b’ 的一个别名,只应当在基于 Python2/3 的代码中使用。 (6)
‘a’ 字节串(使用 repr(obj).encode(‘ascii’,’backslashreplace) 转换任何 Python 对象)。 (5)
‘r’ ‘r’‘a’ 的一个别名,只应当在基于 Python2/3 的代码中使用。 (7)
‘%’ 不转换参数,在结果中输出一个 ‘%’ 字符。

注释:

  1. 此替代形式会在第一个数码之前插入标示八进制数的前缀 ('0o')。

  2. 此替代形式会在第一个数码之前插入 '0x''0X' 前缀(取决于是使用 'x' 还是 'X' 格式)。

  3. 此替代形式总是会在结果中包含一个小数点,即使其后并没有数码。

    小数点后的数码位数由精度决定,默认为 6。

  4. 此替代形式总是会在结果中包含一个小数点,末尾各位的零不会如其他情况下那样被移除。

    小数点前后的有效数码位数由精度决定,默认为 6。

  5. 如果精度为 N,输出将截短为 N 个字符。

  6. b'%s' 已弃用,但在 3.x 系列中将不会被移除。

  7. b'%r' 已弃用,但在 3.x 系列中将不会被移除。

  8. 参见 PEP 237

注解

此方法的 bytearray 版本 并非 原地操作 —— 它总是产生一个新对象,即便没有做任何改变。

参见

PEP 461 - 为 bytes 和 bytearray 添加 % 格式化

3.5 新版功能.

内存视图

memoryview 对象允许 Python 代码访问一个对象的内部数据,只要该对象支持 缓冲区协议 而无需进行拷贝。

class memoryview(object)

创建一个引用 objectmemoryviewobject 必须支持缓冲区协议。支持缓冲区协议的内置对象有 bytesbytearray

memoryview元素 的概念, 元素 指由原始 object 处理的原子内存单元。对于许多简单的类型,如 bytesbytearray ,一个元素是一个字节,但其他类型,如 array.array 可能有更大的元素。

len(view)tolist 的长度相等。 如果 view.ndim = 0,则其长度为 1。 如果 view.ndim = 1,则其长度等于 view 中元素的数量。 对于更高的维度,其长度等于表示 view 的嵌套列表的长度。 itemsize 属性可向你给出单个元素所占的字节数。

memoryview 支持通过切片和索引访问其元素。 一维切片的结果将是一个子视图:

>>> v = memoryview(b'abcefg')
>>> v[1]
98
>>> v[-1]
103
>>> v[1:4]
<memory at 0x7f3ddc9f4350>
>>> bytes(v[1:4])
b'bce'

如果 format 是一个来自于 struct 模块的原生格式说明符,则也支持使用整数或由整数构成的元组进行索引,并返回具有正确类型的单个 元素*。 一维内存视图可以使用一个整数或由一个整数构成的元组进行索引。 多维内存视图可以使用由恰好 *ndim 个整数构成的元素进行索引,ndim 即其维度。 零维内存视图可以使用空元组进行索引。

这里是一个使用非字节格式的例子:

>>> import array
>>> a = array.array('l', [-11111111, 22222222, -33333333, 44444444])
>>> m = memoryview(a)
>>> m[0]
-11111111
>>> m[-1]
44444444
>>> m[::2].tolist()
[-11111111, -33333333]

如果下层对象是可写的,则内存视图支持一维切片赋值。 改变大小则不被允许:

>>> data = bytearray(b'abcefg')
>>> v = memoryview(data)
>>> v.readonly
False
>>> v[0] = ord(b'z')
>>> data
bytearray(b'zbcefg')
>>> v[1:4] = b'123'
>>> data
bytearray(b'z123fg')
>>> v[2:3] = b'spam'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: memoryview assignment: lvalue and rvalue have different structures
>>> v[2:6] = b'spam'
>>> data
bytearray(b'z1spam')

由带有格式符号 ‘B’, ‘b’ 或 ‘c’ 的可哈希(只读)类型构成的一维内存视图同样是可哈希的。 哈希定义为 hash(m) == hash(m.tobytes()):

>>> v = memoryview(b'abcefg')
>>> hash(v) == hash(b'abcefg')
True
>>> hash(v[2:4]) == hash(b'ce')
True
>>> hash(v[::-2]) == hash(b'abcefg'[::-2])
True

在 3.3 版更改: 一维内存视图现在可以被切片。 带有格式符号 ‘B’, ‘b’ 或 ‘c’ 的一维内存视图现在是可哈希的。

在 3.4 版更改: 内存视图现在会自动注册为 collections.abc.Sequence

在 3.5 版更改: 内存视图现在可使用整数元组进行索引。

memoryview 具有以下一些方法:

  • __eq__(exporter)

    memoryview 与 PEP 3118 中的导出器这两者如果形状相同,并且如果当使用 struct 语法解读操作数的相应格式代码时所有对应值都相同,则它们就是等价的。

    对于 tolist() 当前所支持的 struct 格式字符串子集,如果 v.tolist() == w.tolist()vw 相等:

    >>> import array
    >>> a = array.array('I', [1, 2, 3, 4, 5])
    >>> b = array.array('d', [1.0, 2.0, 3.0, 4.0, 5.0])
    >>> c = array.array('b', [5, 3, 1])
    >>> x = memoryview(a)
    >>> y = memoryview(b)
    >>> x == a == y == b
    True
    >>> x.tolist() == a.tolist() == y.tolist() == b.tolist()
    True
    >>> z = y[::-2]
    >>> z == c
    True
    >>> z.tolist() == c.tolist()
    True

    如果两边的格式字符串都不被 struct 模块所支持,则两对象比较结果总是不相等(即使格式字符串和缓冲区内容相同):

    >>> from ctypes import BigEndianStructure, c_long
    >>> class BEPoint(BigEndianStructure):
    ...     _fields_ = [("x", c_long), ("y", c_long)]
    ...
    >>> point = BEPoint(100, 200)
    >>> a = memoryview(point)
    >>> b = memoryview(point)
    >>> a == point
    False
    >>> a == b
    False

    请注意,与浮点数的情况一样,对于内存视图对象来说,v is w并不 意味着 v == w

    在 3.3 版更改: 之前的版本比较原始内存时会忽略条目的格式与逻辑数组结构。

  • tobytes(order=None)

    将缓冲区中的数据作为字节串返回。 这相当于在内存视图上调用 bytes 构造器。

    >>> m = memoryview(b"abc")
    >>> m.tobytes()
    b'abc'
    >>> bytes(m)
    b'abc'

    对于非连续数组,结果等于平面化表示的列表,其中所有元素都转换为字节串。 tobytes() 支持所有格式字符串,不符合 struct 模块语法的那些也包括在内。

    3.8 新版功能: order 可以为 {‘C’, ‘F’, ‘A’}。 当 order 为 ‘C’ 或 ‘F’ 时,原始数组的数据会被转换至 C 或 Fortran 顺序。 对于连续视图,’A’ 会返回物理内存的精确副本。 特别地,内存中的 Fortran 顺序会被保留。对于非连续视图,数据会先被转换为 C 形式。 order=Noneorder=’C’ 是相同的。

  • hex([sep[, bytes_per_sep]])

    返回一个字符串对象,其中分别以两个十六进制数码表示缓冲区里的每个字节。

    >>> m = memoryview(b"abc")
    >>> m.hex()
    '616263'

    3.5 新版功能.

    在 3.8 版更改: 与 bytes.hex() 相似, memoryview.hex() 现在支持可选的 sepbytes_per_sep 参数以在十六进制输出的字节之间插入分隔符。

  • tolist()

    将缓冲区内的数据以一个元素列表的形式返回。

    >>> memoryview(b'abc').tolist()
    [97, 98, 99]
    >>> import array
    >>> a = array.array('d', [1.1, 2.2, 3.3])
    >>> m = memoryview(a)
    >>> m.tolist()
    [1.1, 2.2, 3.3]

    在 3.3 版更改: tolist() 现在支持 struct 模块语法中的所有单字符原生格式以及多维表示形式。

  • toreadonly()

    返回 memoryview 对象的只读版本。 原始的 memoryview 对象不会被改变。

    >>> m = memoryview(bytearray(b'abc'))
    >>> mm = m.toreadonly()
    >>> mm.tolist()
    [89, 98, 99]
    >>> mm[0] = 42
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: cannot modify read-only memory
    >>> m[0] = 43
    >>> mm.tolist()
    [43, 98, 99]

    3.8 新版功能.

  • release()

    释放由内存视图对象所公开的底层缓冲区。 许多对象在被视图所获取时都会采取特殊动作(例如,bytearray 将会暂时禁止调整大小);因此,调用 release() 可以方便地尽早去除这些限制(并释放任何多余的资源)。

    在此方法被调用后,任何对视图的进一步操作将引发 ValueError (release() 本身除外,它可以被多次调用):

    >>> m = memoryview(b'abc')
    >>> m.release()
    >>> m[0]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: operation forbidden on released memoryview object

    使用 with 语句,可以通过上下文管理协议达到类似的效果:

    >>> with memoryview(b'abc') as m:
    ...     m[0]
    ...
    97
    >>> m[0]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: operation forbidden on released memoryview object

    3.2 新版功能.

  • cast(format[, shape])

    将内存视图转化为新的格式或形状。 shape 默认为 [byte_length//new_itemsize],这意味着结果视图将是一维的。 返回值是一个新的内存视图,但缓冲区本身不会被复制。 支持的转化有 1D -> C-contiguous 和 C-contiguous -> 1D。

    目标格式仅限于 struct 语法中的单一元素原生格式。 其中一种格式必须为字节格式 (‘B’, ‘b’ 或 ‘c’)。 结果的字节长度必须与原始长度相同。

    将 1D/long 转换为 1D/unsigned bytes:

    >>> import array
    >>> a = array.array('l', [1,2,3])
    >>> x = memoryview(a)
    >>> x.format
    'l'
    >>> x.itemsize
    8
    >>> len(x)
    3
    >>> x.nbytes
    24
    >>> y = x.cast('B')
    >>> y.format
    'B'
    >>> y.itemsize
    1
    >>> len(y)
    24
    >>> y.nbytes
    24

    将 1D/unsigned bytes 转换为 1D/char:

    >>> b = bytearray(b'zyz')
    >>> x = memoryview(b)
    >>> x[0] = b'a'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: memoryview: invalid value for format "B"
    >>> y = x.cast('c')
    >>> y[0] = b'a'
    >>> b
    bytearray(b'ayz')

    将 1D/bytes 转换为 3D/ints 再转换为 1D/signed char:

    >>> import struct
    >>> buf = struct.pack("i"*12, *list(range(12)))
    >>> x = memoryview(buf)
    >>> y = x.cast('i', shape=[2,2,3])
    >>> y.tolist()
    [[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]]
    >>> y.format
    'i'
    >>> y.itemsize
    4
    >>> len(y)
    2
    >>> y.nbytes
    48
    >>> z = y.cast('b')
    >>> z.format
    'b'
    >>> z.itemsize
    1
    >>> len(z)
    48
    >>> z.nbytes
    48

    将 1D/unsigned long 转换为 2D/unsigned long:

    >>> buf = struct.pack("L"*6, *list(range(6)))
    >>> x = memoryview(buf)
    >>> y = x.cast('L', shape=[2,3])
    >>> len(y)
    2
    >>> y.nbytes
    48
    >>> y.tolist()
    [[0, 1, 2], [3, 4, 5]]

    3.3 新版功能.

    在 3.5 版更改: 当转换为字节视图时,源格式将不再受限。

还存在一些可用的只读属性:

  • obj

    内存视图的下层对象:

    >>> b  = bytearray(b'xyz')
    >>> m = memoryview(b)
    >>> m.obj is b
    True

    3.3 新版功能.

  • nbytes

    nbytes == product(shape) * itemsize == len(m.tobytes())。 这是数组在连续表示时将会占用的空间总字节数。 它不一定等于 len(m):

    >>> import array
    >>> a = array.array('i', [1,2,3,4,5])
    >>> m = memoryview(a)
    >>> len(m)
    5
    >>> m.nbytes
    20
    >>> y = m[::2]
    >>> len(y)
    3
    >>> y.nbytes
    12
    >>> len(y.tobytes())
    12

    多维数组:

    >>> import struct
    >>> buf = struct.pack("d"*12, *[1.5*x for x in range(12)])
    >>> x = memoryview(buf)
    >>> y = x.cast('d', shape=[3,4])
    >>> y.tolist()
    [[0.0, 1.5, 3.0, 4.5], [6.0, 7.5, 9.0, 10.5], [12.0, 13.5, 15.0, 16.5]]
    >>> len(y)
    3
    >>> y.nbytes
    96

    3.3 新版功能.

  • readonly

    一个表明内存是否只读的布尔值。

  • format

    一个字符串,包含视图中每个元素的格式(表示为 struct 模块样式)。 内存视图可以从具有任意格式字符串的导出器创建,但某些方法 (例如 tolist()) 仅限于原生的单元素格式。

    在 3.3 版更改: 格式 'B' 现在会按照 struct 模块语法来处理。 这意味着 memoryview(b'abc')[0] == b'abc'[0] == 97

  • itemsize

    memoryview 中每个元素以字节表示的大小:

    >>> import array, struct
    >>> m = memoryview(array.array('H', [32000, 32001, 32002]))
    >>> m.itemsize
    2
    >>> m[0]
    32000
    >>> struct.calcsize('H') == m.itemsize
    True
  • ndim

    一个整数,表示内存所代表的多维数组具有多少个维度。

  • shape

    一个整数元组,通过 ndim 的长度值给出内存所代表的 N 维数组的形状。

    在 3.3 版更改: 当 ndim = 0 时值为空元组而不再为 None

  • strides

    一个整数元组,通过 ndim 的长度给出以字节表示的大小,以便访问数组中每个维度上的每个元素。

    在 3.3 版更改: 当 ndim = 0 时值为空元组而不再为 None

  • suboffsets

    供 PIL 风格的数组内部使用。 该值仅作为参考信息。

  • c_contiguous

    一个表明内存是否为 C-contiguous 的布尔值。

    3.3 新版功能.

  • f_contiguous

    一个表明内存是否为 Fortran contiguous 的布尔值。

    3.3 新版功能.

  • contiguous

    一个表明内存是否为 contiguous 的布尔值。

    3.3 新版功能.

集合类型 —- set, frozenset

set 对象是由具有唯一性的 hashable 对象所组成的无序多项集。 常见的用途包括成员检测、从序列中去除重复项以及数学中的集合类计算,例如交集、并集、差集与对称差集等等。

与其他多项集一样,集合也支持 x in set, len(set)for x in set。 作为一种无序的多项集,集合并不记录元素位置或插入顺序。 相应地,集合不支持索引、切片或其他序列类的操作。

目前有两种内置集合类型,setfrozensetset 类型是可变的 —- 其内容可以使用 add()remove() 这样的方法来改变。 由于是可变类型,它没有哈希值,且不能被用作字典的键或其他集合的元素。 frozenset 类型是不可变并且为 hashable —- 其内容在被创建后不能再改变;因此它可以被用作字典的键或其他集合的元素。

除了可以使用 set 构造器,非空的 set (不是 frozenset) 还可以通过将以逗号分隔的元素列表包含于花括号之内来创建,例如: {'jack', 'sjoerd'}

两个类的构造器具有相同的作用方式:

class set([iterable])

class frozenset([iterable])

返回一个新的 set 或 frozenset 对象,其元素来自于 iterable。 集合的元素必须为 hashable。 要表示由集合对象构成的集合,所有的内层集合必须为 frozenset 对象。 如果未指定 iterable,则将返回一个新的空集合。

集合可用多种方式来创建:

  • 使用花括号内以逗号分隔元素的方式: {'jack', 'sjoerd'}
  • 使用集合推导式: {c for c in 'abracadabra' if c not in 'abc'}
  • 使用类型构造器: set(), set('foobar'), set(['a', 'b', 'foo'])

setfrozenset 的实例提供以下操作:

  • len(s)

    返回集合 s 中的元素数量(即 s 的基数)。

  • x in s

    检测 x 是否为 s 中的成员。

  • x not in s

    检测 x 是否非 s 中的成员。

  • isdisjoint(other)

    如果集合中没有与 other 共有的元素则返回 True。 当且仅当两个集合的交集为空集合时,两者为不相交集合。

  • issubset(other)

    set <= other

    检测是否集合中的每个元素都在 other 之中。

  • set < other

    检测集合是否为 other 的真子集,即 set <= other and set != other

  • issuperset(other)

    set >= other

    检测是否 other 中的每个元素都在集合之中。

  • set > other

    检测集合是否为 other 的真超集,即 set >= other and set != other

  • union(\others*)

    set | other | ...

    返回一个新集合,其中包含来自原集合以及 others 指定的所有集合中的元素。

  • intersection(\others*)

    set & other & ...

    返回一个新集合,其中包含原集合以及 others 指定的所有集合中共有的元素。

  • difference(\others*)

    set - other - ...

    返回一个新集合,其中包含原集合中在 others 指定的其他集合中不存在的元素。

  • symmetric_difference(other)

    set ^ other

    返回一个新集合,其中的元素或属于原集合或属于 other 指定的其他集合,但不能同时属于两者。

  • copy()

    返回原集合的浅拷贝。

Note, the non-operator versions of union(), intersection(), difference(), symmetric_difference(), issubset(), and issuperset() methods will accept any iterable as an argument. In contrast, their operator based counterparts require their arguments to be sets. This precludes error-prone constructions like set('abc') & 'cbs' in favor of the more readable set('abc').intersection('cbs').

setfrozenset 均支持集合与集合的比较。 两个集合当且仅当每个集合中的每个元素均包含于另一个集合之内(即各为对方的子集)时则相等。 一个集合当且仅当其为另一个集合的真子集(即为后者的子集但两者不相等)时则小于另一个集合。 一个集合当且仅当其为另一个集合的真超集(即为后者的超集但两者不相等)时则大于另一个集合。

set 的实例与 frozenset 的实例之间基于它们的成员进行比较。 例如 set('abc') == frozenset('abc') 返回 Trueset('abc') in set([frozenset('abc')]) 也一样。

子集与相等比较并不能推广为完全排序函数。 例如,任意两个非空且不相交的集合不相等且互不为对方的子集,因此以下 所有 比较均返回 False: a<b, a==b, or a>b

由于集合仅定义了部分排序(子集关系),因此由集合构成的列表 list.sort() 方法的输出并无定义。

集合的元素,与字典的键类似,必须为 hashable。

混合了 set 实例与 frozenset 的二进制位运算将返回与第一个操作数相同的类型。例如: frozenset('ab') | set('bc') 将返回 frozenset 的实例。

下表列出了可用于 set 而不能用于不可变的 frozenset 实例的操作:

  • update(\others*)

    set |= other | ...

    更新集合,添加来自 others 中的所有元素。

  • intersection_update(\others*)

    set &= other & ...

    更新集合,只保留其中在所有 others 中也存在的元素。

  • difference_update(\others*)

    set -= other | ...

    更新集合,移除其中也存在于 others 中的元素。

  • symmetric_difference_update(other)

    set ^= other

    更新集合,只保留存在于集合的一方而非共同存在的元素。

  • add(elem)

    将元素 elem 添加到集合中。

  • remove(elem)

    从集合中移除元素 elem*。 如果 *elem 不存在于集合中则会引发 KeyError

  • discard(elem)

    如果元素 elem 存在于集合中则将其移除。

  • pop()

    从集合中移除并返回任意一个元素。 如果集合为空则会引发 KeyError

  • clear()

    从集合中移除所有元素。

请注意,非运算符版本的 update(), intersection_update(), difference_update()symmetric_difference_update() 方法将接受任意可迭代对象作为参数。

请注意,__contains__(), remove()discard() 方法的 elem 参数可能是一个 set。 为支持对一个等价的 frozenset 进行搜索,会根据 elem 临时创建一个该类型对象。

映射类型 —- dict

mapping 对象会将 hashable 值映射到任意对象。 映射属于可变对象。 目前仅有一种标准映射类型 字典

字典的键 几乎 可以是任何值。 非 hashable 的值,即包含列表、字典或其他可变类型的值(此类对象基于值而非对象标识进行比较)不可用作键。 数字类型用作键时遵循数字比较的一般规则:如果两个数值相等 (例如 11.0) 则两者可以被用来索引同一字典条目。 (但是请注意,由于计算机对于浮点数存储的只是近似值,因此将其用作字典键是不明智的。)

字典可以通过将以逗号分隔的 键: 值 对列表包含于花括号之内来创建,例如: {'jack': 4098, 'sjoerd': 4127}{4098: 'jack', 4127: 'sjoerd'},也可以通过 dict 构造器来创建。

class dict(**kwarg)

class dict(mapping, **kwarg)

class dict(iterable, **kwarg)

返回一个新的字典,基于可选的位置参数和可能为空的关键字参数集来初始化。

字典可用多种方式来创建:

  • 使用花括号内以逗号分隔 键: 值 对的方式: {'jack': 4098, 'sjoerd': 4127} or {4098: 'jack', 4127: 'sjoerd'}
  • 使用字典推导式: {}, {x: x ** 2 for x in range(10)}
  • 使用类型构造器: dict(), dict([('foo', 100), ('bar', 200)]), dict(foo=100, bar=200)

如果没有给出位置参数,将创建一个空字典。 如果给出一个位置参数并且其属于映射对象,将创建一个具有与映射对象相同键值对的字典。 否则的话,位置参数必须为一个 iterable 对象。 该可迭代对象中的每一项本身必须为一个刚好包含两个元素的可迭代对象。 每一项中的第一个对象将成为新字典的一个键,第二个对象将成为其对应的值。 如果一个键出现一次以上,该键的最后一个值将成为其在新字典中对应的值。

如果给出了关键字参数,则关键字参数及其值会被加入到基于位置参数创建的字典。 如果要加入的键已存在,来自关键字参数的值将替代来自位置参数的值。

作为演示,以下示例返回的字典均等于 {"one": 1, "two": 2, "three": 3}:

>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> f = dict({'one': 1, 'three': 3}, two=2)
>>> a == b == c == d == e == f
True

像第一个例子那样提供关键字参数的方式只能使用有效的 Python 标识符作为键。 其他方式则可使用任何有效的键。

这些是字典所支持的操作(因而自定义的映射类型也应当支持):

  • list(d)

    返回字典 d 中使用的所有键的列表。

  • len(d)

    返回字典 d 中的项数。

  • d[key]

    返回 d 中以 key 为键的项。 如果映射中不存在 key 则会引发 KeyError

    如果字典的子类定义了方法 __missing__() 并且 key 不存在,则 d[key] 操作将调用该方法并附带键 key 作为参数。 d[key] 随后将返回或引发 __missing__(key) 调用所返回或引发的任何对象或异常。 没有其他操作或方法会发起调用 __missing__()。 如果未定义 __missing__(),则会引发 KeyError__missing__() 必须是一个方法;它不能是一个实例变量:

    >>> class Counter(dict):
    ...     def __missing__(self, key):
    ...         return 0
    >>> c = Counter()
    >>> c['red']
    0
    >>> c['red'] += 1
    >>> c['red']
    1

    上面的例子显示了 collections.Counter 实现的部分代码。 还有另一个不同的 __missing__ 方法是由 collections.defaultdict 所使用的。

  • d[key] = value

    d[key] 设为 value

  • del d[key]

    d[key]d 中移除。 如果映射中不存在 key 则会引发 KeyError

  • key in d

    如果 d 中存在键 key 则返回 True,否则返回 False

  • key not in d

    等价于 not key in d

  • iter(d)

    返回以字典的键为元素的迭代器。 这是 iter(d.keys()) 的快捷方式。

  • clear()

    移除字典中的所有元素。

  • copy()

    返回原字典的浅拷贝。

  • classmethod fromkeys(iterable[, value])

    使用来自 iterable 的键创建一个新字典,并将键值设为 value

    fromkeys() 是一个返回新字典的类方法。 value 默认为 None。 所有值都只引用一个单独的实例,因此让 value 成为一个可变对象例如空列表通常是没有意义的。 要获取不同的值,请改用 字典推导式。

  • get(key[, default])

    如果 key 存在于字典中则返回 key 的值,否则返回 default*。 如果 *default 未给出则默认为 None,因而此方法绝不会引发 KeyError

  • items()

    返回由字典项 ((键, 值) 对) 组成的一个新视图。

  • keys()

    返回由字典键组成的一个新视图。

  • pop(key[, default])

    如果 key 存在于字典中则将其移除并返回其值,否则返回 default*。 如果 *default 未给出且 key 不存在于字典中,则会引发 KeyError

  • popitem()

    从字典中移除并返回一个 (键, 值) 对。 键值对会按 LIFO 的顺序被返回。

    popitem() 适用于对字典进行消耗性的迭代,这在集合算法中经常被使用。 如果字典为空,调用 popitem() 将引发 KeyError

    在 3.7 版更改: 现在会确保采用 LIFO 顺序。 在之前的版本中,popitem() 会返回一个任意的键/值对。

  • reversed(d)

    返回一个逆序获取字典键的迭代器。 这是 reversed(d.keys()) 的快捷方式。

    3.8 新版功能.

  • setdefault(key[, default])

    如果字典存在键 key ,返回它的值。如果不存在,插入值为 default 的键 key ,并返回 defaultdefault 默认为 None

  • update([other])

    使用来自 other 的键/值对更新字典,覆盖原有的键。 返回 None

    update() 接受另一个字典对象,或者一个包含键/值对(以长度为二的元组或其他可迭代对象表示)的可迭代对象。 如果给出了关键字参数,则会以其所指定的键/值对更新字典: d.update(red=1, blue=2)

  • values()

    返回由字典值组成的一个新视图。

    两个 dict.values() 视图之间的相等性比较将总是返回 False。 这在 dict.values() 与其自身比较时也同样适用:

    >>> d = {'a': 1}
    >>> d.values() == d.values()
    False
  • d | other

    合并 dother 中的键和值来创建一个新的字典,两者必须都是字典。当 dother 有相同键时, other 的值优先。

    3.9 新版功能.

  • d |= other

    other 的键和值更新字典 dother 可以是 mapping 或 iterable 的键值对。当 dother 有相同键时, other 的值优先。

    3.9 新版功能.

两个字典的比较当且仅当它们具有相同的 (键, 值) 对时才会相等(不考虑顺序)。 排序比较 (‘<’, ‘<=’, ‘>=’, ‘>’) 会引发 TypeError

字典会保留插入时的顺序。 请注意对键的更新不会影响顺序。 删除并再次添加的键将被插入到末尾。

>>> d = {"one": 1, "two": 2, "three": 3, "four": 4}
>>> d
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> list(d)
['one', 'two', 'three', 'four']
>>> list(d.values())
[1, 2, 3, 4]
>>> d["one"] = 42
>>> d
{'one': 42, 'two': 2, 'three': 3, 'four': 4}
>>> del d["two"]
>>> d["two"] = None
>>> d
{'one': 42, 'three': 3, 'four': 4, 'two': None}

在 3.7 版更改: 字典顺序会确保为插入顺序。 此行为是自 3.6 版开始的 CPython 实现细节。

字典和字典视图都是可逆的。

>>> d = {"one": 1, "two": 2, "three": 3, "four": 4}
>>> d
{'one': 1, 'two': 2, 'three': 3, 'four': 4}
>>> list(reversed(d))
['four', 'three', 'two', 'one']
>>> list(reversed(d.values()))
[4, 3, 2, 1]
>>> list(reversed(d.items()))
[('four', 4), ('three', 3), ('two', 2), ('one', 1)]

在 3.8 版更改: 字典现在是可逆的。

字典视图对象

dict.keys(), dict.values()dict.items() 所返回的对象是 视图对象。 该对象提供字典条目的一个动态视图,这意味着当字典改变时,视图也会相应改变。

字典视图可以被迭代以产生与其对应的数据,并支持成员检测:

len(dictview)

返回字典中的条目数。

iter(dictview)

返回字典中的键、值或项(以 (键, 值) 为元素的元组表示)的迭代器。

键和值是按插入时的顺序进行迭代的。 这样就允许使用 zip() 来创建 (值, 键) 对: pairs = zip(d.values(), d.keys())。 另一个创建相同列表的方式是 pairs = [(v, k) for (k, v) in d.items()].

在添加或删除字典中的条目期间对视图进行迭代可能引发 RuntimeError 或者无法完全迭代所有条目。

在 3.7 版更改: 字典顺序会确保为插入顺序。

x in dictview

如果 x 是对应字典中存在的键、值或项(在最后一种情况下 x 应为一个 (键, 值) 元组) 则返回 True

reversed(dictview)

返回一个逆序获取字典键、值或项的迭代器。 视图将按与插入时相反的顺序进行迭代。

在 3.8 版更改: 字典视图现在是可逆的。

dictview.mapping

Return a types.MappingProxyType that wraps the original dictionary to which the view refers.

3.10 新版功能.

键视图类似于集合,因为其条目不重复且可哈希。 如果所有值都是可哈希的,即 (键, 值) 对也是不重复且可哈希的,那么条目视图也会类似于集合。 (值视图则不被视为类似于集合,因其条目通常都是有重复的。) 对于类似于集合的视图,为抽象基类 collections.abc.Set 所定义的全部操作都是有效的 (例如 ==, <^)。

一个使用字典视图的示例:

>>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
>>> keys = dishes.keys()
>>> values = dishes.values()
>>> # iteration
>>> n = 0
>>> for val in values:
...     n += val
>>> print(n)
504
>>> # keys and values are iterated over in the same order (insertion order)
>>> list(keys)
['eggs', 'sausage', 'bacon', 'spam']
>>> list(values)
[2, 1, 1, 500]
>>> # view objects are dynamic and reflect dict changes
>>> del dishes['eggs']
>>> del dishes['sausage']
>>> list(keys)
['bacon', 'spam']
>>> # set operations
>>> keys & {'eggs', 'bacon', 'salad'}
{'bacon'}
>>> keys ^ {'sausage', 'juice'}
{'juice', 'sausage', 'bacon', 'spam'}
>>> # get back a read-only proxy for the original dictionary
>>> values.mapping
mappingproxy({'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500})
>>> values.mapping['spam']
500

上下文管理器类型

Python 的 with 语句支持通过上下文管理器所定义的运行时上下文这一概念。 此对象的实现使用了一对专门方法,允许用户自定义类来定义运行时上下文,在语句体被执行前进入该上下文,并在语句执行完毕时退出该上下文:

contextmanager.__enter__()

进入运行时上下文并返回此对象或关联到该运行时上下文的其他对象。 此方法的返回值会绑定到使用此上下文管理器的 with 语句的 as 子句中的标识符。

一个返回其自身的上下文管理器的例子是 file object。 文件对象会从 enter() 返回其自身,以允许 open() 被用作 with 语句中的上下文表达式。

一个返回关联对象的上下文管理器的例子是 decimal.localcontext() 所返回的对象。 此种管理器会将活动的 decimal 上下文设为原始 decimal 上下文的一个副本并返回该副本。 这允许对 with 语句的语句体中的当前 decimal 上下文进行更改,而不会影响 with 语句以外的代码。

contextmanager.__exit__(exc_type, exc_val, exc_tb)

退出运行时上下文并返回一个布尔值旗标来表明所发生的任何异常是否应当被屏蔽。 如果在执行 with 语句的语句体期间发生了异常,则参数会包含异常的类型、值以及回溯信息。 在其他情况下三个参数均为 None

自此方法返回一个真值将导致 with 语句屏蔽异常并继续执行紧随在 with 语句之后的语句。 否则异常将在此方法结束执行后继续传播。 在此方法执行期间发生的异常将会取代 with 语句的语句体中发生的任何异常。

传入的异常绝对不应当被显式地重新引发 —— 相反地,此方法应当返回一个假值以表明方法已成功完成并且不希望屏蔽被引发的异常。 这允许上下文管理代码方便地检测 __exit__() 方法是否确实已失败。

Python 定义了一些上下文管理器来支持简易的线程同步、文件或其他对象的快速关闭,以及更方便地操作活动的十进制算术上下文。 除了实现上下文管理协议以外,不同类型不会被特殊处理。

Python 的 generator 和 contextlib.contextmanager 装饰器提供了实现这些协议的便捷方式。 如果使用 contextlib.contextmanager 装饰器来装饰一个生成器函数,它将返回一个实现了必要的 __enter__() and __exit__() 方法的上下文管理器,而不再是由未经装饰的生成器函数所产生的迭代器。

请注意,Python/C API 中 Python 对象的类型结构中并没有针对这些方法的专门槽位。 想要定义这些方法的扩展类型必须将它们作为普通的 Python 可访问方法来提供。 与设置运行时上下文的开销相比,单个类字典查找的开销可以忽略不计。

Type Annotation Types —- Generic Alias, Union

The core built-in types for type annotations are Generic Alias and Union.

Generic Alias Type

GenericAlias objects are created by subscripting a class (usually a container), such as list[int]. They are intended primarily for type annotations.

Usually, the subscription of container objects calls the method __getitem__() of the object. However, the subscription of some containers’ classes may call the classmethod __class_getitem__() of the class instead. The classmethod __class_getitem__() should return a GenericAlias object.

注解

If the __getitem__() of the class’ metaclass is present, it will take precedence over the __class_getitem__() defined in the class (see PEP 560 for more details).

The GenericAlias object acts as a proxy for generic types, implementing parameterized generics - a specific instance of a generic which provides the types for container elements.

The user-exposed type for the GenericAlias object can be accessed from types.GenericAlias and used for isinstance() checks. It can also be used to create GenericAlias objects directly.

T[X, Y, ...]

Creates a GenericAlias representing a type T containing elements of types X, Y, and more depending on the T used. For example, a function expecting a list containing float elements:

def average(values: list[float]) -> float:
    return sum(values) / len(values)

Another example for mapping objects, using a dict, which is a generic type expecting two type parameters representing the key type and the value type. In this example, the function expects a dict with keys of type str and values of type int:

def send_post_request(url: str, body: dict[str, int]) -> None:
    ...

The builtin functions isinstance() and issubclass() do not accept GenericAlias types for their second argument:

>>> isinstance([1, 2], list[str])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: isinstance() argument 2 cannot be a parameterized generic

The Python runtime does not enforce type annotations. This extends to generic types and their type parameters. When creating an object from a GenericAlias, container elements are not checked against their type. For example, the following code is discouraged, but will run without errors:

>>> t = list[str]
>>> t([1, 2, 3])
[1, 2, 3]

Furthermore, parameterized generics erase type parameters during object creation:

>>> t = list[str]
>>> type(t)
<class 'types.GenericAlias'>
>>> l = t()
>>> type(l)
<class 'list'>

Calling repr() or str() on a generic shows the parameterized type:

>>> repr(list[int])
'list[int]'
>>> str(list[int])
'list[int]'

The __getitem__() method of generics will raise an exception to disallow mistakes like dict[str][str]:

>>> dict[str][str]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: There are no type variables left in dict[str]

However, such expressions are valid when type variables are used. The index must have as many elements as there are type variable items in the GenericAlias object’s __args__.

>>> from typing import TypeVar
>>> Y = TypeVar('Y')
>>> dict[str, Y][int]
dict[str, int]

Standard Generic Collections

These standard library collections support parameterized generics.

  • tuple
  • list
  • dict
  • set
  • frozenset
  • type
  • collections.deque
  • collections.defaultdict
  • collections.OrderedDict
  • collections.Counter
  • collections.ChainMap
  • collections.abc.Awaitable
  • collections.abc.Coroutine
  • collections.abc.AsyncIterable
  • collections.abc.AsyncIterator
  • collections.abc.AsyncGenerator
  • collections.abc.Iterable
  • collections.abc.Iterator
  • collections.abc.Generator
  • collections.abc.Reversible
  • collections.abc.Container
  • collections.abc.Collection
  • collections.abc.Callable
  • collections.abc.Set
  • collections.abc.MutableSet
  • collections.abc.Mapping
  • collections.abc.MutableMapping
  • collections.abc.Sequence
  • collections.abc.MutableSequence
  • collections.abc.ByteString
  • collections.abc.MappingView
  • collections.abc.KeysView
  • collections.abc.ItemsView
  • collections.abc.ValuesView
  • contextlib.AbstractContextManager
  • contextlib.AbstractAsyncContextManager
  • re.Pattern
  • re.Match

Special Attributes of Generic Alias

All parameterized generics implement special read-only attributes.

genericalias.__origin__

This attribute points at the non-parameterized generic class:

>>> list[int].__origin__
<class 'list'>

genericalias.__args__

This attribute is a tuple (possibly of length 1) of generic types passed to the original __class_getitem__() of the generic container:

>>> dict[str, list[int]].__args__
(<class 'str'>, list[int])

genericalias.__parameters__

This attribute is a lazily computed tuple (possibly empty) of unique type variables found in __args__:

>>> from typing import TypeVar
>>> T = TypeVar('T')
>>> list[T].__parameters__
(~T,)

注解

A GenericAlias object with typing.ParamSpec parameters may not have correct __parameters__ after substitution because typing.ParamSpec is intended primarily for static type checking.

参见

  • PEP 585 — “Type Hinting Generics In Standard Collections”
  • __class_getitem__() — Used to implement parameterized generics.
  • 泛型(Generic) — Generics in the typing module.

3.9 新版功能.

Union Type

A union object holds the value of the | (bitwise or) operation on multiple type objects. These types are intended primarily for type annotations. The union type expression enables cleaner type hinting syntax compared to typing.Union.

X | Y | ...

Defines a union object which holds types X, Y, and so forth. X | Y means either X or Y. It is equivalent to typing.Union[X, Y]. For example, the following function expects an argument of type int or float:

def square(number: int | float) -> int | float:
    return number ** 2

union_object == other

Union objects can be tested for equality with other union objects. Details:

  • Unions of unions are flattened:

    (int | str) | float == int | str | float
  • Redundant types are removed:

    int | str | int == int | str
  • When comparing unions, the order is ignored:

    int | str == str | int
  • It is compatible with typing.Union:

    int | str == typing.Union[int, str]
  • Optional types can be spelled as a union with None:

    str | None == typing.Optional[str]
isinstance(obj, union_object)
issubclass(obj, union_object)

Calls to isinstance() and issubclass() are also supported with a union object:

>>> isinstance("", int | str)
True

However, union objects containing parameterized generics cannot be used:

>>> isinstance(1, int | list[int])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: isinstance() argument 2 cannot contain a parameterized generic

The user-exposed type for the union object can be accessed from types.UnionType and used for isinstance() checks. An object cannot be instantiated from the type:

>>> import types
>>> isinstance(int | str, types.UnionType)
True
>>> types.UnionType()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create 'types.UnionType' instances

注解

The __or__() method for type objects was added to support the syntax X | Y. If a metaclass implements __or__(), the Union may override it:

>>> class M(type):
...     def __or__(self, other):
...         return "Hello"
...
>>> class C(metaclass=M):
...     pass
...
>>> C | int
'Hello'
>>> int | C
int | __main__.C

参见

PEP 604 — PEP proposing the X | Y syntax and the Union type.

3.10 新版功能.

其他内置类型

解释器支持一些其他种类的对象。 这些对象大都仅支持一两种操作。

模块

模块唯一的特殊操作是属性访问: m.name,这里 m 为一个模块而 name 访问定义在 m 的符号表中的一个名称。 模块属性可以被赋值。 (请注意 import 语句严格来说也是对模块对象的一种操作;import foo 不要求存在一个名为 foo 的模块对象,而是要求存在一个对于名为 foo 的模块的 (永久性) 定义。)

每个模块都有一个特殊属性 __dict__。 这是包含模块的符号表的字典。 修改此字典将实际改变模块的符号表,但是无法直接对 __dict__ 赋值 (你可以写 m.__dict__['a'] = 1,这会将 m.a 定义为 1,但是你不能写 m.__dict__ = {})。 不建议直接修改 __dict__

内置于解释器中的模块会写成这样: <module 'sys' (built-in)>。 如果是从一个文件加载,则会写成 <module 'os' from '/usr/local/lib/pythonX.Y/os.pyc'>

类与类实例

关于这些类型请参阅 对象、值与类型 和 类定义。

函数

函数对象是通过函数定义创建的。 对函数对象的唯一操作是调用它: func(argument-list)

实际上存在两种不同的函数对象:内置函数和用户自定义函数。 两者支持同样的操作(调用函数),但实现方式不同,因此对象类型也不同。

方法

方法是使用属性表示法来调用的函数。 存在两种形式:内置方法(例如列表的 append() 方法)和类实例方法。 内置方法由支持它们的类型来描述。

如果你通过一个实例来访问方法(即定义在类命名空间内的函数),你会得到一个特殊对象: 绑定方法 (或称 实例方法) 对象。 当被调用时,它会将 self 参数添加到参数列表。 绑定方法具有两个特殊的只读属性: m.__self__ 操作该方法的对象,而 m.__func__ 是实现该方法的函数。 调用 m(arg-1, arg-2, ..., arg-n) 完全等价于调用 m.__func__(m.__self__, arg-1, arg-2, ..., arg-n)

与函数对象类似,绑定方法对象也支持获取任意属性。 但是,由于方法属性实际上保存于下层的函数对象中 (meth.__func__),因此不允许设置绑定方法的方法属性。 尝试设置方法的属性将会导致引发 AttributeError。 想要设置方法属性,你必须在下层的函数对象中显式地对其进行设置:

>>> class C:
...     def method(self):
...         pass
...
>>> c = C()
>>> c.method.whoami = 'my name is method'  # can't set on the method
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'method' object has no attribute 'whoami'
>>> c.method.__func__.whoami = 'my name is method'
>>> c.method.whoami
'my name is method'

代码对象

代码对象被具体实现用来表示“伪编译”的可执行 Python 代码,例如一个函数体。 它们不同于函数对象,因为它们不包含对其全局执行环境的引用。 代码对象由内置的 compile() 函数返回,并可通过从函数对象的 __code__ 属性从中提取。

Accessing __code__ raises an auditing event object.__getattr__ with arguments obj and "__code__".

可以通过将代码对象(而非源码字符串)传给 exec()eval() 内置函数来执行或求值。

类型对象

类型对象表示各种对象类型。 对象的类型可通过内置函数 type() 来获取。 类型没有特殊的操作。 标准库模块 types 定义了所有标准内置类型的名称。

类型以这样的写法来表示: <class 'int'>

空对象

此对象会由不显式地返回值的函数所返回。 它不支持任何特殊的操作。 空对象只有一种值 None (这是个内置名称)。 type(None)() 会生成同一个单例。

该对象的写法为 None

省略符对象

此对象常被用于切片。 它不支持任何特殊的操作。 省略符对象只有一种值 Ellipsis (这是个内置名称)。 type(Ellipsis)() 会生成 Ellipsis 单例。

该对象的写法为 Ellipsis...

未实现对象

此对象会被作为比较和二元运算被应用于它们所不支持的类型时的返回值。未实现对象只有一种值 NotImplementedtype(NotImplemented)() 会生成这个单例。

该对象的写法为 NotImplemented

布尔值

布尔值是两个常量对象 FalseTrue。 它们被用来表示逻辑上的真假(不过其他值也可被当作真值或假值)。 在数字类的上下文中(例如被用作算术运算符的参数时),它们的行为分别类似于整数 0 和 1。 内置函数 bool() 可被用来将任意值转换为布尔值,只要该值可被解析为一个逻辑值。

该对象的写法分别为 FalseTrue

内部对象

有关此对象的信息请参阅 标准类型层级结构。 其中描述了栈帧对象、回溯对象以及切片对象等等。

特殊属性

语言实现为部分对象类型添加了一些特殊的只读属性,它们具有各自的作用。 其中一些并不会被 dir() 内置函数所列出。

object.__dict__

一个字典或其他类型的映射对象,用于存储对象的(可写)属性。

instance.__class__

类实例所属的类。

class.__bases__

由类对象的基类所组成的元组。

definition.__name__

类、函数、方法、描述器或生成器实例的名称。

definition.__qualname__

类、函数、方法、描述器或生成器实例的 qualified name。

3.3 新版功能.

class.__mro__

此属性是由类组成的元组,在方法解析期间会基于它来查找基类。

class.mro()

此方法可被一个元类来重载,以为其实例定制方法解析顺序。 它会在类实例化时被调用,其结果存储于 __mro__ 之中。

class.__subclasses__()

Each class keeps a list of weak references to its immediate subclasses. This method returns a list of all those references still alive. The list is in definition order. Example:

>>> int.__subclasses__()
[<class 'bool'>]

内置异常

在 Python 中,所有异常必须为一个派生自 BaseException 的类的实例。 在带有提及一个特定类的 except 子句的 try 语句中,该子句也会处理任何派生自该类的异常类(但不处理 所派生出的异常类)。 通过子类化创建的两个不相关异常类永远是不等效的,既使它们具有相同的名称。

下面列出的内置异常可通过解释器或内置函数来生成。除非另有说明,它们都会具有一个提示导致错误详细原因的“关联值”。 这可以是一个字符串或由多个信息项(例如一个错误码和一个解释错误的字符串)组成的元组。 关联值通常会作为参数被传递给异常类的构造器。

用户代码可以引发内置异常。 这可被用于测试异常处理程序或报告错误条件,“就像” 在解释器引发了相同异常的情况时一样;但是请注意,没有任何机制能防止用户代码引发不适当的错误。

内置异常类可以被子类化以定义新的异常;鼓励程序员从 Exception 类或它的某个子类而不是从 BaseException 来派生新的异常。

当在 exceptfinally 子句中引发(或重新引发)异常时,__context__ 会被自动设为所捕获的最后一个异常;如果新的异常未被处理,则最终显示的回溯信息将包括原始的异常和最后的异常。

当引发一个新的异常(而不是简单地使用 raise 来重新引发 当前在处理的异常)时,隐式的异常上下文可以通过使用带有 raisefrom 子句来补充一个显式的原因:

raise new_exc from original_exc

跟在 from 之后一表达式必须为一个异常或 None。 它将在所引发的异常上被设置为 __cause__。 设置 __cause__ 还会隐式地将 __suppress_context__ 属性设为 True,这样使用 raise new_exc from None 可以有效地将旧异常替换为新异常来显示其目的 (例如将 KeyError 转换为 AttributeError),同时让旧异常在 __context__ 中保持可用状态以便在调试时进行内省。

除了异常本身的回溯以外,默认的回溯还会显示这些串连的异常。 __cause__ 中的显式串连异常如果存在将总是显示。 __context__ 中的隐式串连异常仅在 __cause__None 并且 __suppress_context__ 为假值时显示。

不论在哪种情况下,异常本身总会在任何串连异常之后显示,以便回溯的最后一行总是显示所引发的最后一个异常。

基类

下列异常主要被用作其他异常的基类。

  • exception BaseException

所有内置异常的基类。 它不应该被用户自定义类直接继承 (这种情况请使用 Exception)。 如果在此类的实例上调用 str(),则会返回实例的参数表示,或者当没有参数时返回空字符串。

args

传给异常构造器的参数元组。 某些内置异常 (例如 OSError) 接受特定数量的参数并赋予此元组中的元素特殊的含义,而其他异常通常只接受一个给出错误信息的单独字符串。

with_traceback(tb)

此方法会将 tb 设为新的异常回溯信息并返回异常对象。 它在 PEP 3134 的异常链特性可用之前更为常用。 下面的例子演示了我们如何将一个 SomeException 实例转换为 OtherException 实例而保留回溯信息。 异常一旦被引发,当前帧会被推至 OtherException 的回溯栈顶端,就像当我们允许原始 SomeException 被传播给调用方时它的回溯栈将会发生的情形一样。:

try:
    ...
except SomeException:
    tb = sys.exc_info()[2]
    raise OtherException(...).with_traceback(tb)
  • exception Exception

所有内置的非系统退出类异常都派生自此类。 所有用户自定义异常也应当派生自此类。

  • exception ArithmeticError

此基类用于派生针对各种算术类错误而引发的内置异常: OverflowError, ZeroDivisionError, FloatingPointError

  • exception BufferError

当与 缓冲区 相关的操作无法执行时将被引发。

  • exception LookupError

此基类用于派生当映射或序列所使用的键或索引无效时引发的异常: IndexError, KeyError。 这可以通过 codecs.lookup() 来直接引发。

具体异常

以下异常属于经常被引发的异常。

  • exception AssertionError

assert 语句失败时将被引发。

  • exception AttributeError

当属性引用 或赋值失败时将被引发。 (当一个对象根本不支持属性引用或属性赋值时则将引发 TypeError。)

nameobj 属性可以使用构造器的仅限关键字参数来设置。 它们如果被设置则分别代表要尝试访问的属性名称以及所访问的该属性的对象。

在 3.10 版更改: 增加了 nameobj 属性。

  • exception EOFError

input() 函数未读取任何数据即达到文件结束条件 (EOF) 时将被引发。 (另外,io.IOBase.read()io.IOBase.readline() 方法在遇到 EOF 则将返回一个空字符串。)

  • exception FloatingPointError

目前未被使用。

  • exception GeneratorExit

当一个 generator 或 coroutine 被关闭时将被引发;见 generator.close()coroutine.close()。 它直接继承自 BaseException 而不是 Exception,因为从技术上来说它并不是一个错误。

  • exception ImportError

import 语句尝试加载模块遇到麻烦时将被引发。 并且当 from ... import 中的 “from list” 存在无法找到的名称时也会被引发。

namepath 属性可通过对构造器使用仅关键字参数来设定。 设定后它们将分别表示被尝试导入的模块名称与触发异常的任意文件所在路径。

在 3.3 版更改: 添加了 namepath 属性。

  • exception ModuleNotFoundError

ImportError 的子类,当一个模块无法被定位时将由 import 引发。 当在 sys.modules 中找到 None 时也会被引发。

3.6 新版功能.

  • exception IndexError

当序列抽取超出范围时将被引发。 (切片索引会被静默截短到允许的范围;如果指定索引不是整数则 TypeError 会被引发。)

  • exception KeyError

当在现有键集合中找不到指定的映射(字典)键时将被引发。

  • exception KeyboardInterrupt

当用户按下中断键 (通常为 Control-C 或 Delete) 时将被引发。 在执行期间,会定期检测中断信号。 该异常继承自 BaseException 以确保不会被处理 Exception 的代码意外捕获,这样可以避免退出解释器。

  • exception MemoryError

当一个操作耗尽内存但情况仍可(通过删除一些对象)进行挽救时将被引发。 关联的值是一个字符串,指明是哪种(内部)操作耗尽了内存。 请注意由于底层的内存管理架构(C 的 malloc() 函数),解释器也许并不总是能够从这种情况下完全恢复;但它毕竟可以引发一个异常,这样就能打印出栈回溯信息,以便找出导致问题的失控程序。

  • exception NameError

当某个局部或全局名称未找到时将被引发。 此异常仅用于非限定名称。 关联的值是一条错误信息,其中包含未找到的名称。

name 属性可以使用构造器的仅限关键字参数来设置。 它如果被设置则代表要尝试访问的变量名称。

在 3.10 版更改: 增加了 name 属性。

  • exception NotImplementedError

此异常派生自 RuntimeError。 在用户自定义的基类中,抽象方法应当在其要求所派生类重载该方法,或是在其要求所开发的类提示具体实现尚待添加时引发此异常。

注解

它不应当用来表示一个运算符或方法根本不能被支持 — 在此情况下应当让特定运算符 / 方法保持未定义,或者在子类中将其设为 None

注解

NotImplementedErrorNotImplemented 不可互换,即使它们有相似的名称和用途。

  • exception OSError([arg])

  • exception OSError(errno, strerror[, filename[, winerror[, filename2]]])

    此异常在一个系统函数返回系统相关的错误时将被引发,此类错误包括 I/O 操作失败例如 “文件未找到” 或 “磁盘已满” 等(不包括非法参数类型或其他偶然性错误)。

    构造器的第二种形式可设置如下所述的相应属性。 如果未指定这些属性则默认为 None。 为了能向下兼容,如果传入了三个参数,则 args 属性将仅包含由前两个构造器参数组成的 2 元组。

    构造器实际返回的往往是 OSError 的某个子类,如下文 OS exceptions 中所描述的。 具体的子类取决于最终的 errno 值。 此行为仅在直接或通过别名来构造 OSError 时发生,并且在子类化时不会被继承。

    • errno

      来自于 C 变量 errno 的数字错误码。

    • winerror

      在 Windows 下,此参数将给出原生的 Windows 错误码。 而 errno 属性将是该原生错误码在 POSIX 平台下的近似转换形式。

      在 Windows 下,如果 winerror 构造器参数是一个整数,则 errno 属性会根据 Windows 错误码来确定,而 errno 参数会被忽略。 在其他平台上,winerror 参数会被忽略,并且 winerror 属性将不存在。

    • strerror

      操作系统所提供的相应错误信息。 它在 POSIX 平台中由 C 函数 perror() 来格式化,在 Windows 中则是由 FormatMessage()

    • filename

      filename2

      对于与文件系统路径有关 (例如 open()os.unlink()) 的异常,filename 是传给函数的文件名。 对于涉及两个文件系统路径的函数 (例如 os.rename()),filename2 将是传给函数的第二个文件名。

在 3.3 版更改: EnvironmentError, IOError, WindowsError, socket.error, select.errormmap.error 已被合并到 OSError,构造器可能返回其中一个子类。

在 3.4 版更改: filename 属性现在是传给函数的原始文件名,而不是基于 filesystem encoding and error handler 进行编码或解码之后的名称。 此外,还添加了 filename2 构造器参数和属性。

  • exception OverflowError

当算术运算的结果大到无法表示时将被引发。 这对整数来说不可能发生(宁可引发 MemoryError 也不会放弃尝试)。 但是出于历史原因,有时也会在整数超出要求范围的情况下引发 OverflowError。 因为在 C 中缺少对浮点异常处理的标准化,大多数浮点运算都不会做检查。

  • exception RecursionError

此异常派生自 RuntimeError。 它会在解释器检测发现超过最大递归深度 时被引发。

3.5 新版功能: 在此之前将只引发 RuntimeError

  • exception ReferenceError

此异常将在使用 weakref.proxy() 函数所创建的弱引用来访问该引用的某个已被作为垃圾回收的属性时被引发。

  • exception RuntimeError

当检测到一个不归属于任何其他类别的错误时将被引发。 关联的值是一个指明究竟发生了什么问题的字符串。

  • exception StopIteration

由内置函数 next() 和 iterator 的 __next__() 方法所引发,用来表示该迭代器不能产生下一项。

该异常对象只有一个属性 value,它在构造该异常时作为参数给出,默认值为 None

当一个 generator 或 coroutine 函数返回时,将引发一个新的 StopIteration 实例,函数返回的值将被用作异常构造器的 value 形参。

如果某个生成器代码直接或间接地引发了 StopIteration,它会被转换为 RuntimeError (并将 StopIteration 保留为导致新异常的原因)。

在 3.3 版更改: 添加了 value 属性及其被生成器函数用作返回值的功能。

在 3.5 版更改: 引入了通过 from __future__ import generator_stop 来实现 RuntimeError 转换,参见 PEP 479

在 3.7 版更改: 默认对所有代码启用 PEP 479: 在生成器中引发的 StopIteration 错误将被转换为 RuntimeError

  • exception StopAsyncIteration

必须由一个 asynchronous iterator 对象的 __anext__() 方法来引发以停止迭代操作。

3.5 新版功能.

  • exception SyntaxError(message, details)

    当解析器遇到语法错误时引发。 这可以发生在 import 语句,对内置函数 compile(), exec()eval() 的调用,或是读取原始脚本或标准输入(也包括交互模式)的时候。

    异常实例的 str() 只返回错误消息。 错误详情为一个元组,其成员也可在单独的属性中分别获取。

    • filename

      发生语法错误所在文件的名称。

    • lineno

      发生错误所在文件中的行号。 行号索引从 1 开始:文件中首行的 lineno 为 1。

    • offset

      发生错误所在文件中的列号。 列号索引从 1 开始:行中首个字符的 offset 为 1。

    • text

      错误所涉及的源代码文本。

    • end_lineno

      发生的错误在文件中的末尾行号。 这个索引是从 1 开始的:文件中首行的 lineno 为 1。

    • end_offset

      发生的错误在文件中的末尾列号。 这个索引是从 1 开始:行中首个字符的 offset 为 1。

对于 f-字符串字段中的错误,消息会带有 “f-string: “ 前缀并且其位置是基于替换表达式构建的文本中的位置。 例如,编译 f’Bad {a b} field’ 将产生这样的 args 属性: (‘f-string: …’, (‘’, 1, 2, ‘(a b)n’, 1, 5))。

在 3.10 版更改: 增加了 end_linenoend_offset 属性。

  • exception IndentationError

与不正确的缩进相关的语法错误的基类。 这是 SyntaxError 的一个子类。

  • exception TabError

当缩进包含对制表符和空格符不一致的使用时将被引发。 这是 IndentationError 的一个子类。

  • exception SystemError

当解释器发现内部错误,但情况看起来尚未严重到要放弃所有希望时将被引发。 关联的值是一个指明发生了什么问题的字符串(表示为低层级的符号)。

你应当将此问题报告给你所用 Python 解释器的作者或维护人员。 请确认报告 Python 解释器的版本号 (sys.version; 它也会在交互式 Python 会话开始时被打印出来),具体的错误消息(异常所关联的值)以及可能触发该错误的程序源码。

  • exception SystemExit

此异常由 sys.exit() 函数引发。 它继承自 BaseException 而不是 Exception 以确保不会被处理 Exception 的代码意外捕获。 这允许此异常正确地向上传播并导致解释器退出。 如果它未被处理,则 Python 解释器就将退出;不会打印任何栈回溯信息。 构造器接受的可选参数与传递给 sys.exit() 的相同。 如果该值为一个整数,则它指明系统退出状态码(会传递给 C 的 exit() 函数);如果该值为 None,则退出状态码为零;如果该值为其他类型(例如字符串),则会打印对象的值并将退出状态码设为一。

sys.exit() 的调用会被转换为一个异常以便能执行清理处理程序 (try 语句的 finally 子句),并且使得调试器可以执行一段脚本而不必冒失去控制的风险。 如果绝对确实地需要立即退出(例如在调用 os.fork() 之后的子进程中)则可使用 os._exit().

code

​ 传给构造器的退出状态码或错误信息(默认为 None。)

  • exception TypeError

当一个操作或函数被应用于类型不适当的对象时将被引发。 关联的值是一个字符串,给出有关类型不匹配的详情。

此异常可以由用户代码引发,以表明尝试对某个对象进行的操作不受支持也不应当受支持。 如果某个对象应当支持给定的操作但尚未提供相应的实现,所要引发的适当异常应为 NotImplementedError

传入参数的类型错误 (例如在要求 int 时却传入了 list) 应当导致 TypeError,但传入参数的值错误 (例如传入要求范围之外的数值) 则应当导致 ValueError

  • exception UnboundLocalError

当在函数或方法中对某个局部变量进行引用,但该变量并未绑定任何值时将被引发。 此异常是 NameError 的一个子类。

  • exception UnicodeError

    当发生与 Unicode 相关的编码或解码错误时将被引发。 此异常是 ValueError 的一个子类。

    UnicodeError 具有一些描述编码或解码错误的属性。 例如 err.object[err.start:err.end] 会给出导致编解码器失败的特定无效输入。

    • encoding

      引发错误的编码名称。

    • reason

      描述特定编解码器错误的字符串。

    • object

      编解码器试图要编码或解码的对象。

    • start

      object 中无效数据的开始位置索引。

    • end

      object 中无效数据的末尾位置索引(不含)。

  • exception UnicodeEncodeError

当在编码过程中发生与 Unicode 相关的错误时将被引发。 此异常是 UnicodeError 的一个子类。

  • exception UnicodeDecodeError

当在解码过程中发生与 Unicode 相关的错误时将被引发。 此异常是 UnicodeError 的一个子类。

  • exception UnicodeTranslateError

在转写过程中发生与 Unicode 相关的错误时将被引发。 此异常是 UnicodeError 的一个子类。

  • exception ValueError

当操作或函数接收到具有正确类型但值不适合的参数,并且情况不能用更精确的异常例如 IndexError 来描述时将被引发。

  • exception ZeroDivisionError

当除法或取余运算的第二个参数为零时将被引发。 关联的值是一个字符串,指明操作数和运算的类型。

下列异常被保留以与之前的版本相兼容;从 Python 3.3 开始,它们都是 OSError 的别名。

  • exception EnvironmentError

  • exception IOError

  • exception WindowsError

限在 Windows 中可用。

OS 异常

下列异常均为 OSError 的子类,它们将根据系统错误代码被引发。

  • exception BlockingIOError

当一个操作会被某个设置为非阻塞操作的对象(例如套接字)所阻塞时将被引发。 对应于 errno EAGAIN, EALREADY, EWOULDBLOCKEINPROGRESS

除了 OSError 已有的属性,BlockingIOError 还有一个额外属性:

  • characters_written

    一个整数,表示在被阻塞前已写入到流的字符数。 当使用来自 io 模块的带缓冲 I/O 类时此属性可用。

  • exception ChildProcessError

当一个子进程上的操作失败时将被引发。 对应于 errno ECHILD

  • exception ConnectionError

与连接相关问题的基类。

其子类有 BrokenPipeError, ConnectionAbortedError, ConnectionRefusedErrorConnectionResetError

  • exception BrokenPipeError

ConnectionError 的子类,当试图写入另一端已被关闭的管道,或是试图写入已关闭写入的套接字时将被引发。 对应于 errno EPIPEESHUTDOWN

  • exception ConnectionAbortedError

ConnectionError 的子类,当连接尝试被对端中止时将被引发。 对应于 errno ECONNABORTED

  • exception ConnectionRefusedError

ConnectionError 的子类,当连接尝试被对端拒绝时将被引发。 对应于 errno ECONNREFUSED

  • exception ConnectionResetError

ConnectionError 的子类,当连接被对端重置时将被引发。 对应于 errno ECONNRESET

  • exception FileExistsError

当试图创建一个已存在的文件或目录时将被引发。 对应于 errno EEXIST

  • exception FileNotFoundError

当所请求的文件或目录不存在时将被引发。 对应于 errno ENOENT

  • exception InterruptedError

当系统调用被输入信号中断时将被引发。 对应于 errno EINTR

在 3.5 版更改: 当系统调用被某个信号中断时,Python 现在会重试系统调用,除非该信号的处理程序引发了其它异常 (原理参见 PEP 475) 而不是引发 InterruptedError

  • exception IsADirectoryError

当请求对一个目录执行文件操作 (例如 os.remove()) 将被引发。 对应于 errno EISDIR

  • exception NotADirectoryError

当在非目录上请求目录操作 (例如 os.listdir()) 时被引发。 在大多数 POSIX 平台上,它还可能在某个操作尝试以目录方式打开或遍历非目录时被引发。 对应于 errno ENOTDIR

  • exception PermissionError

当在没有足够操作权限的情况下试图执行某个操作时将被引发 —— 例如缺少文件系统权限。 对应于 errno EACCESEPERM

  • exception ProcessLookupError

当给定的进程不存在时将被引发。 对应于 errno ESRCH

  • exception TimeoutError

当一个系统函数发生系统级超时的情况下将被引发。 对应于 errno ETIMEDOUT

3.3 新版功能: 添加了以上所有 OSError 的子类。

参见

PEP 3151 - 重写 OS 和 IO 异常的层次结构

警告

下列异常被用作警告类别

  • exception Warning

警告类别的基类。

  • exception UserWarning

用户代码所产生警告的基类。

  • exception DeprecationWarning

如果所发出的警告是针对其他 Python 开发者的,则以此作为与已弃用特性相关警告的基类。

会被默认警告过滤器忽略,在 __main__ 模块中的情况除外 (PEP 565)。 启用 Python 开发模式 时会显示此警告。

The deprecation policy is described in PEP 387.

  • exception PendingDeprecationWarning

对于已过时并预计在未来弃用,但目前尚未弃用的特性相关警告的基类。

这个类很少被使用,因为针对未来可能的弃用发出警告的做法并不常见,而针对当前已有的弃用则推荐使用 DeprecationWarning

会被默认警告过滤器忽略。 启用 Python 开发模式 时会显示此警告。

The deprecation policy is described in PEP 387.

  • exception SyntaxWarning

与模糊的语法相关的警告的基类。

  • exception RuntimeWarning

与模糊的运行时行为相关的警告的基类。

  • exception FutureWarning

如果所发出的警告是针对以 Python 所编写应用的最终用户的,则以此作为与已弃用特性相关警告的基类。

  • exception ImportWarning

与在模块导入中可能的错误相关的警告的基类。

会被默认警告过滤器忽略。 启用 Python 开发模式 时会显示此警告。

  • exception UnicodeWarning

与 Unicode 相关的警告的基类。

  • exception EncodingWarning

与编码格式相关的警告的基类。

3.10 新版功能.

  • exception BytesWarning

bytesbytearray 相关的警告的基类。

  • exception ResourceWarning

资源使用相关警告的基类。

会被默认警告过滤器忽略。 启用 Python 开发模式 时会显示此警告。

3.2 新版功能.

异常层次结构

内置异常的类层级结构如下:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- EncodingWarning
           +-- ResourceWarning

文本处理服务

在 二进制数据服务 之下描述的 codecs 模块也与文本处理高度相关。

  • string —- 常见的字符串操作
    • 字符串常量
    • 自定义字符串格式化
    • 格式字符串语法
      • 格式规格迷你语言
      • 格式示例
    • 模板字符串
    • 辅助函数
  • re —- 正则表达式操作
    • 正则表达式语法
    • 模块内容
    • 正则表达式对象 (正则对象)
    • 匹配对象
    • 正则表达式例子
      • 检查对子
      • 模拟 scanf()
      • search() vs. match()
      • 制作一个电话本
      • 文字整理
      • 查找所有副词
      • 查找所有的副词及其位置
      • 原始字符串标记
      • 写一个词法分析器
  • difflib —- 计算差异的辅助工具
    • SequenceMatcher 对象
    • SequenceMatcher 的示例
    • Differ 对象
    • Differ 示例
    • difflib 的命令行接口
  • textwrap —- 文本自动换行与填充
  • unicodedata —- Unicode 数据库
  • stringprep —- 因特网字符串预备
  • readline —- GNU readline 接口
    • 初始化文件
    • 行缓冲区
    • 历史文件
    • 历史列表
    • 启动钩子
    • Completion
    • 示例
  • rlcompleter —- GNU readline 的补全函数
    • Completer 对象

string —- 常见的字符串操作

源代码: Lib/string.py

字符串常量

此模块中定义的常量为:

string.ascii_letters

下文所述 ascii_lowercaseascii_uppercase 常量的拼连。 该值不依赖于语言区域。

string.ascii_lowercase

小写字母 'abcdefghijklmnopqrstuvwxyz'。 该值不依赖于语言区域,不会发生改变。

string.ascii_uppercase

大写字母 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'。 该值不依赖于语言区域,不会发生改变。

string.digits

字符串 '0123456789'

string.hexdigits

字符串 '0123456789abcdefABCDEF'

string.octdigits

字符串 '01234567'

string.punctuation

由在 C 区域设置中被视为标点符号的 ASCII 字符所组成的字符串: !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`.

string.printable

由被视为可打印符号的 ASCII 字符组成的字符串。 这是 digits, ascii_letters, punctuationwhitespace 的总和。

string.whitespace

由被视为空白符号的 ASCII 字符组成的字符串。 其中包括空格、制表、换行、回车、进纸和纵向制表符。

自定义字符串格式化

内置的字符串类提供了通过使用 PEP 3101 所描述的 format() 方法进行复杂变量替换和值格式化的能力。 string 模块中的 Formatter 类允许你使用与内置 format() 方法相同的实现来创建并定制你自己的字符串格式化行为。

class string.Formatter

Formatter 类包含下列公有方法:

  • format(format_string, /, \args, *kwargs)

    首要的 API 方法。 它接受一个格式字符串和任意一组位置和关键字参数。 它只是一个调用 vformat() 的包装器。

    在 3.7 版更改: 格式字符串参数现在是 仅限位置参数。

  • vformat(format_string, args, kwargs)

    此函数执行实际的格式化操作。 它被公开为一个单独的函数,用于需要传入一个预定义字母作为参数,而不是使用 *args**kwargs 语法将字典解包为多个单独参数并重打包的情况。 vformat() 完成将格式字符串分解为字符数据和替换字段的工作。 它会调用下文所述的几种不同方法。

此外,Formatter 还定义了一些旨在被子类替换的方法:

  • parse(format_string)

    循环遍历 format_string 并返回一个由可迭代对象组成的元组 (literal_text, field_name, format_spec, conversion)。 它会被 vformat() 用来将字符串分解为文本字面值或替换字段。

    元组中的值在概念上表示一段字面文本加上一个替换字段。 如果没有字面文本(如果连续出现两个替换字段就会发生这种情况),则 literal_text 将是一个长度为零的字符串。 如果没有替换字段,则 field_name, format_specconversion 的值将为 None

  • get_field(field_name, args, kwargs)

    给定 field_name 作为 parse() (见上文) 的返回值,将其转换为要格式化的对象。 返回一个元组 (obj, used_key)。 默认版本接受在 PEP 3101 所定义形式的字符串,例如 “0[name]“ 或 “label.title”。 argskwargs 与传给 vformat() 的一样。 返回值 used_keyget_value()key 形参具有相同的含义。

  • get_value(key, args, kwargs)

    提取给定的字段值。 key 参数将为整数或字符串。 如果是整数,它表示 args 中位置参数的索引;如果是字符串,它表示 kwargs 中的关键字参数名。

    args 形参会被设为 vformat() 的位置参数列表,而 kwargs 形参会被设为由关键字参数组成的字典。

    对于复合字段名称,仅会为字段名称的第一个组件调用这些函数;后续组件会通过普通属性和索引操作来进行处理。

    因此举例来说,字段表达式 ‘0.name’ 将导致调用 get_value() 时附带 key 参数值 0。 在 get_value() 通过调用内置的 getattr() 函数返回后将会查找 name 属性。

    如果索引或关键字引用了一个不存在的项,则将引发 IndexErrorKeyError

  • check_unused_args(used_args, args, kwargs)

    在必要时实现对未使用参数进行检测。 此函数的参数是是格式字符串中实际引用的所有参数键的集合(整数表示位置参数,字符串表示名称参数),以及被传给 vformat 的 argskwargs 的引用。 未使用参数的集合可以根据这些形参计算出来。 如果检测失败则 check_unused_args() 应会引发一个异常。

  • format_field(value, format_spec)

    format_field() 会简单地调用内置全局函数 format()。 提供该方法是为了让子类能够重载它。

  • convert_field(value, conversion)

    使用给定的转换类型(来自 parse() 方法所返回的元组)来转换(由 get_field() 所返回的)值。 默认版本支持 ‘s’ (str), ‘r’ (repr) 和 ‘a’ (ascii) 等转换类型。

格式字符串语法

str.format() 方法和 Formatter 类共享相同的格式字符串语法(虽然对于 Formatter 来说,其子类可以定义它们自己的格式字符串语法)。 具体语法与 格式化字符串字面值 相似,但较为简单一些,并且关键的一点是不支持任意表达式。

格式字符串包含有以花括号 {} 括起来的“替换字段”。 不在花括号之内的内容被视为字面文本,会不加修改地复制到输出中。 如果你需要在字面文本中包含花括号字符,可以通过重复来转义: {{` and `}}

替换字段的语法如下:

replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
arg_name          ::=  [identifier | digit+]
attribute_name    ::=  identifier
element_index     ::=  digit+ | index_string
index_string      ::=  <any source character except "]"> +
conversion        ::=  "r" | "s" | "a"
format_spec       ::=  <described in the next section>

用不太正式的术语来描述,替换字段开头可以用一个 field_name 指定要对值进行格式化并取代替换字符被插入到输出结果的对象。 field_name 之后有可选的 conversion 字段,它是一个感叹号 '!' 加一个 format_spec,并以一个冒号 ':' 打头。 这些指明了替换值的非默认格式。

field_name 本身以一个数字或关键字 arg_name 打头。 如果为数字,则它指向一个位置参数,而如果为关键字,则它指向一个命名关键字参数。 如果格式字符串中的数字 arg_names 为 0, 1, 2, … 的序列,它们可以全部省略(而非部分省略),数字 0, 1, 2, … 将会按顺序自动插入。 由于 arg_name 不使用引号分隔,因此无法在格式字符串中指定任意的字典键 (例如字符串 '10'':-]')。 arg_name 之后可以带上任意数量的索引或属性表达式。 '.name' 形式的表达式会使用 getattr() 选择命名属性,而 '[index]' 形式的表达式会使用 __getitem__() 执行索引查找。

在 3.1 版更改: 位置参数说明符对于 str.format() 可以省略,因此 '{} {}'.format(a, b) 等价于 '{0} {1}'.format(a, b)

在 3.4 版更改: 位置参数说明符对于 Formatter 可以省略。

一些简单的格式字符串示例

"First, thou shalt count to {0}"  # References first positional argument
"Bring me a {}"                   # Implicitly references the first positional argument
"From {} to {}"                   # Same as "From {0} to {1}"
"My quest is {name}"              # References keyword argument 'name'
"Weight in tons {0.weight}"       # 'weight' attribute of first positional arg
"Units destroyed: {players[0]}"   # First element of keyword argument 'players'.

使用 conversion 字段在格式化之前进行类型强制转换。 通常,格式化值的工作由值本身的 __format__() 方法来完成。 但是,在某些情况下最好强制将类型格式化为一个字符串,覆盖其本身的格式化定义。 通过在调用 __format__() 之前将值转换为字符串,可以绕过正常的格式化逻辑。

目前支持的转换旗标有三种: '!s' 会对值调用 str()'!r' 调用 repr()'!a' 则调用 ascii()

示例如下:

"Harold's a clever {0!s}"        # Calls str() on the argument first
"Bring out the holy {name!r}"    # Calls repr() on the argument first
"More {!a}"                      # Calls ascii() on the argument first

format_spec 字段包含值应如何呈现的规格描述,例如字段宽度、对齐、填充、小数精度等细节信息。 每种值类型可以定义自己的“格式化迷你语言”或对 format_spec 的解读方式。

大多数内置类型都支持同样的格式化迷你语言,具体描述见下一节。

format_spec 字段还可以在其内部包含嵌套的替换字段。 这些嵌套的替换字段可能包括字段名称、转换旗标和格式规格描述,但是不再允许更深层的嵌套。 format_spec 内部的替换字段会在解读 format_spec 字符串之前先被解读。 这将允许动态地指定特定值的格式。

格式规格迷你语言

“格式规格”在格式字符串所包含的替换字段内部使用,用于定义单个值应如何呈现 。 它们也可以被直接传给内置的 format() 函数。 每种可格式化的类型都可以自行定义如何对格式规格进行解读。

大多数内置类型都为格式规格实现了下列选项,不过某些格式化选项只被数值类型所支持。

一般约定空的格式描述将产生与在值上调用 str() 相同的结果。 非空格式描述通常会修改此结果。

标准格式说明符 的一般形式如下:

format_spec     ::=  [[fill]align][sign][#][0][width][grouping_option][.precision][type]
fill            ::=  <any character>
align           ::=  "<" | ">" | "=" | "^"
sign            ::=  "+" | "-" | " "
width           ::=  digit+
grouping_option ::=  "_" | ","
precision       ::=  digit+
type            ::=  "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"

如果指定了一个有效的 align 值,则可以在该值前面加一个 fill 字符,它可以为任意字符,如果省略则默认为空格符。 在 格式化字符串字面值 或在使用 str.format() 方法时是无法使用花括号字面值 (“{“ or “}“) 作为 fill 字符的。 但是,通过嵌套替换字段插入花括号则是可以的。 这个限制不会影响 format() 函数。

各种对齐选项的含义如下:

选项 含意
‘<’ 强制字段在可用空间内左对齐(这是大多数对象的默认值)。
‘>’ 强制字段在可用空间内右对齐(这是数字的默认值)。
‘=’ 强制在符号(如果有)之后数码之前放置填充。 这被用于以 ‘+000000120’ 形式打印字段。 这个对齐选项仅对数字类型有效。 这是当 ‘0’ 紧接在字段宽度之前时的默认选项。
‘^’ 强制字段在可用空间内居中。

请注意,除非定义了最小字段宽度,否则字段宽度将始终与填充它的数据大小相同,因此在这种情况下,对齐选项没有意义。

sign 选项仅对数字类型有效,可以是以下之一:

选项 含意
‘+’ 表示标志应该用于正数和负数。
‘-‘ 表示标志应仅用于负数(这是默认行为)。
space 表示应在正数上使用前导空格,在负数上使用减号。

'#' 选项可让“替代形式”被用于执行转换。 替代形式会针对不同的类型分别定义。 此选项仅适用于整数、浮点数和复数类型。 对于整数类型,当使用二进制、八进制或十六进制输出时,此选项会为输出值分别添加相应的 '0b', '0o', '0x''0X' 前缀。 对于浮点数和复数类型,替代形式会使得转换结果总是包含小数点符号,即使其不带小数部分。 通常只有在带有小数部分的情况下,此类转换的结果中才会出现小数点符号。 此外,对于 'g''G' 转换,末尾的零不会从结果中被移除。

',' 选项表示使用逗号作为千位分隔符。 对于感应区域设置的分隔符,请改用 'n' 整数表示类型。

在 3.1 版更改: 添加了 ',' 选项 (另请参阅 PEP 378)。

'_' 选项表示对浮点表示类型和整数表示类型 'd' 使用下划线作为千位分隔符。 对于整数表示类型 'b', 'o', 'x''X',将为每 4 个数位插入一个下划线。 对于其他表示类型指定此选项则将导致错误。

在 3.6 版更改: 添加了 '_' 选项 (另请参阅 PEP 515)。

width 是一个定义最小总字段宽度的十进制整数,包括任何前缀、分隔符和其他格式化字符。 如果未指定,则字段宽度将由内容确定。

当未显式给出对齐方式时,在 width 字段前加一个零 ('0') 字段将为数字类型启用感知正负号的零填充。 这相当于设置 fill 字符为 '0'alignment 类型为 '='

在 3.10 版更改: 在 width 字段之前添加 '0' 不会再影响字符串的默认对齐。

precision 是一个十进制数字,表示对于以 'f' and 'F' 格式化的浮点数值要在小数点后显示多少个数位,或者对于以 'g''G' 格式化的浮点数值要在小数点前后共显示多少个数位。 对于非数字类型,该字段表示最大字段大小 —— 换句话说就是要使用多少个来自字段内容的字符。 对于整数值则不允许使用 precision

最后,type 确定了数据应如何呈现。

可用的字符串表示类型是:

类型 含意
‘s’ 字符串格式。这是字符串的默认类型,可以省略。
None ‘s’ 一样。

可用的整数表示类型是:

类型 含意
‘b’ 二进制格式。 输出以 2 为基数的数字。
‘c’ 字符。在打印之前将整数转换为相应的unicode字符。
‘d’ 十进制整数。 输出以 10 为基数的数字。
‘o’ 八进制格式。 输出以 8 为基数的数字。
‘x’ 十六进制格式。 输出以 16 为基数的数字,使用小写字母表示 9 以上的数码。
‘X’ 十六进制格式。 输出以 16 为基数的数字,使用大写字母表示 9 以上的数码。 在指定 ‘#’ 的情况下,前缀 ‘0x’ 也将被转为大写形式 ‘0X’
‘n’ 数字。 这与 ‘d’ 相似,不同之处在于它会使用当前区域设置来插入适当的数字分隔字符。
None ‘d’ 相同。

在上述的表示类型之外,整数还可以通过下列的浮点表示类型来格式化 (除了 'n'None)。 当这样做时,会在格式化之前使用 float() 将整数转换为浮点数。

floatDecimal 值的可用表示类型有:

类型 含意
‘e’ 科学计数法。 对于一个给定的精度 p,将数字格式化为以字母 ‘e’ 分隔系数和指数的科学计数法形式。 系数在小数点之前有一位,之后有 p 位,总计 p + 1 个有效数位。 如未指定精度,则会对 float 采用小数点之后 6 位精度,而对 Decimal 则显示所有系数位。 如果小数点之后没有数位,则小数点也会被略去,除非使用了 # 选项。
‘E’ 科学计数法。 与 ‘e’ 相似,不同之处在于它使用大写字母 ‘E’ 作为分隔字符。
‘f’ 定点表示法。 对于一个给定的精度 p,将数字格式化为在小数点之后恰好有 p 位的小数形式。 如未指定精度,则会对 float 采用小数点之后 6 位精度,而对 Decimal 则使用大到足够显示所有系数位的精度。 如果小数点之后没有数位,则小数点也会被略去,除非使用了 # 选项。
‘F’ 定点表示。 与 ‘f’ 相似,但会将 nan 转为 NAN 并将 inf 转为 INF
‘g’ 常规格式。 对于给定精度 p >= 1,这会将数值舍入到 p 个有效数位,再将结果以定点表示法或科学计数法进行格式化,具体取决于其值的大小。 精度 0 会被视为等价于精度 1。准确的规则如下:假设使用表示类型 ‘e’ 和精度 p-1 进行格式化的结果具有指数值 exp。 那么如果 m <= exp < p,其中 m 以 -4 表示浮点值而以 -6 表示 Decimal 值,该数字将使用类型 ‘f’ 和精度 p-1-exp 进行格式化。 否则的话,该数字将使用表示类型 ‘e’ 和精度 p-1 进行格式化。 在两种情况下,都会从有效数字中移除无意义的末尾零,如果小数点之后没有余下数字则小数点也会被移除,除非使用了 ‘#’ 选项。如未指定精度,会对 float 采用 6 个有效数位的精度。 对于 Decimal,结果的系数会沿用原值的系数数位;对于绝对值小于 1e-6 的值以及最小有效数位的位值大于 1 的数值将会使用科学计数法,在其他情况下则会使用定点表示法。正负无穷,正负零和 nan 会分别被格式化为 inf, -inf, 0, -0nan,无论精度如何设定。
‘G’ 常规格式。 类似于 ‘g’,不同之处在于当数值非常大时会切换为 ‘E’。 无穷与 NaN 也会表示为大写形式。
‘n’ 数字。 这与 ‘g’ 相似,不同之处在于它会使用当前区域设置来插入适当的数字分隔字符。
‘%’ 百分比。 将数字乘以 100 并显示为定点 (‘f’) 格式,后面带一个百分号。
None 对于 float 来说这类似于 ‘g’,不同之处在于当使用定点表示法时,小数点之后将至少显示一位。 所用的精度会大到足以精确表示给定的值。对于 Decimal 来说这相当于 ‘g’‘G’,具体取决于当前 decimal 上下文的 context.capitals 值。总体效果是将 str() 的输出匹配为其他格式化因子所调整出的样子。

格式示例

本节包含 str.format() 语法的示例以及与旧式 % 格式化的比较。

该语法在大多数情况下与旧式的 % 格式化类似,只是增加了 {}: 来取代 %。 例如,,'%03.2f' 可以被改写为 '{:03.2f}'

新的格式语法还支持新增的不同选项,将在以下示例中说明。

按位置访问参数:

>>> '{0}, {1}, {2}'.format('a', 'b', 'c')
'a, b, c'
>>> '{}, {}, {}'.format('a', 'b', 'c')  # 3.1+ only
'a, b, c'
>>> '{2}, {1}, {0}'.format('a', 'b', 'c')
'c, b, a'
>>> '{2}, {1}, {0}'.format(*'abc')      # unpacking argument sequence
'c, b, a'
>>> '{0}{1}{0}'.format('abra', 'cad')   # arguments' indices can be repeated
'abracadabra'

按名称访问参数:

>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'
>>> coord = {'latitude': '37.24N', 'longitude': '-115.81W'}
>>> 'Coordinates: {latitude}, {longitude}'.format(**coord)
'Coordinates: 37.24N, -115.81W'

访问参数的属性:

>>> c = 3-5j
>>> ('The complex number {0} is formed from the real part {0.real} '
...  'and the imaginary part {0.imag}.').format(c)
'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.'
>>> class Point:
...     def __init__(self, x, y):
...         self.x, self.y = x, y
...     def __str__(self):
...         return 'Point({self.x}, {self.y})'.format(self=self)
...
>>> str(Point(4, 2))
'Point(4, 2)'

访问参数的项:

>>> coord = (3, 5)
>>> 'X: {0[0]};  Y: {0[1]}'.format(coord)
'X: 3;  Y: 5'

替代 %s%r:

>>> "repr() shows quotes: {!r}; str() doesn't: {!s}".format('test1', 'test2')
"repr() shows quotes: 'test1'; str() doesn't: test2"

对齐文本以及指定宽度:

>>> '{:<30}'.format('left aligned')
'left aligned                  '
>>> '{:>30}'.format('right aligned')
'                 right aligned'
>>> '{:^30}'.format('centered')
'           centered           '
>>> '{:*^30}'.format('centered')  # use '*' as a fill char
'***********centered***********'

替代 %+f, %-f% f 以及指定正负号:

>>> '{:+f}; {:+f}'.format(3.14, -3.14)  # show it always
'+3.140000; -3.140000'
>>> '{: f}; {: f}'.format(3.14, -3.14)  # show a space for positive numbers
' 3.140000; -3.140000'
>>> '{:-f}; {:-f}'.format(3.14, -3.14)  # show only the minus -- same as '{:f}; {:f}'
'3.140000; -3.140000'

替代 %x%o 以及转换基于不同进位制的值:

>>> # format also supports binary numbers
>>> "int: {0:d};  hex: {0:x};  oct: {0:o};  bin: {0:b}".format(42)
'int: 42;  hex: 2a;  oct: 52;  bin: 101010'
>>> # with 0x, 0o, or 0b as prefix:
>>> "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}".format(42)
'int: 42;  hex: 0x2a;  oct: 0o52;  bin: 0b101010'

使用逗号作为千位分隔符:

>>> '{:,}'.format(1234567890)
'1,234,567,890'

表示为百分数:

>>> points = 19
>>> total = 22
>>> 'Correct answers: {:.2%}'.format(points/total)
'Correct answers: 86.36%'

使用特定类型的专属格式化:

>>> import datetime
>>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
>>> '{:%Y-%m-%d %H:%M:%S}'.format(d)
'2010-07-04 12:15:58'

嵌套参数以及更复杂的示例:

>>> for align, text in zip('<^>', ['left', 'center', 'right']):
...     '{0:{fill}{align}16}'.format(text, fill=align, align=align)
...
'left<<<<<<<<<<<<'
'^^^^^center^^^^^'
'>>>>>>>>>>>right'
>>>
>>> octets = [192, 168, 0, 1]
>>> '{:02X}{:02X}{:02X}{:02X}'.format(*octets)
'C0A80001'
>>> int(_, 16)
3232235521
>>>
>>> width = 5
>>> for num in range(5,12): 
...     for base in 'dXob':
...         print('{0:{width}{base}}'.format(num, base=base, width=width), end=' ')
...     print()
...
    5     5     5   101
    6     6     6   110
    7     7     7   111
    8     8    10  1000
    9     9    11  1001
   10     A    12  1010
   11     B    13  1011

模板字符串

模板字符串提供了由 PEP 292 所描述的更简便的字符串替换方式。 模板字符串的一个主要用例是文本国际化 (i18n),因为在此场景下,更简单的语法和功能使得文本翻译过程比使用 Python 的其他内置字符串格式化工具更为方便。 作为基于模板字符串构建以实现 i18n 的库的一个示例,请参看 flufl.i18n 包。

模板字符串支持基于 $ 的替换,使用以下规则:

  • $$ 为转义符号;它会被替换为单个的 $
  • $identifier 为替换占位符,它会匹配一个名为 "identifier" 的映射键。 在默认情况下,"identifier" 限制为任意 ASCII 字母数字(包括下划线)组成的字符串,不区分大小写,以下划线或 ASCII 字母开头。 在 $ 字符之后的第一个非标识符字符将表明占位符的终结。
  • ${identifier} 等价于 $identifier。 当占位符之后紧跟着有效的但又不是占位符一部分的标识符字符时需要使用,例如 "${noun}ification"

在字符串的其他位置出现 $ 将导致引发 ValueError

string 模块提供了实现这些规则的 Template 类。 Template 有下列方法:

class string.Template(template)

该构造器接受一个参数作为模板字符串。

  • substitute(mapping={}, /, **kwds)

    执行模板替换,返回一个新字符串。 mapping 为任意字典类对象,其中的键将匹配模板中的占位符。 或者你也可以提供一组关键字参数,其中的关键字即对应占位符。 当同时给出 mappingkwds 并且存在重复时,则以 kwds 中的占位符为优先。

  • safe_substitute(mapping={}, /, **kwds)

    类似于 substitute(),不同之处是如果有占位符未在 mappingkwds 中找到,不是引发 KeyError 异常,而是将原始占位符不加修改地显示在结果字符串中。 另一个与 substitute() 的差异是任何在其他情况下出现的 $ 将简单地返回 $ 而不是引发 ValueError

    此方法被认为“安全”,因为虽然仍有可能发生其他异常,但它总是尝试返回可用的字符串而不是引发一个异常。 从另一方面来说,safe_substitute() 也可能根本算不上安全,因为它将静默地忽略错误格式的模板,例如包含多余的分隔符、不成对的花括号或不是合法 Python 标识符的占位符等等。

Template 的实例还提供一个公有数据属性:

  • template

    这是作为构造器的 template 参数被传入的对象。 一般来说,你不应该修改它,但并不强制要求只读访问。

以下是一个如何使用模版的示例:

>>> from string import Template
>>> s = Template('$who likes $what')
>>> s.substitute(who='tim', what='kung pao')
'tim likes kung pao'
>>> d = dict(who='tim')
>>> Template('Give $who $100').substitute(d)
Traceback (most recent call last):
...
ValueError: Invalid placeholder in string: line 1, col 11
>>> Template('$who likes $what').substitute(d)
Traceback (most recent call last):
...
KeyError: 'what'
>>> Template('$who likes $what').safe_substitute(d)
'tim likes $what'

进阶用法:你可以派生 Template 的子类来自定义占位符语法、分隔符,或用于解析模板字符串的整个正则表达式。 为此目的,你可以重载这些类属性:

  • delimiter — 这是用来表示占位符的起始的分隔符的字符串字面值。 默认值为 $。 请注意此参数 不能 为正则表达式,因为其实现将在必要时对此字符串调用 re.escape()。 还要注意你不能在创建类之后改变此分隔符(例如在子类的类命名空间中必须设置不同的分隔符)。

  • idpattern — 这是用来描述不带花括号的占位符的模式的正则表达式。 默认值为正则表达式 (?a:[_a-z][_a-z0-9]*)。 如果给出了此属性并且 braceidpatternNone 则此模式也将作用于带花括号的占位符。

    注解

    由于默认的 flagsre.IGNORECASE,模式 [a-z] 可以匹配某些非 ASCII 字符。 因此我们在这里使用了局部旗标 a

    在 3.7 版更改: braceidpattern 可被用来定义对花括号内部和外部进行区分的模式。

  • braceidpattern — 此属性类似于 idpattern 但是用来描述带花括号的占位符的模式。 默认值 None 意味着回退到 idpattern (即在花括号内部和外部使用相同的模式)。 如果给出此属性,这将允许你为带花括号和不带花括号的占位符定义不同的模式。

    3.7 新版功能.

  • flags — 将在编译用于识别替换内容的正则表达式被应用的正则表达式旗标。 默认值为 re.IGNORECASE。 请注意 re.VERBOSE 总是会被加为旗标,因此自定义的 idpattern 必须遵循详细正则表达式的约定。

    3.2 新版功能.

作为另一种选项,你可以通过重载类属性 pattern 来提供整个正则表达式模式。 如果你这样做,该值必须为一个具有四个命名捕获组的正则表达式对象。 这些捕获组对应于上面已经给出的规则,以及无效占位符的规则:

  • escaped — 这个组匹配转义序列,在默认模式中即 $$
  • named — 这个组匹配不带花括号的占位符名称;它不应当包含捕获组中的分隔符。
  • braced — 这个组匹配带有花括号的占位符名称;它不应当包含捕获组中的分隔符或者花括号。
  • invalid — 这个组匹配任何其他分隔符模式(通常为单个分隔符),并且它应当出现在正则表达式的末尾。

辅助函数

string.capwords(s, sep=None)

使用 str.split() 将参数拆分为单词,使用 str.capitalize() 将单词转为大写形式,使用 str.join() 将大写的单词进行拼接。 如果可选的第二个参数 sep 被省略或为 None,则连续的空白字符会被替换为单个空格符并且开头和末尾的空白字符会被移除,否则 sep 会被用来拆分和拼接单词。

re —- 正则表达式操作

源代码: Lib/re.py


本模块提供了与 Perl 语言类似的正则表达式匹配操作。

模式和被搜索的字符串既可以是 Unicode 字符串 (str) ,也可以是8位字节串 (bytes)。 但是,Unicode 字符串与 8 位字节串不能混用:也就是说,不能用字节串模式匹配 Unicode 字符串,反之亦然;同理,替换操作时,替换字符串的类型也必须与所用的模式和搜索字符串的类型一致。

正则表达式用反斜杠字符 ('\') 表示特殊形式,或是允许在使用特殊字符时,不引发它们的特殊含义。 这与 Python 的字符串字面值中对相同字符出于相同目的的用法产生冲突;例如,要匹配一个反斜杠字面值,用户可能必须写成 '\\\\' 来作为模式字符串,因为正则表达式必须为 \\,而每个反斜杠在普通 Python 字符串字面值中又必须表示为 \\。 而且还要注意,在 Python 的字符串字面值中使用的反斜杠如果有任何无效的转义序列,现在会触发 DeprecationWarning,但以后会改为 SyntaxError。 此行为即使对于正则表达式来说有效的转义字符同样会发生。

解决办法是对于正则表达式样式使用 Python 的原始字符串表示法;在带有 'r' 前缀的字符串字面值中,反斜杠不必做任何特殊处理。 因此 r"\n" 表示包含 '\''n' 两个字符的字符串,而 "\n" 则表示只包含一个换行符的字符串。 样式在 Python 代码中通常都使用原始字符串表示法。

绝大多数正则表达式操作都提供为模块函数和方法,在 编译正则表达式. 这些函数是一个捷径,不需要先编译正则对象,但是损失了一些优化参数。

参见

第三方模块 regex , 提供了与标准库 re 模块兼容的 API 接口,同时,还提供了更多功能和更全面的 Unicode 支持。

正则表达式语法

正则表达式(或 RE)指定了一组与之匹配的字符串;模块内的函数可以检查某个字符串是否与给定的正则表达式匹配(或者正则表达式是否匹配到字符串,这两种说法含义相同)。

正则表达式可以拼接;如果 AB 都是正则表达式,则 AB 也是正则表达式。通常,如果字符串 p 匹配 A,并且另一个字符串 q 匹配 B,那么 pq 可以匹配 AB。除非 A 或者 B 包含低优先级操作,AB 存在边界条件;或者命名组引用。所以,复杂表达式可以很容易的从这里描述的简单源语表达式构建。

正则表达式可以包含普通或者特殊字符。绝大部分普通字符,比如 'A', 'a', 或者 '0',都是最简单的正则表达式。它们就匹配自身。你可以拼接普通字符,所以 last 匹配字符串 'last'. (在这一节的其他部分,我们将用 this special style 这种方式表示正则表达式,通常不带引号,要匹配的字符串用 'in single quotes' ,单引号形式。)

有些字符,比如 '|' 或者 '(',属于特殊字符。 特殊字符既可以表示它的普通含义, 也可以影响它旁边的正则表达式的解释。

重复修饰符 (*, +, ?, {m,n}, 等) 不能直接嵌套。这样避免了非贪婪后缀 ? 修饰符,和其他实现中的修饰符产生的多义性。要应用一个内层重复嵌套,可以使用括号。 比如,表达式 (?:a{6})* 匹配6个 'a' 字符重复任意次数。

特殊字符有:

.

(点) 在默认模式,匹配除了换行的任意字符。如果指定了标签 DOTALL ,它将匹配包括换行符的任意字符。

^

(插入符号) 匹配字符串的开头, 并且在 MULTILINE 模式也匹配换行后的首个符号。

$

匹配字符串尾或者在字符串尾的换行符的前一个字符,在 MULTILINE 模式下也会匹配换行符之前的文本。 foo 匹配 ‘foo’ 和 ‘foobar’,但正则表达式 foo$ 只匹配 ‘foo’。 更有趣的是,在 'foo1\nfoo2\n' 中搜索 foo.$,通常匹配 ‘foo2’,但在 MULTILINE 模式下可以匹配到 ‘foo1’;在 'foo\n' 中搜索 $ 会找到两个(空的)匹配:一个在换行符之前,一个在字符串的末尾。

*

对它前面的正则式匹配0到任意次重复, 尽量多的匹配字符串。 ab* 会匹配 'a''ab',或者 'a' 后面跟随任意个 'b'

+

对它前面的正则式匹配1到任意次重复。 ab+ 会匹配 'a' 后面跟随1个以上到任意个 'b',它不会匹配 'a'

?

对它前面的正则式匹配0到1次重复。 ab? 会匹配 'a' 或者 'ab'

*?, +?, ??

'*', '+',和 '?' 修饰符都是 贪婪的*;它们在字符串进行尽可能多的匹配。有时候并不需要这种行为。如果正则式 `<.>希望找到 b ,它将会匹配整个字符串,而不仅是。在修饰符之后添加?将使样式以 *非贪婪方式或者 :dfn:最小* 方式进行匹配; 尽量 *少* 的字符将会被匹配。 使用正则式<.*?>将会仅仅匹配‘`。

{m}

对其之前的正则式指定匹配 m 个重复;少于 m 的话就会导致匹配失败。比如, a{6} 将匹配6个 'a' , 但是不能是5个。

{m,n}

对正则式进行 mn 次匹配,在 mn 之间取尽量多。 比如,a{3,5} 将匹配 3 到 5个 'a'。忽略 m 意为指定下界为0,忽略 n 指定上界为无限次。 比如 a{4,}b 将匹配 'aaaab' 或者1000个 'a' 尾随一个 'b',但不能匹配 'aaab'。逗号不能省略,否则无法辨别修饰符应该忽略哪个边界。

{m,n}?

前一个修饰符的非贪婪模式,只匹配尽量少的字符次数。比如,对于 'aaaaaa'a{3,5} 匹配 5个 'a' ,而 a{3,5}? 只匹配3个 'a'

\

转义特殊字符(允许你匹配 '*', '?', 或者此类其他),或者表示一个特殊序列;特殊序列之后进行讨论。

如果你没有使用原始字符串( r'raw' )来表达样式,要牢记Python也使用反斜杠作为转义序列;如果转义序列不被Python的分析器识别,反斜杠和字符才能出现在字符串中。如果Python可以识别这个序列,那么反斜杠就应该重复两次。这将导致理解障碍,所以高度推荐,就算是最简单的表达式,也要使用原始字符串。

[]

用于表示一个字符集合。在一个集合中:

在 3.7 版更改: 如果一个字符串构建的语义在未来会改变的话,一个 FutureWarningraise

|

A|BAB 可以是任意正则表达式,创建一个正则表达式,匹配 A 或者 B. 任意个正则表达式可以用 '|' 连接。它也可以在组合(见下列)内使用。扫描目标字符串时, '|' 分隔开的正则样式从左到右进行匹配。当一个样式完全匹配时,这个分支就被接受。意思就是,一旦 A 匹配成功, B 就不再进行匹配,即便它能产生一个更好的匹配。或者说,'|' 操作符绝不贪婪。 如果要匹配 '|' 字符,使用 \|, 或者把它包含在字符集里,比如 [|].

(...)

(组合),匹配括号内的任意正则表达式,并标识出组合的开始和结尾。匹配完成后,组合的内容可以被获取,并可以在之后用 \number 转义序列进行再次匹配,之后进行详细说明。要匹配字符 '(' 或者 ')', 用 \(\), 或者把它们包含在字符集合里: [(], [)].

(?…)

这是个扩展标记法 (一个 '?' 跟随 '(' 并无含义)。 '?' 后面的第一个字符决定了这个构建采用什么样的语法。这种扩展通常并不创建新的组合; (?P<name>...) 是唯一的例外。 以下是目前支持的扩展。

(?aiLmsux)

( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一个或多个) 这个组合匹配一个空字符串;这些字符对正则表达式设置以下标记 re.A (只匹配ASCII字符), re.I (忽略大小写), re.L (语言依赖), re.M (多行模式), re.S (点dot匹配全部字符), re.U (Unicode匹配), and re.X (冗长模式)。 如果你想将这些标记包含在正则表达式中,这个方法就很有用,免去了在 re.compile() 中传递 flag 参数。标记应该在表达式字符串首位表示。

(?:…)

正则括号的非捕获版本。 匹配在括号内的任何正则表达式,但该分组所匹配的子字符串 不能 在执行匹配后被获取或是之后在模式中被引用。

(?aiLmsux-imsx:…)

('a', 'i', 'L', 'm', 's', 'u', 'x' 中的0或者多个, 之后可选跟随 '-' 在后面跟随 'i' , 'm' , 's' , 'x' 中的一到多个 .) 这些字符为表达式的其中一部分 设置 或者 去除 相应标记 re.A (只匹配ASCII), re.I (忽略大小写), re.L (语言依赖), re.M (多行), re.S (点匹配所有字符), re.U (Unicode匹配), and re.X (冗长模式)。

'a', 'L' and 'u' 作为内联标记是相互排斥的, 所以它们不能结合在一起,或者跟随 '-' 。 当他们中的某个出现在内联组中,它就覆盖了括号组内的匹配模式。在Unicode样式中, (?a:...) 切换为 只匹配ASCII, (?u:...) 切换为Unicode匹配 (默认). 在byte样式中 (?L:...) 切换为语言依赖模式, (?a:...) 切换为 只匹配ASCII (默认)。这种方式只覆盖组合内匹配,括号外的匹配模式不受影响。

3.6 新版功能.

在 3.7 版更改: 符号 'a', 'L''u' 同样可以用在一个组合内。

(?P<name>…)

(命名组合)类似正则组合,但是匹配到的子串组在外部是通过定义的 name 来获取的。组合名必须是有效的Python标识符,并且每个组合名只能用一个正则表达式定义,只能定义一次。一个符号组合同样是一个数字组合,就像这个组合没有被命名一样。

命名组合可以在三种上下文中引用。如果样式是 (?P<quote>['"]).*?(?P=quote) (也就是说,匹配单引号或者双引号括起来的字符串):

引用组合 “quote” 的上下文 引用方法
在正则式自身内 (?P=quote) (如示) \1
处理匹配对象 m m.group(‘quote’) m.end(‘quote’) (等)
传递到 re.sub() 里的 repl 参数中 \g<quote> \g<1> \1
(?P=name)

反向引用一个命名组合;它匹配前面那个叫 name 的命名组中匹配到的串同样的字串。

(?#…)

注释;里面的内容会被忽略。

(?=…)

匹配 的内容,但是并不消费样式的内容。这个叫做 lookahead assertion。比如, Isaac (?=Asimov) 匹配 'Isaac ' 只有在后面是 'Asimov' 的时候。

(?!…)

匹配 不符合的情况。这个叫 negative lookahead assertion (前视取反)。比如说, Isaac (?!Asimov) 只有后面 'Asimov' 的时候才匹配 'Isaac '

(?<=…)

匹配字符串的当前位置,它的前面匹配 ... 的内容到当前位置。这叫 positive lookbehind assertion (正向后视断定)。 (?<=abc)def 会在 'abcdef' 中找到一个匹配,因为后视会往后看3个字符并检查是否包含匹配的样式。包含的匹配样式必须是定长的,意思就是 abca|b 是允许的,但是 a*a{3,4} 不可以。注意以 positive lookbehind assertions 开始的样式,如 (?<=abc)def ,并不是从 a 开始搜索,而是从 d 往回看的。你可能更加愿意使用 search() 函数,而不是 match() 函数:

>>> import re
>>> m = re.search('(?<=abc)def', 'abcdef')
>>> m.group(0)
'def'

这个例子搜索一个跟随在连字符后的单词:

>>> m = re.search(r'(?<=-)\w+', 'spam-egg')
>>> m.group(0)
'egg'

在 3.5 版更改: 添加定长组合引用的支持。

(?<!…)

匹配当前位置之前不是 ... 的样式。这个叫 negative lookbehind assertion (后视断定取非)。类似正向后视断定,包含的样式匹配必须是定长的。由 negative lookbehind assertion 开始的样式可以从字符串搜索开始的位置进行匹配。

(?(id/name)yes-pattern|no-pattern)

如果给定的 idname 存在,将会尝试匹配 yes-pattern ,否则就尝试匹配 no-patternno-pattern 可选,也可以被忽略。比如, (<)?(\w+@\w+(?:\.\w+)+)(?(1)>|$) 是一个email样式匹配,将匹配 '<user@host.com>''user@host.com' ,但不会匹配 '<user@host.com' ,也不会匹配 'user@host.com>'

'\' 和一个字符组成的特殊序列在以下列出。 如果普通字符不是ASCII数位或者ASCII字母,那么正则样式将匹配第二个字符。比如,\$ 匹配字符 '$'.

\number

匹配数字代表的组合。每个括号是一个组合,组合从1开始编号。比如 (.+) \1 匹配 'the the' 或者 '55 55', 但不会匹配 'thethe' (注意组合后面的空格)。这个特殊序列只能用于匹配前面99个组合。如果 number 的第一个数位是0, 或者 number 是三个八进制数,它将不会被看作是一个组合,而是八进制的数字值。在 '['']' 字符集合内,任何数字转义都被看作是字符。

\A

只匹配字符串开始。

\b

匹配空字符串,但只在单词开始或结尾的位置。一个单词被定义为一个单词字符的序列。注意,通常 \b 定义为 \w\W 字符之间,或者 \w 和字符串开始/结尾的边界, 意思就是 r'\bfoo\b' 匹配 'foo', 'foo.', '(foo)', 'bar foo baz' 但不匹配 'foobar' 或者 'foo3'

默认情况下,Unicode字母和数字是在Unicode样式中使用的,但是可以用 ASCII 标记来更改。如果 LOCALE 标记被设置的话,词的边界是由当前语言区域设置决定的,\b 表示退格字符,以便与Python字符串文本兼容。

\B

匹配空字符串,但 能在词的开头或者结尾。意思就是 r'py\B' 匹配 'python', 'py3', 'py2', 但不匹配 'py', 'py.', 或者 'py!'. \B\b 的取非,所以Unicode样式的词语是由Unicode字母,数字或下划线构成的,虽然可以用 ASCII 标志来改变。如果使用了 LOCALE 标志,则词的边界由当前语言区域设置。

\d
  • 对于 Unicode (str) 样式:

    匹配任何Unicode十进制数(就是在Unicode字符目录[Nd]里的字符)。这包括了 [0-9] ,和很多其他的数字字符。如果设置了 ASCII 标志,就只匹配 [0-9]

    对于8位(bytes)样式:

    匹配任何十进制数,就是 [0-9]

\D

匹配任何非十进制数字的字符。就是 \d 取非。 如果设置了 ASCII 标志,就相当于 [^0-9]

\s
  • 对于 Unicode (str) 样式:

    匹配任何Unicode空白字符(包括 [ \t\n\r\f\v] ,还有很多其他字符,比如不同语言排版规则约定的不换行空格)。如果 ASCII 被设置,就只匹配 [ \t\n\r\f\v]

    对于8位(bytes)样式:

    匹配ASCII中的空白字符,就是 [ \t\n\r\f\v]

\S

匹配任何非空白字符。就是 \s 取非。如果设置了 ASCII 标志,就相当于 [^ \t\n\r\f\v]

\w
  • 对于 Unicode (str) 样式:

    匹配Unicode词语的字符,包含了可以构成词语的绝大部分字符,也包括数字和下划线。如果设置了 ASCII 标志,就只匹配 [a-zA-Z0-9_]

    对于8位(bytes)样式:

    匹配ASCII字符中的数字和字母和下划线,就是 [a-zA-Z0-9_] 。如果设置了 LOCALE 标记,就匹配当前语言区域的数字和字母和下划线。

\W

匹配非单词字符的字符。这与 \w 正相反。如果使用了 ASCII 旗标,这就等价于 [^a-zA-Z0-9_]。如果使用了 LOCALE 旗标,则会匹配当前区域中既非字母数字也非下划线的字符。

\Z

只匹配字符串尾。

绝大部分Python的标准转义字符也被正则表达式分析器支持。:

\a      \b      \f      \n\N      \r      \t      \u\U      \v      \x      \\

(注意 \b 被用于表示词语的边界,它只在字符集合内表示退格,比如 [\b] 。)

'\u', '\U''\N' 转义序列只在 Unicode 模式中可被识别。 在 bytes 模式中它们会导致错误。 未知的 ASCII 字母转义序列保留在未来使用,会被当作错误来处理。

八进制转义包含为一个有限形式。如果首位数字是 0, 或者有三个八进制数位,那么就认为它是八进制转义。其他的情况,就看作是组引用。对于字符串文本,八进制转义最多有三个数位长。

在 3.3 版更改: 增加了 '\u''\U' 转义序列。

在 3.6 版更改: 由 '\' 和一个ASCII字符组成的未知转义会被看成错误。

在 3.8 版更改: 添加了 '\N{name}' 转义序列。 与在字符串字面值中一样,它扩展了命名 Unicode 字符 (例如 '\N{EM DASH}')。

模块内容

模块定义了几个函数、常量,和一个异常。有些函数是编译后的正则表达式方法的简化版本(少了一些特性)。重要的应用程序大多会在使用前先编译正则表达式。

在 3.6 版更改: 标志常量现在是 RegexFlag 类的实例,这个类是 enum.IntFlag 的子类。

re.compile(pattern, flags=0)

将正则表达式的样式编译为一个 正则表达式对象 (正则对象),可以用于匹配,通过这个对象的方法 match(), search() 以及其他如下描述。

这个表达式的行为可以通过指定 标记 的值来改变。值可以是以下任意变量,可以通过位的OR操作来结合( | 操作符)。

序列

prog = re.compile(pattern)
result = prog.match(string)

等价于

result = re.match(pattern, string)

如果需要多次使用这个正则表达式的话,使用 re.compile() 和保存这个正则对象以便复用,可以让程序更加高效。

注解

通过 re.compile() 编译后的样式,和模块级的函数会被缓存, 所以少数的正则表达式使用无需考虑编译的问题。

re.A
re.ASCII

\w, \W, \b, \B, \d, \D, \s\S 只匹配ASCII,而不是Unicode。这只对Unicode样式有效,会被byte样式忽略。相当于前面语法中的内联标志 (?a)

注意,为了保持向后兼容, re.U 标记依然存在(还有他的同义 re.UNICODE 和嵌入形式 (?u) ) , 但是这些在 Python 3 是冗余的,因为默认字符串已经是Unicode了(并且Unicode匹配不允许byte出现)。

re.DEBUG

显示编译时的debug信息,没有内联标记。

re.I
re.IGNORECASE

进行忽略大小写匹配;表达式如 [A-Z] 也会匹配小写字符。Unicode匹配(比如 Ü 匹配 ü)同样有用,除非设置了 re.ASCII 标记来禁用非ASCII匹配。当前语言区域不会改变这个标记,除非设置了 re.LOCALE 标记。这个相当于内联标记 (?i)

注意,当设置了 IGNORECASE 标记,搜索Unicode样式 [a-z][A-Z] 的结合时,它将会匹配52个ASCII字符和4个额外的非ASCII字符: ‘İ’ (U+0130, 拉丁大写的 I 带个点在上面), ‘ı’ (U+0131, 拉丁小写没有点的 I ), ‘ſ’ (U+017F, 拉丁小写长 s) and ‘K’ (U+212A, 开尔文符号).如果使用 ASCII 标记,就只匹配 ‘a’ 到 ‘z’ 和 ‘A’ 到 ‘Z’ 。

re.L
re.LOCALE

由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配。这个标记只能对byte样式有效。这个标记不推荐使用,因为语言区域机制很不可靠,它一次只能处理一个 “习惯”,而且只对8位字节有效。Unicode匹配在Python 3 里默认启用,并可以处理不同语言。 这个对应内联标记 (?L)

在 3.6 版更改: re.LOCALE 只能用于byte样式,而且不能和 re.ASCII 一起用。

在 3.7 版更改: 设置了 re.LOCALE 标记的编译正则对象不再在编译时依赖语言区域设置。语言区域设置只在匹配的时候影响其结果。

re.M
re.MULTILINE

设置以后,样式字符 '^' 匹配字符串的开始,和每一行的开始(换行符后面紧跟的符号);样式字符 '$' 匹配字符串尾,和每一行的结尾(换行符前面那个符号)。默认情况下,’^’ 匹配字符串头,'$' 匹配字符串尾。对应内联标记 (?m)

re.S
re.DOTALL

'.' 特殊字符匹配任何字符,包括换行符;如果没有这个标记,'.' 就匹配 除了 换行符的其他任意字符。对应内联标记 (?s)

re.X
re.VERBOSE

这个标记允许你编写更具可读性更友好的正则表达式。通过分段和添加注释。空白符号会被忽略,除非在一个字符集合当中或者由反斜杠转义,或者在 *?, (?: or (?P<…> 分组之内。当一个行内有 # 不在字符集和转义序列,那么它之后的所有字符都是注释。

意思就是下面两个正则表达式等价地匹配一个十进制数字:

a = re.compile(r"""\d +  # the integral part
                   \.    # the decimal point
                   \d *  # some fractional digits""", re.X)
b = re.compile(r"\d+\.\d*")

对应内联标记 (?x)

re.search(pattern, string, flags=0)

扫描整个 字符串 找到匹配样式的第一个位置,并返回一个相应的 匹配对象。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。

re.match(pattern, string, flags=0)

如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的 匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。

注意即便是 MULTILINE 多行模式, re.match() 也只匹配字符串的开始位置,而不匹配每行开始。

如果你想定位 string 的任何位置,使用 search() 来替代

re.fullmatch(pattern, string, flags=0)

如果整个 string 匹配到正则表达式样式,就返回一个相应的 匹配对象 。 否则就返回一个 None ;注意这跟零长度匹配是不同的。

3.4 新版功能.

re.split(pattern, string, maxsplit=0, flags=0)

pattern 分开 string 。 如果在 pattern 中捕获到括号,那么所有的组里的文字也会包含在列表里。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。

>>> re.split(r'\W+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split(r'(\W+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split(r'\W+', 'Words, words, words.', 1)
['Words', 'words, words.']
>>> re.split('[a-f]+', '0a3B9', flags=re.IGNORECASE)
['0', '3', '9']

如果分隔符里有捕获组合,并且匹配到字符串的开始,那么结果将会以一个空字符串开始。对于结尾也是一样

>>> re.split(r'(\W+)', '...words, words...')
['', '...', 'words', ', ', 'words', '...', '']

这样的话,分隔组将会出现在结果列表中同样的位置。

样式的空匹配仅在与前一个空匹配不相邻时才会拆分字符串。

>>> re.split(r'\b', 'Words, words, words.')
['', 'Words', ', ', 'words', ', ', 'words', '.']
>>> re.split(r'\W*', '...words...')
['', '', 'w', 'o', 'r', 'd', 's', '', '']
>>> re.split(r'(\W*)', '...words...')
['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', '']

在 3.1 版更改: 增加了可选标记参数。

在 3.7 版更改: 增加了空字符串的样式分隔。

re.findall(pattern, string, flags=0)

Return all non-overlapping matches of pattern in string, as a list of strings or tuples. The string is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result.

The result depends on the number of capturing groups in the pattern. If there are no groups, return a list of strings matching the whole pattern. If there is exactly one group, return a list of strings matching that group. If multiple groups are present, return a list of tuples of strings matching the groups. Non-capturing groups do not affect the form of the result.

>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
[('width', '20'), ('height', '10')]

在 3.7 版更改: 非空匹配现在可以在前一个空匹配之后出现了。

re.finditer(pattern, string, flags=0)

patternstring 里所有的非重复匹配,返回为一个迭代器 iterator 保存了 匹配对象 。 string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。

在 3.7 版更改: 非空匹配现在可以在前一个空匹配之后出现了。

re.sub(pattern, repl, string, count=0, flags=0)

返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。 如果样式没有找到,则不加改变地返回 string*。 *repl 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。 也就是说,\n 会被转换为一个换行符,\r 会被转换为一个回车符,依此类推。 未知的 ASCII 字符转义序列保留在未来使用,会被当作错误来处理。 其他未知转义序列例如 \& 会保持原样。 向后引用像是 \6 会用样式中第 6 组所匹配到的子字符串来替换。 例如:

>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):',
...        r'static PyObject*\npy_\1(void)\n{',
...        'def myfunc():')
'static PyObject*\npy_myfunc(void)\n{'

如果 repl 是一个函数,那它会对每个非重复的 pattern 的情况调用。这个函数只能有一个 匹配对象 参数,并返回一个替换后的字符串。比如

>>> def dashrepl(matchobj):
...     if matchobj.group(0) == '-': return ' '
...     else: return '-'
>>> re.sub('-{1,2}', dashrepl, 'pro----gram-files')
'pro--gram files'
>>> re.sub(r'\sAND\s', ' & ', 'Baked Beans And Spam', flags=re.IGNORECASE)
'Baked Beans & Spam'

样式可以是一个字符串或者一个 样式对象 。

可选参数 count 是要替换的最大次数;count 必须是非负整数。如果省略这个参数或设为 0,所有的匹配都会被替换。 样式的空匹配仅在与前一个空匹配不相邻时才会被替换,所以 sub('x*', '-', 'abxd') 返回 '-a-b--d-'

在字符串类型的 repl 参数里,如上所述的转义和向后引用中,\g<name> 会使用命名组合 name,(在 (?P<name>…) 语法中定义) \g<number> 会使用数字组;\g<2> 就是 \2,但它避免了二义性,如 \g<2>0\20 就会被解释为组20,而不是组2后面跟随一个字符 '0'。向后引用 \g<0>pattern 作为一整个组进行引用。

在 3.1 版更改: 增加了可选标记参数。

在 3.5 版更改: 不匹配的组合替换为空字符串。

在 3.6 版更改: pattern 中的未知转义(由 '\' 和一个 ASCII 字符组成)被视为错误。

在 3.7 版更改: repl 中的未知转义(由 '\' 和一个 ASCII 字符组成)被视为错误。

在 3.7 版更改: 样式中的空匹配相邻接时会被替换。

re.subn(pattern, repl, string, count=0, flags=0)

行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数).

在 3.1 版更改: 增加了可选标记参数。

在 3.5 版更改: 不匹配的组合替换为空字符串。

re.escape(pattern)

转义 pattern 中的特殊字符。如果你想对任意可能包含正则表达式元字符的文本字符串进行匹配,它就是有用的。比如

>>> print(re.escape('https://www.python.org'))
https://www\.python\.org
>>> legal_chars = string.ascii_lowercase + string.digits + "!#$%&'*+-.^_`|~:"
>>> print('[%s]+' % re.escape(legal_chars))
[abcdefghijklmnopqrstuvwxyz0123456789!\#\$%\&'\*\+\-\.\^_`\|\~:]+
>>> operators = ['+', '-', '*', '/', '**']
>>> print('|'.join(map(re.escape, sorted(operators, reverse=True))))
/|\-|\+|\*\*|\*

这个函数不能被用于 sub()subn() 的替换字符串,只有反斜杠应该被转义。 例如:

>>> digits_re = r'\d+'
>>> sample = '/usr/sbin/sendmail - 0 errors, 12 warnings'
>>> print(re.sub(digits_re, digits_re.replace('\\', r'\\'), sample))
/usr/sbin/sendmail - \d+ errors, \d+ warnings

在 3.3 版更改: '_' 不再被转义。

在 3.7 版更改: 只有在正则表达式中具有特殊含义的字符才会被转义。 因此, '!', '"', '%', "'", ',', '/', ':', ';', '<', '=', '>', '@'"“` 将不再会被转义。

re.purge()

清除正则表达式的缓存。

exception re.error(msg, pattern=None, pos=None)

当传递给函数的正则表达式不合法(比如括号不匹配),或者在编译或匹配过程中出现其他错误时,会引发异常。所给字符串不匹配所给模式不会引发异常。异常实例有以下附加属性:

  • msg

    未格式化的错误消息。

  • pattern

    正则表达式的模式串。

  • pos

    编译失败的 pattern 的位置索引(可以是 None )。

  • lineno

    对应 pos (可以是 None) 的行号。

  • colno

    对应 pos (可以是 None) 的列号。

在 3.5 版更改: 增加了额外的属性。

正则表达式对象 (正则对象)

编译后的正则表达式对象支持以下方法和属性:

Pattern.search(string[, pos[, endpos]])

扫描整个 string 寻找第一个匹配的位置, 并返回一个相应的 匹配对象。如果没有匹配,就返回 None ;注意它和零长度匹配是不同的。

可选的第二个参数 pos 给出了字符串中开始搜索的位置索引;默认为 0,它不完全等价于字符串切片; '^' 样式字符匹配字符串真正的开头,和换行符后面的第一个字符,但不会匹配索引规定开始的位置。

可选参数 endpos 限定了字符串搜索的结束;它假定字符串长度到 endpos , 所以只有从 posendpos - 1 的字符会被匹配。如果 endpos 小于 pos*,就不会有匹配产生;另外,如果 *rx 是一个编译后的正则对象, rx.search(string, 0, 50) 等价于 rx.search(string[:50], 0)

>>> pattern = re.compile("d")
>>> pattern.search("dog")     # Match at index 0
<re.Match object; span=(0, 1), match='d'>
>>> pattern.search("dog", 1)  # No match; search doesn't include the "d"

Pattern.match(string[, pos[, endpos]])

如果 string开始位置 能够找到这个正则样式的任意个匹配,就返回一个相应的 匹配对象。如果不匹配,就返回 None ;注意它与零长度匹配是不同的。

可选参数 posendpossearch() 含义相同。

>>> pattern = re.compile("o")
>>> pattern.match("dog")      # No match as "o" is not at the start of "dog".
>>> pattern.match("dog", 1)   # Match as "o" is the 2nd character of "dog".
<re.Match object; span=(1, 2), match='o'>

如果你想定位匹配在 string 中的位置,使用 search() 来替代。

Pattern.fullmatch(string[, pos[, endpos]])

如果整个 string 匹配这个正则表达式,就返回一个相应的 匹配对象 。 否则就返回 None ; 注意跟零长度匹配是不同的。

可选参数 posendpossearch() 含义相同。

>>> pattern = re.compile("o[gh]")
>>> pattern.fullmatch("dog")      # No match as "o" is not at the start of "dog".
>>> pattern.fullmatch("ogre")     # No match as not the full string matches.
>>> pattern.fullmatch("doggie", 1, 3)   # Matches within given limits.
<re.Match object; span=(1, 3), match='og'>

3.4 新版功能.

Pattern.split(string, maxsplit=0)

等价于 split() 函数,使用了编译后的样式。

Pattern.findall(string[, pos[, endpos]])

类似函数 findall() , 使用了编译后样式,但也可以接收可选参数 posendpos ,限制搜索范围,就像 search()

Pattern.finditer(string[, pos[, endpos]])

类似函数 finditer() , 使用了编译后样式,但也可以接收可选参数 posendpos ,限制搜索范围,就像 search()

Pattern.sub(repl, string, count=0)

等价于 sub() 函数,使用了编译后的样式。

Pattern.subn(repl, string, count=0)

等价于 subn() 函数,使用了编译后的样式。

Pattern.flags

正则匹配标记。这是可以传递给 compile() 的参数,任何 (?…) 内联标记,隐性标记比如 UNICODE 的结合。

Pattern.groups

捕获到的模式串中组的数量。

Pattern.groupindex

映射由 (?P<id>) 定义的命名符号组合和数字组合的字典。如果没有符号组,那字典就是空的。

Pattern.pattern

编译对象的原始样式字符串。

在 3.7 版更改: 添加 copy.copy()copy.deepcopy() 函数的支持。编译后的正则表达式对象被认为是原子性的。

匹配对象

匹配对象总是有一个布尔值 True。如果没有匹配的话 match()search() 返回 None 所以你可以简单的用 if 语句来判断是否匹配

match = re.search(pattern, string)
if match:
    process(match)

匹配对象支持以下方法和属性:

Match.expand(template)

template 进行反斜杠转义替换并且返回,就像 sub() 方法中一样。转义如同 \n 被转换成合适的字符,数字引用(\1, \2)和命名组合(\g<1>, \g<name>) 替换为相应组合的内容。

在 3.5 版更改: 不匹配的组合替换为空字符串。

Match.group([group1, ])

返回一个或者多个匹配的子组。如果只有一个参数,结果就是一个字符串,如果有多个参数,结果就是一个元组(每个参数对应一个项),如果没有参数,组1默认到0(整个匹配都被返回)。 如果一个组N 参数值为 0,相应的返回值就是整个匹配字符串;如果它是一个范围 [1..99],结果就是相应的括号组字符串。如果一个组号是负数,或者大于样式中定义的组数,就引发一个 IndexError 异常。如果一个组包含在样式的一部分,并被匹配多次,就返回最后一个匹配。:

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0)       # The entire match
'Isaac Newton'
>>> m.group(1)       # The first parenthesized subgroup.
'Isaac'
>>> m.group(2)       # The second parenthesized subgroup.
'Newton'
>>> m.group(1, 2)    # Multiple arguments give us a tuple.
('Isaac', 'Newton')

如果正则表达式使用了 (?P<name>...) 语法, groupN 参数就也可能是命名组合的名字。如果一个字符串参数在样式中未定义为组合名,就引发一个 IndexError 异常。

一个相对复杂的例子

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.group('first_name')
'Malcolm'
>>> m.group('last_name')
'Reynolds'

命名组合同样可以通过索引值引用

>>> m.group(1)
'Malcolm'
>>> m.group(2)
'Reynolds'

如果一个组匹配成功多次,就只返回最后一个匹配

>>> m = re.match(r"(..)+", "a1b2c3")  # Matches 3 times.
>>> m.group(1)                        # Returns only the last match.
'c3'

Match.__getitem__(g)

这个等价于 m.group(g)。这允许更方便的引用一个匹配

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m[0]       # The entire match
'Isaac Newton'
>>> m[1]       # The first parenthesized subgroup.
'Isaac'
>>> m[2]       # The second parenthesized subgroup.
'Newton'

3.6 新版功能.

Match.groups(default=None)

返回一个元组,包含所有匹配的子组,在样式中出现的从1到任意多的组合。 default 参数用于不参与匹配的情况,默认为 None

例如:

>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups()
('24', '1632')

如果我们使小数点可选,那么不是所有的组都会参与到匹配当中。这些组合默认会返回一个 None ,除非指定了 default 参数。

>>> m = re.match(r"(\d+)\.?(\d+)?", "24")
>>> m.groups()      # Second group defaults to None.
('24', None)
>>> m.groups('0')   # Now, the second group defaults to '0'.
('24', '0')

Match.groupdict(default=None)

返回一个字典,包含了所有的 命名 子组。key就是组名。 default 参数用于不参与匹配的组合;默认为 None。 例如

>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.groupdict()
{'first_name': 'Malcolm', 'last_name': 'Reynolds'}

Match.start([group])

Match.end([group])

返回 group 匹配到的字串的开始和结束标号。group 默认为0(意思是整个匹配的子串)。如果 group 存在,但未产生匹配,就返回 -1 。对于一个匹配对象 m, 和一个未参与匹配的组 g ,组 g (等价于 m.group(g))产生的匹配是

m.string[m.start(g):m.end(g)]

注意 m.start(group) 将会等于 m.end(group) ,如果 group 匹配一个空字符串的话。比如,在 m = re.search('b(c?)', 'cba') 之后,m.start(0) 为 1, m.end(0) 为 2, m.start(1)m.end(1) 都是 2, m.start(2) 引发一个 IndexError 异常。

这个例子会从email地址中移除掉 remove_this

>>> email = "tony@tiremove_thisger.net"
>>> m = re.search("remove_this", email)
>>> email[:m.start()] + email[m.end():]
'tony@tiger.net'

Match.span([group])

对于一个匹配 m , 返回一个二元组 (m.start(group), m.end(group)) 。 注意如果 group 没有在这个匹配中,就返回 (-1, -1)group 默认为0,就是整个匹配。

Match.pos

pos 的值,会传递给 search()match() 的方法 a 正则对象 。这个是正则引擎开始在字符串搜索一个匹配的索引位置。

Match.endpos

endpos 的值,会传递给 search()match() 的方法 a 正则对象 。这个是正则引擎停止在字符串搜索一个匹配的索引位置。

Match.lastindex

捕获组的最后一个匹配的整数索引值,或者 None 如果没有匹配产生的话。比如,对于字符串 'ab',表达式 (a)b, ((a)(b)), 和 ((ab)) 将得到 lastindex == 1 , 而 (a)(b) 会得到 lastindex == 2

Match.lastgroup

最后一个匹配的命名组名字,或者 None 如果没有产生匹配的话。

Match.re

返回产生这个实例的 正则对象 , 这个实例是由 正则对象的 match()search() 方法产生的。

Match.string

传递到 match()search() 的字符串。

在 3.7 版更改: 添加了对 copy.copy()copy.deepcopy() 的支持。匹配对象被看作是原子性的。

正则表达式例子

检查对子

在这个例子里,我们使用以下辅助函数来更好地显示匹配对象:

def displaymatch(match):
    if match is None:
        return None
    return '<Match: %r, groups=%r>' % (match.group(), match.groups())

假设你在写一个扑克程序,一个玩家的一手牌为五个字符的串,每个字符表示一张牌,”a” 就是 A, “k” K, “q” Q, “j” J, “t” 为 10, “2” 到 “9” 表示2 到 9。

要看给定的字符串是否有效,我们可以按照以下步骤

>>> valid = re.compile(r"^[a2-9tjqk]{5}$")
>>> displaymatch(valid.match("akt5q"))  # Valid.
"<Match: 'akt5q', groups=()>"
>>> displaymatch(valid.match("akt5e"))  # Invalid.
>>> displaymatch(valid.match("akt"))    # Invalid.
>>> displaymatch(valid.match("727ak"))  # Valid.
"<Match: '727ak', groups=()>"

最后一手牌,"727ak" ,包含了一个对子,或者两张同样数值的牌。要用正则表达式匹配它,应该使用向后引用如下

>>> pair = re.compile(r".*(.).*\1")
>>> displaymatch(pair.match("717ak"))     # Pair of 7s.
"<Match: '717', groups=('7',)>"
>>> displaymatch(pair.match("718ak"))     # No pairs.
>>> displaymatch(pair.match("354aa"))     # Pair of aces.
"<Match: '354aa', groups=('a',)>"

要找出对子由什么牌组成,开发者可以按照下面的方式来使用匹配对象的 group() 方法:

>>> pair = re.compile(r".*(.).*\1")
>>> pair.match("717ak").group(1)
'7'
# Error because re.match() returns None, which doesn't have a group() method:
>>> pair.match("718ak").group(1)
Traceback (most recent call last):
  File "<pyshell#23>", line 1, in <module>
    re.match(r".*(.).*\1", "718ak").group(1)
AttributeError: 'NoneType' object has no attribute 'group'
>>> pair.match("354aa").group(1)
'a'

模拟 scanf()

Python 目前没有一个类似c函数 scanf() 的替代品。正则表达式通常比 scanf() 格式字符串要更强大一些,但也带来更多复杂性。下面的表格提供了 scanf() 格式符和正则表达式大致相同的映射。

scanf() 格式符 正则表达式
%c .
%5c .{5}
%d [-+]?\d+
%e, %E, %f, %g `[-+]?(\d+(.\d*)?
%i `[-+]?(0[xX][\dA-Fa-f]+
%o [-+]?[0-7]+
%s \S+
%u \d+
%x, %X [-+]?(0[xX])?[\dA-Fa-f]+

从文件名和数字提取字符串

/usr/sbin/sendmail - 0 errors, 4 warnings

你可以使用 scanf() 格式化

%s - %d errors, %d warnings

等价的正则表达式是:

(\S+) - (\d+) errors, (\d+) warnings

search() vs. match()

Python 提供了两种不同的操作:基于 re.match() 检查字符串开头,或者 re.search() 检查字符串的任意位置(默认Perl中的行为)。

例如:

>>> re.match("c", "abcdef")    # No match
>>> re.search("c", "abcdef")   # Match
<re.Match object; span=(2, 3), match='c'>

search() 中,可以用 '^' 作为开始来限制匹配到字符串的首位

>>> re.match("c", "abcdef")    # No match
>>> re.search("^c", "abcdef")  # No match
>>> re.search("^a", "abcdef")  # Match
<re.Match object; span=(0, 1), match='a'>

注意 MULTILINE 多行模式中函数 match() 只匹配字符串的开始,但使用 search() 和以 '^' 开始的正则表达式会匹配每行的开始

>>> re.match('X', 'A\nB\nX', re.MULTILINE)  # No match
>>> re.search('^X', 'A\nB\nX', re.MULTILINE)  # Match
<re.Match object; span=(4, 5), match='X'>

制作一个电话本

split() 将字符串用参数传递的样式分隔开。这个方法对于转换文本数据到易读而且容易修改的数据结构,是很有用的,如下面的例子证明。

首先,这里是输入。 它通常来自一个文件,这里我们使用三重引号字符串语法

>>> text = """Ross McFluff: 834.345.1254 155 Elm Street
...
... Ronald Heathmore: 892.345.3428 436 Finley Avenue
... Frank Burger: 925.541.7625 662 South Dogwood Way
...
...
... Heather Albrecht: 548.326.4584 919 Park Place"""

条目用一个或者多个换行符分开。现在我们将字符串转换为一个列表,每个非空行都有一个条目:

>>> entries = re.split("\n+", text)
>>> entries
['Ross McFluff: 834.345.1254 155 Elm Street',
'Ronald Heathmore: 892.345.3428 436 Finley Avenue',
'Frank Burger: 925.541.7625 662 South Dogwood Way',
'Heather Albrecht: 548.326.4584 919 Park Place']

最终,将每个条目分割为一个由名字、姓氏、电话号码和地址组成的列表。我们为 split() 使用了 maxsplit 形参,因为地址中包含有被我们作为分割模式的空格符:

>>> [re.split(":? ", entry, 3) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155 Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436 Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662 South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919 Park Place']]

:? 样式匹配姓后面的冒号,因此它不出现在结果列表中。如果 maxsplit 设置为 4 ,我们还可以从地址中获取到房间号:

>>> [re.split(":? ", entry, 4) for entry in entries]
[['Ross', 'McFluff', '834.345.1254', '155', 'Elm Street'],
['Ronald', 'Heathmore', '892.345.3428', '436', 'Finley Avenue'],
['Frank', 'Burger', '925.541.7625', '662', 'South Dogwood Way'],
['Heather', 'Albrecht', '548.326.4584', '919', 'Park Place']]

文字整理

sub() 替换字符串中出现的样式的每一个实例。这个例子证明了使用 sub() 来整理文字,或者随机化每个字符的位置,除了首位和末尾字符

>>> def repl(m):
...     inner_word = list(m.group(2))
...     random.shuffle(inner_word)
...     return m.group(1) + "".join(inner_word) + m.group(3)
>>> text = "Professor Abdolmalek, please report your absences promptly."
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Poefsrosr Aealmlobdk, pslaee reorpt your abnseces plmrptoy.'
>>> re.sub(r"(\w)(\w+)(\w)", repl, text)
'Pofsroser Aodlambelk, plasee reoprt yuor asnebces potlmrpy.'

查找所有副词

findall() 匹配样式 所有 的出现,不仅是像 search() 中的第一个匹配。比如,如果一个作者希望找到文字中的所有副词,他可能会按照以下方法用 findall()

>>> text = "He was carefully disguised but captured quickly by police."
>>> re.findall(r"\w+ly", text)
['carefully', 'quickly']

查找所有的副词及其位置

如果需要匹配样式的更多信息, finditer() 可以起到作用,它提供了 匹配对象 作为返回值,而不是字符串。继续上面的例子,如果一个作者希望找到所有副词和它的位置,可以按照下面方法使用 finditer()

>>> text = "He was carefully disguised but captured quickly by police."
>>> for m in re.finditer(r"\w+ly", text):
...     print('%02d-%02d: %s' % (m.start(), m.end(), m.group(0)))
07-16: carefully
40-47: quickly

原始字符串标记

原始字符串记法 (r"text") 保持正则表达式正常。否则,每个正则式里的反斜杠('\') 都必须前缀一个反斜杠来转义。比如,下面两行代码功能就是完全一致的

>>> re.match(r"\W(.)\1\W", " ff ")
<re.Match object; span=(0, 4), match=' ff '>
>>> re.match("\\W(.)\\1\\W", " ff ")
<re.Match object; span=(0, 4), match=' ff '>

当需要匹配一个字符反斜杠,它必须在正则表达式中转义。在原始字符串记法,就是 r"\\"。否则就必须用 "\\\\",来表示同样的意思

>>> re.match(r"\\", r"\\")
<re.Match object; span=(0, 1), match='\\'>
>>> re.match("\\\\", r"\\")
<re.Match object; span=(0, 1), match='\\'>

写一个词法分析器

一个 词法器或词法分析器 分析字符串,并分类成目录组。 这是写一个编译器或解释器的第一步。

文字目录是由正则表达式指定的。这个技术是通过将这些样式合并为一个主正则式,并且循环匹配来实现的

from typing import NamedTuple
import re
class Token(NamedTuple):
    type: str
    value: str
    line: int
    column: int
def tokenize(code):
    keywords = {'IF', 'THEN', 'ENDIF', 'FOR', 'NEXT', 'GOSUB', 'RETURN'}
    token_specification = [
        ('NUMBER',   r'\d+(\.\d*)?'),  # Integer or decimal number
        ('ASSIGN',   r':='),           # Assignment operator
        ('END',      r';'),            # Statement terminator
        ('ID',       r'[A-Za-z]+'),    # Identifiers
        ('OP',       r'[+\-*/]'),      # Arithmetic operators
        ('NEWLINE',  r'\n'),           # Line endings
        ('SKIP',     r'[ \t]+'),       # Skip over spaces and tabs
        ('MISMATCH', r'.'),            # Any other character
    ]
    tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
    line_num = 1
    line_start = 0
    for mo in re.finditer(tok_regex, code):
        kind = mo.lastgroup
        value = mo.group()
        column = mo.start() - line_start
        if kind == 'NUMBER':
            value = float(value) if '.' in value else int(value)
        elif kind == 'ID' and value in keywords:
            kind = value
        elif kind == 'NEWLINE':
            line_start = mo.end()
            line_num += 1
            continue
        elif kind == 'SKIP':
            continue
        elif kind == 'MISMATCH':
            raise RuntimeError(f'{value!r} unexpected on line {line_num}')
        yield Token(kind, value, line_num, column)
statements = '''
    IF quantity THEN
        total := total + price * quantity;
        tax := price * 0.05;
    ENDIF;
'''
for token in tokenize(statements):
    print(token)

该词法器产生以下的输出

Token(type='IF', value='IF', line=2, column=4)
Token(type='ID', value='quantity', line=2, column=7)
Token(type='THEN', value='THEN', line=2, column=16)
Token(type='ID', value='total', line=3, column=8)
Token(type='ASSIGN', value=':=', line=3, column=14)
Token(type='ID', value='total', line=3, column=17)
Token(type='OP', value='+', line=3, column=23)
Token(type='ID', value='price', line=3, column=25)
Token(type='OP', value='*', line=3, column=31)
Token(type='ID', value='quantity', line=3, column=33)
Token(type='END', value=';', line=3, column=41)
Token(type='ID', value='tax', line=4, column=8)
Token(type='ASSIGN', value=':=', line=4, column=12)
Token(type='ID', value='price', line=4, column=15)
Token(type='OP', value='*', line=4, column=21)
Token(type='NUMBER', value=0.05, line=4, column=23)
Token(type='END', value=';', line=4, column=27)
Token(type='ENDIF', value='ENDIF', line=5, column=4)
Token(type='END', value=';', line=5, column=9)

Frie09

Friedl, Jeffrey. Mastering Regular Expressions. 3rd ed., O’Reilly Media, 2009. 该书的第三版不再包含 Python,但第一版极详细地覆盖了正则表达式模式串的编写。

difflib —- 计算差异的辅助工具

源代码: Lib/difflib.py

此模块提供用于比较序列的类和函数。 例如,它可被用于比较文件,并可产生多种格式的不同文件差异信息,包括 HTML 和上下文以及统一的 diff 数据。

class difflib.SequenceMatcher

这是一个灵活的类,可用于比较任何类型的序列对,只要序列元素为 hashable 对象。 其基本算法要早于由 Ratcliff 和 Obershelp 于 1980 年代末期发表并以“格式塔模式匹配”的夸张名称命名的算法,并且更加有趣一些。 其思路是找到不包含“垃圾”元素的最长连续匹配子序列;所谓“垃圾”元素是指其在某种意义上没有价值,例如空白行或空白符。 (处理垃圾元素是对 Ratcliff 和 Obershelp 算法的一个扩展。) 然后同样的思路将递归地应用于匹配序列的左右序列片段。 这并不能产生最小编辑序列,但确实能产生在人们看来“正确”的匹配。

耗时: 基本 Ratcliff-Obershelp 算法在最坏情况下为立方时间而在一般情况下为平方时间。 SequenceMatcher 在最坏情况下为平方时间而在一般情况下的行为受到序列中有多少相同元素这一因素的微妙影响;在最佳情况下则为线性时间。

自动垃圾启发式计算: SequenceMatcher 支持使用启发式计算来自动将特定序列项视为垃圾。 这种启发式计算会统计每个单独项在序列中出现的次数。 如果某一项(在第一项之后)的重复次数超过序列长度的 1% 并且序列长度至少有 200 项,该项会被标记为“热门”并被视为序列匹配中的垃圾。 这种启发式计算可以通过在创建 SequenceMatcher 时将 autojunk 参数设为 False 来关闭。

3.2 新版功能: autojunk 形参。

class difflib.Differ

这个类的作用是比较由文本行组成的序列,并产生可供人阅读的差异或增量信息。 Differ 统一使用 SequenceMatcher 来完成行序列的比较以及相似(接近匹配)行内部字符序列的比较。

Differ 增量的每一行均以双字母代码打头:

双字母代码 含意
‘- ‘ 行为序列 1 所独有
‘+ ‘ 行为序列 2 所独有
‘ ‘ 行在两序列中相同
‘? ‘ 行不存在于任一输入序列

以 ‘?‘ 打头的行尝试将视线引至行以外而不存在于任一输入序列的差异。 如果序列包含制表符则这些行可能会令人感到迷惑。

class difflib.HtmlDiff

这个类可用于创建 HTML 表格(或包含表格的完整 HTML 文件)以并排地逐行显示文本比较,行间与行外的更改将突出显示。 此表格可以基于完全或上下文差异模式来生成。

这个类的构造函数:

  • __init__(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK)

    初始化 HtmlDiff 的实例。

    tabsize 是一个可选关键字参数,指定制表位的间隔,默认值为 8

    wrapcolumn 是一个可选关键字参数,指定行文本自动打断并换行的列位置,默认值为 None 表示不自动换行。

    linejunkcharjunk 均是可选关键字参数,会传入 ndiff() (被 HtmlDiff 用来生成并排显示的 HTML 差异)。

下列是公开的方法

  • make_file(fromlines, tolines, fromdesc=’’, todesc=’’, context=False, numlines=5, **, charset=’utf-8’*)

    比较 fromlinestolines (字符串列表) 并返回一个字符串,表示一个完整 HTML 文件,其中包含各行差异的表格,行间与行外的更改将突出显示。

    fromdesctodesc 均是可选关键字参数,指定来源/目标文件的列标题字符串(默认均为空白字符串)。

    contextnumlines 均是可选关键字参数。 当只要显示上下文差异时就将 context 设为 True,否则默认值 False 为显示完整文件。 numlines 默认为 5。 当 contextTruenumlines 将控制围绕突出显示差异部分的上下文行数。 当 contextFalsenumlines 将控制在使用 “next” 超链接时突出显示差异部分之前所显示的行数(设为零则会导致 “next” 超链接将下一个突出显示差异部分放在浏览器顶端,不添加任何前导上下文)。

    注解

    fromdesctodesc 会被当作未转义的 HTML 来解读,当接收不可信来源的输入时应该适当地进行转义。

    在 3.5 版更改: 增加了 charset 关键字参数。 HTML 文档的默认字符集从 'ISO-8859-1' 更改为 'utf-8'

  • make_table(fromlines, tolines, fromdesc=’’, todesc=’’, context=False, numlines=5)

    比较 fromlinestolines (字符串列表) 并返回一个字符串,表示一个包含各行差异的完整 HTML 表格,行间与行外的更改将突出显示。

Tools/scripts/diff.py 是这个类的命令行前端,其中包含一个很好的使用示例。

difflib.context_diff(a, b, fromfile=’’, tofile=’’, fromfiledate=’’, tofiledate=’’, n=3, lineterm=’\n’)

比较 ab (字符串列表);返回上下文差异格式的增量信息 (一个产生增量行的 generator)。

所谓上下文差异是一种只显示有更改的行再加几个上下文行的紧凑形式。 更改被显示为之前/之后的样式。 上下文行数由 n 设定,默认为三行。

默认情况下,差异控制行(以 *** or --- 表示)是通过末尾换行符来创建的。 这样做的好处是从 io.IOBase.readlines() 创建的输入将得到适用于 io.IOBase.writelines() 的差异信息,因为输入和输出都带有末尾换行符。

对于没有末尾换行符的输入,应将 lineterm 参数设为 "",这样输出内容将统一不带换行符。

上下文差异格式通常带有一个记录文件名和修改时间的标头。 这些信息的部分或全部可以使用字符串 fromfile, tofile, fromfiledatetofiledate 来指定。 修改时间通常以 ISO 8601 格式表示。 如果未指定,这些字符串默认为空。

>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']
>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']
>>> sys.stdout.writelines(context_diff(s1, s2, fromfile='before.py', tofile='after.py'))
*** before.py
--- after.py
***************
*** 1,4 ****
! bacon
! eggs
! ham
  guido
--- 1,4 ----
! python
! eggy
! hamster
  guido

difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6)

返回由最佳“近似”匹配构成的列表。 word 为一个指定目标近似匹配的序列(通常为字符串),possibilities 为一个由用于匹配 word 的序列构成的列表(通常为字符串列表)。

可选参数 n (默认为 3) 指定最多返回多少个近似匹配; n 必须大于 0.

可选参数 cutoff (默认为 0.6) 是一个 [0, 1] 范围内的浮点数。 与 word 相似度得分未达到该值的候选匹配将被忽略。

候选匹配中(不超过 n 个)的最佳匹配将以列表形式返回,按相似度得分排序,最相似的排在最前面。

>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'])
['apple', 'ape']
>>> import keyword
>>> get_close_matches('wheel', keyword.kwlist)
['while']
>>> get_close_matches('pineapple', keyword.kwlist)
[]
>>> get_close_matches('accept', keyword.kwlist)
['except']

difflib.ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK)

比较 ab (字符串列表);返回 Differ 形式的增量信息 (一个产生增量行的 generator)。

可选关键字形参 linejunkcharjunk 均为过滤函数 (或为 None):

linejunk: 此函数接受单个字符串参数,如果其为垃圾字符串则返回真值,否则返回假值。 默认为 None。 此外还有一个模块层级的函数 IS_LINE_JUNK(),它会过滤掉没有可见字符的行,除非该行添加了至多一个井号符 ('#') — 但是下层的 SequenceMatcher 类会动态分析哪些行的重复频繁到足以形成噪音,这通常会比使用此函数的效果更好。

charjunk: 此函数接受一个字符(长度为 1 的字符串),如果其为垃圾字符则返回真值,否则返回假值。 默认为模块层级的函数 IS_CHARACTER_JUNK(),它会过滤掉空白字符(空格符或制表符;但包含换行符可不是个好主意!)。

Tools/scripts/ndiff.py 是这个函数的命令行前端。

>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True),
...              'ore\ntree\nemu\n'.splitlines(keepends=True))
>>> print(''.join(diff), end="")
- one
?  ^
+ ore
?  ^
- two
- three
?  -
+ tree
+ emu

difflib.restore(sequence, which)

返回两个序列中产生增量的那一个。

给出一个由 Differ.compare()ndiff() 产生的 序列,提取出来自文件 1 或 2 (which 形参) 的行,去除行前缀。

示例:

>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True),
...              'ore\ntree\nemu\n'.splitlines(keepends=True))
>>> diff = list(diff) # materialize the generated delta into a list
>>> print(''.join(restore(diff, 1)), end="")
one
two
three
>>> print(''.join(restore(diff, 2)), end="")
ore
tree
emu

difflib.unified_diff(a, b, fromfile=’’, tofile=’’, fromfiledate=’’, tofiledate=’’, n=3, lineterm=’\n’)

比较 ab (字符串列表);返回统一差异格式的增量信息 (一个产生增量行的 generator)。

所以统一差异是一种只显示有更改的行再加几个上下文行的紧凑形式。 更改被显示为内联的样式(而不是分开的之前/之后文本块)。 上下文行数由 n 设定,默认为三行。

默认情况下,差异控制行 (以 ---, +++@@ 表示) 是通过末尾换行符来创建的。 这样做的好处是从 io.IOBase.readlines() 创建的输入将得到适用于 io.IOBase.writelines() 的差异信息,因为输入和输出都带有末尾换行符。

对于没有末尾换行符的输入,应将 lineterm 参数设为 "",这样输出内容将统一不带换行符。

上下文差异格式通常带有一个记录文件名和修改时间的标头。 这些信息的部分或全部可以使用字符串 fromfile, tofile, fromfiledatetofiledate 来指定。 修改时间通常以 ISO 8601 格式表示。 如果未指定,这些字符串默认为空。

>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']
>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']
>>> sys.stdout.writelines(unified_diff(s1, s2, fromfile='before.py', tofile='after.py'))
--- before.py
+++ after.py
@@ -1,4 +1,4 @@
-bacon
-eggs
-ham
+python
+eggy
+hamster
 guido

difflib.diff_bytes(dfunc, a, b, fromfile=b’’, tofile=b’’, fromfiledate=b’’, tofiledate=b’’, n=3, lineterm=b’\n’)

使用 dfunc 比较 ab (字节串对象列表);产生以 dfunc 所返回格式表示的差异行列表(也是字节串)。 dfunc 必须是可调用对象,通常为 unified_diff()context_diff()

允许你比较编码未知或不一致的数据。 除 n 之外的所有输入都必须为字节串对象而非字符串。 作用方式为无损地将所有输入 (除 n 之外) 转换为字符串,并调用 dfunc(a, b, fromfile, tofile, fromfiledate, tofiledate, n, lineterm)dfunc 的输出会被随即转换回字节串,这样你所得到的增量行将具有与 ab 相同的未知/不一致编码。

3.5 新版功能.

difflib.IS_LINE_JUNK(line)

对于可忽略的行返回 True。 如果 line 为空行或只包含单个 '#'line 行就是可忽略的,否则就是不可忽略的。 此函数被用作较旧版本 ndiff()linejunk 形参的默认值。

difflib.IS_CHARACTER_JUNK(ch)

对于可忽略的字符返回 True。 字符 ch 如果为空格符或制表符则 ch 就是可忽略的,否则就是不可忽略的。 此函数被用作 ndiff()charjunk 形参的默认值。

SequenceMatcher 对象

SequenceMatcher 类具有这样的构造器:

class difflib.SequenceMatcher(isjunk=None, a=’’, b=’’, autojunk=True)

可选参数 isjunk 必须为 None (默认值) 或为接受一个序列元素并当且仅当其为应忽略的“垃圾”元素时返回真值的单参数函数。 传入 None 作为 isjunk 的值就相当于传入 lambda x: False;也就是说不忽略任何值。 例如,传入:

lambda x: x in " \t"

如果你以字符序列的形式对行进行比较,并且不希望区分空格符或硬制表符。

可选参数 ab 为要比较的序列;两者默认为空字符串。 两个序列的元素都必须为 hashable。

可选参数 autojunk 可用于启用自动垃圾启发式计算。

3.2 新版功能: autojunk 形参。

SequenceMatcher 对象接受三个数据属性: bjunkb 当中 isjunkTrue 的元素集合;bpopular 是被启发式计算(如果其未被禁用)视为热门候选的非垃圾元素集合;b2j 是将 b 当中剩余元素映射到一个它们出现位置列表的字典。 所有三个数据属性将在 b 通过 set_seqs()set_seq2() 重置时被重置。

3.2 新版功能: bjunkbpopular 属性。

SequenceMatcher 对象具有以下方法:

  • set_seqs(a, b)

    设置要比较的两个序列。

SequenceMatcher 计算并缓存有关第二个序列的详细信息,这样如果你想要将一个序列与多个序列进行比较,可使用 set_seq2() 一次性地设置该常用序列并重复地对每个其他序列各调用一次 set_seq1()

  • set_seq1(a)

    设置要比较的第一个序列。 要比较的第二个序列不会改变。

  • set_seq2(b)

    设置要比较的第二个序列。 要比较的第一个序列不会改变。

  • find_longest_match(alo=0, ahi=None, blo=0, bhi=None)

    找出 a[alo:ahi]b[blo:bhi] 中的最长匹配块。

    如果 isjunk 被省略或为 Nonefind_longest_match() 将返回 (i, j, k) 使得 a[i:i+k] 等于 b[j:j+k],其中 alo <= i <= i+k <= ahi 并且 blo <= j <= j+k <= bhi。 对于所有满足这些条件的 (i', j', k'),如果 i == i', j <= j' 也被满足,则附加条件 k >= k', i <= i'。 换句话说,对于所有最长匹配块,返回在 a 当中最先出现的一个,而对于在 a 当中最先出现的所有最长匹配块,则返回在 b 当中最先出现的一个。

    >>> s = SequenceMatcher(None, " abcd", "abcd abcd")
    >>> s.find_longest_match(0, 5, 0, 9)
    Match(a=0, b=4, size=5)

    如果提供了 isjunk,将按上述规则确定第一个最长匹配块,但额外附加不允许块内出现垃圾元素的限制。 然后将通过(仅)匹配两边的垃圾元素来尽可能地扩展该块。 这样结果块绝对不会匹配垃圾元素,除非同样的垃圾元素正好与有意义的匹配相邻。

    这是与之前相同的例子,但是将空格符视为垃圾。 这将防止 ' abcd' 直接与第二个序列末尾的 ' abcd' 相匹配。 而只可以匹配 'abcd',并且是匹配第二个序列最左边的 'abcd'

    >>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
    >>> s.find_longest_match(0, 5, 0, 9)
    Match(a=1, b=0, size=4)

    如果未找到匹配块,此方法将返回 (alo, blo, 0)

    此方法将返回一个 named tuple Match(a, b, size)

    在 3.9 版更改: 加入默认参数。

  • get_matching_blocks()

    返回描述非重叠匹配子序列的三元组列表。 每个三元组的形式为 (i, j, n),其含义为 a[i:i+n] == b[j:j+n]。 这些三元组按 ij 单调递增排列。

    最后一个三元组用于占位,其值为 (len(a), len(b), 0)。 它是唯一 n == 0 的三元组。 如果 (i, j, n)(i', j', n') 是在列表中相邻的三元组,且后者不是列表中的最后一个三元组,则 i+n < i'j+n < j';换句话说,相邻的三元组总是描述非相邻的相等块。

    >>> s = SequenceMatcher(None, "abxcd", "abcd")
    >>> s.get_matching_blocks()
    [Match(a=0, b=0, size=2), Match(a=3, b=2, size=2), Match(a=5, b=4, size=0)]
  • get_opcodes()

    返回描述如何将 a 变为 b 的 5 元组列表,每个元组的形式为 (tag, i1, i2, j1, j2)。 在第一个元组中 i1 == j1 == 0,而在其余的元组中 i1 等于前一个元组的 i2*,并且 *j1 也等于前一个元组的 j2

    tag 值为字符串,其含义如下:

    含意
    ‘replace’ a[i1:i2] 应由 b[j1:j2] 替换。
    ‘delete’ a[i1:i2] 应被删除。 请注意在此情况下 j1 == j2
    ‘insert’ b[j1:j2] 应插入到 a[i1:i1]。 请注意在此情况下 i1 == i2
    ‘equal’ a[i1:i2] == b[j1:j2] (两个子序列相同)。

    例如:

    >>> a = "qabxcd"
    >>> b = "abycdf"
    >>> s = SequenceMatcher(None, a, b)
    >>> for tag, i1, i2, j1, j2 in s.get_opcodes():
    ...     print('{:7}   a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format(
    ...         tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2]))
    delete    a[0:1] --> b[0:0]      'q' --> ''
    equal     a[1:3] --> b[0:2]     'ab' --> 'ab'
    replace   a[3:4] --> b[2:3]      'x' --> 'y'
    equal     a[4:6] --> b[3:5]     'cd' --> 'cd'
    insert    a[6:6] --> b[5:6]       '' --> 'f'
  • get_grouped_opcodes(n=3)

    返回一个带有最多 n 行上下文的分组的 generator。

    get_opcodes() 所返回的组开始,此方法会拆分出较小的更改簇并消除没有更改的间隔区域。

    这些分组以与 get_opcodes() 相同的格式返回。

  • ratio()

    返回一个取值范围 [0, 1] 的浮点数作为序列相似性度量。

    其中 T 是两个序列中元素的总数量,M 是匹配的数量,即 2.0*M / T。 请注意如果两个序列完全相同则该值为 1.0,如果两者完全不同则为 0.0

    如果 get_matching_blocks()get_opcodes() 尚未被调用则此方法运算消耗较大,在此情况下你可能需要先调用 quick_ratio()real_quick_ratio() 来获取一个上界。

    注解

    注意: ratio() 调用的结果可能会取决于参数的顺序。 例如:

    >>> SequenceMatcher(None, 'tide', 'diet').ratio()
    0.25
    >>> SequenceMatcher(None, 'diet', 'tide').ratio()
    0.5
  • quick_ratio()

    相对快速地返回一个 ratio() 的上界。

  • real_quick_ratio()

    非常快速地返回一个 ratio() 的上界。

这三个返回匹配部分占字符总数的比率的方法可能由于不同的近似级别而给出不一样的结果,但是 quick_ratio()real_quick_ratio() 总是会至少与 ratio() 一样大:

>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75
>>> s.quick_ratio()
0.75
>>> s.real_quick_ratio()
1.0

SequenceMatcher 的示例

以下示例比较两个字符串,并将空格视为“垃圾”:

>>> s = SequenceMatcher(lambda x: x == " ",
...                     "private Thread currentThread;",
...                     "private volatile Thread currentThread;")

ratio() 返回一个 [0, 1] 范围内的整数作为两个序列相似性的度量。 根据经验,ratio() 值超过 0.6 就意味着两个序列是近似匹配的:

>>> print(round(s.ratio(), 3))
0.866

如果你只对两个序列相匹配的位置感兴趣,则 get_matching_blocks() 就很方便:

>>> for block in s.get_matching_blocks():
...     print("a[%d] and b[%d] match for %d elements" % block)
a[0] and b[0] match for 8 elements
a[8] and b[17] match for 21 elements
a[29] and b[38] match for 0 elements

请注意 get_matching_blocks() 返回的最后一个元组总是只用于占位的 (len(a), len(b), 0),这也是元组末尾元素(匹配的元素数量)为 0 的唯一情况。

如果你想要知道如何将第一个序列转成第二个序列,可以使用 get_opcodes():

>>> for opcode in s.get_opcodes():
...     print("%6s a[%d:%d] b[%d:%d]" % opcode)
 equal a[0:8] b[0:8]
insert a[8:8] b[8:17]
 equal a[8:29] b[17:38]

参见

  • 此模块中的 get_close_matches() 函数显示了如何基于 SequenceMatcher 构建简单的代码来执行有用的功能。
  • 使用 SequenceMatcher 构建小型应用的 简易版本控制方案。

Differ 对象

请注意 Differ 所生成的增量并不保证是 最小 差异。 相反,最小差异往往是违反直觉的,因为它们会同步任何可能的地方,有时甚至意外产生相距 100 页的匹配。 将同步点限制为连续匹配保留了一些局部性概念,这偶尔会带来产生更长差异的代价。

Differ 类具有这样的构造器:

class difflib.Differ(linejunk=None, charjunk=None)

可选关键字形参 linejunkcharjunk 均为过滤函数 (或为 None):

linejunk: 接受单个字符串作为参数的函数,如果其为垃圾字符串则返回真值。 默认值为 None,意味着没有任何行会被视为垃圾行。

charjunk: 接受单个字符(长度为 1 的字符串)作为参数的函数,如果其为垃圾字符则返回真值。 默认值为 None,意味着没有任何字符会被视为垃圾字符。

这些垃圾过滤函数可加快查找差异的匹配速度,并且不会导致任何差异行或字符被忽略。

Differ 对象是通过一个单独方法来使用(生成增量)的:

  • compare(a, b)

    比较两个由行组成的序列,并生成增量(一个由行组成的序列)。

    每个序列必须包含一个以换行符结尾的单行字符串。 这样的序列可以通过文件类对象的 readlines() 方法来获取。 所生成的增量同样由以换行符结尾的字符串构成,可以通过文件类对象的 writelines() 方法原样打印出来。

Differ 示例

此示例比较两段文本。 首先我们设置文本为以换行符结尾的单行字符串构成的序列(这样的序列也可以通过文件类对象的 readlines() 方法来获取):

>>> text1 = '''  1. Beautiful is better than ugly.
...   2. Explicit is better than implicit.
...   3. Simple is better than complex.
...   4. Complex is better than complicated.
... '''.splitlines(keepends=True)
>>> len(text1)
4
>>> text1[0][-1]
'\n'
>>> text2 = '''  1. Beautiful is better than ugly.
...   3.   Simple is better than complex.
...   4. Complicated is better than complex.
...   5. Flat is better than nested.
... '''.splitlines(keepends=True)

接下来我们实例化一个 Differ 对象:

>>> d = Differ()

请注意在实例化 Differ 对象时我们可以传入函数来过滤掉“垃圾”行和字符。

最后,我们比较两个序列:

>>> result = list(d.compare(text1, text2))

result 是一个字符串列表,让我们将其美化打印出来:

>>> from pprint import pprint
>>> pprint(result)
['    1. Beautiful is better than ugly.\n',
 '-   2. Explicit is better than implicit.\n',
 '-   3. Simple is better than complex.\n',
 '+   3.   Simple is better than complex.\n',
 '?     ++\n',
 '-   4. Complex is better than complicated.\n',
 '?            ^                     ---- ^\n',
 '+   4. Complicated is better than complex.\n',
 '?           ++++ ^                      ^\n',
 '+   5. Flat is better than nested.\n']

作为单独的多行字符串显示出来则是这样:

>>> import sys
>>> sys.stdout.writelines(result)
    1. Beautiful is better than ugly.
-   2. Explicit is better than implicit.
-   3. Simple is better than complex.
+   3.   Simple is better than complex.
?     ++
-   4. Complex is better than complicated.
?            ^                     ---- ^
+   4. Complicated is better than complex.
?           ++++ ^                      ^
+   5. Flat is better than nested.

difflib 的命令行接口

这个实例演示了如何使用 difflib 来创建一个类似于 diff 的工具。 它同样包含在 Python 源码发布包中,文件名为 Tools/scripts/diff.py

#!/usr/bin/env python3
""" Command line interface to difflib.py providing diffs in four formats:
* ndiff:    lists every line and highlights interline changes.
* context:  highlights clusters of changes in a before/after format.
* unified:  highlights clusters of changes in an inline format.
* html:     generates side by side comparison with change highlights.
"""
import sys, os, difflib, argparse
from datetime import datetime, timezone
def file_mtime(path):
    t = datetime.fromtimestamp(os.stat(path).st_mtime,
                               timezone.utc)
    return t.astimezone().isoformat()
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', action='store_true', default=False,
                        help='Produce a context format diff (default)')
    parser.add_argument('-u', action='store_true', default=False,
                        help='Produce a unified format diff')
    parser.add_argument('-m', action='store_true', default=False,
                        help='Produce HTML side by side diff '
                             '(can use -c and -l in conjunction)')
    parser.add_argument('-n', action='store_true', default=False,
                        help='Produce a ndiff format diff')
    parser.add_argument('-l', '--lines', type=int, default=3,
                        help='Set number of context lines (default 3)')
    parser.add_argument('fromfile')
    parser.add_argument('tofile')
    options = parser.parse_args()
    n = options.lines
    fromfile = options.fromfile
    tofile = options.tofile
    fromdate = file_mtime(fromfile)
    todate = file_mtime(tofile)
    with open(fromfile) as ff:
        fromlines = ff.readlines()
    with open(tofile) as tf:
        tolines = tf.readlines()
    if options.u:
        diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
    elif options.n:
        diff = difflib.ndiff(fromlines, tolines)
    elif options.m:
        diff = difflib.HtmlDiff().make_file(fromlines,tolines,fromfile,tofile,context=options.c,numlines=n)
    else:
        diff = difflib.context_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
    sys.stdout.writelines(diff)
if __name__ == '__main__':
    main()

textwrap —- 文本自动换行与填充

源代码: Lib/textwrap.py


textwrap 模块提供了一些快捷函数,以及可以完成所有工作的类 TextWrapper。 如果你只是要对一两个文本字符串进行自动换行或填充,快捷函数应该就够用了;否则的话,你应该使用 TextWrapper 的实例来提高效率。

textwrap.wrap(text, width=70, **, initial_indent=’’, subsequent_indent=’’, expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, drop_whitespace=True, break_on_hyphens=True, tabsize=8, max_lines=None*)

text (字符串) 中的单独段落自动换行以使每行长度最多为 width 个字符。 返回由输出行组成的列表,行尾不带换行符。

TextWrapper 的实例属性对应的可选的关键字参数,具体文档见下。

textwrap.fill(text, width=70, **, initial_indent=’’, subsequent_indent=’’, expand_tabs=True, replace_whitespace=True, fix_sentence_endings=False, break_long_words=True, drop_whitespace=True, break_on_hyphens=True, tabsize=8, max_lines=None*)

text 中的单独段落自动换行,并返回一个包含被自动换行段落的单独字符串。 fill() 是以下语句的快捷方式

"\n".join(wrap(text, ...))

特别要说明的是,fill() 接受与 wrap() 完全相同的关键字参数。

textwrap.shorten(text, width, **, fix_sentence_endings=False, break_long_words=True, break_on_hyphens=True, placeholder=’ […]‘*)

折叠并截短给定的 text 以符合给定的 width

首先,将折叠 text 中的空格(所有连续空格替换为单个空格)。 如果结果能适合 width 则将其返回。 否则将丢弃足够数量的末尾单词以使得剩余单词加 placeholder 能适合 width

>>> textwrap.shorten("Hello  world!", width=12)
'Hello world!'
>>> textwrap.shorten("Hello  world!", width=11)
'Hello [...]'
>>> textwrap.shorten("Hello world", width=10, placeholder="...")
'Hello...'

可选的关键字参数对应于 TextWrapper 的实际属性,具体见下文。 请注意文本在被传入 TextWrapperfill() 函数之前会被折叠,因此改变 tabsize, expand_tabs, drop_whitespacereplace_whitespace 的值将没有任何效果。

3.4 新版功能.

textwrap.dedent(text)

移除 text 中每一行的任何相同前缀空白符。

这可以用来清除三重引号字符串行左侧空格,而仍然在源码中显示为缩进格式。

请注意制表符和空格符都被视为是空白符,但它们并不相等:以下两行 " hello""\thello" 不会被视为具有相同的前缀空白符。

只包含空白符的行会在输入时被忽略并在输出时被标准化为单个换行符。

例如:

def test():
    # end first line with \ to avoid the empty line!
    s = '''\
    hello
      world
    '''
    print(repr(s))          # prints '    hello\n      world\n    '
    print(repr(dedent(s)))  # prints 'hello\n  world\n'

textwrap.indent(text, prefix, predicate=None)

prefix 添加到 text 中选定行的开头。

通过调用 text.splitlines(True) 来对行进行拆分。

默认情况下,prefix 会被添加到所有不是只由空白符(包括任何行结束符)组成的行。

例如:

>>> s = 'hello\n\n \nworld'
>>> indent(s, '  ')
'  hello\n\n \n  world'

可选的 predicate 参数可用来控制哪些行要缩进。 例如,可以很容易地为空行或只有空白符的行添加 prefix:

>>> print(indent(s, '+ ', lambda line: True))
+ hello
+
+
+ world

3.3 新版功能.

wrap(), fill()shorten() 的作用方式为创建一个 TextWrapper 实例并在其上调用单个方法。 该实例不会被重用,因此对于要使用 wrap() 和/或 fill() 来处理许多文本字符串的应用来说,创建你自己的 TextWrapper 对象可能会更有效率。

文本最好在空白符位置自动换行,包括带连字符单词的连字符之后;长单词仅在必要时会被拆分,除非 TextWrapper.break_long_words 被设为假值。

class textwrap.TextWrapper(**kwargs)

TextWrapper 构造器接受多个可选的关键字参数。 每个关键字参数对应一个实例属性,比如说

wrapper = TextWrapper(initial_indent="* ")

相当于:

wrapper = TextWrapper()
wrapper.initial_indent = "* "

你可以多次重用相同的 TextWrapper 对象,并且你也可以在使用期间通过直接向实例属性赋值来修改它的任何选项。

TextWrapper 的实例属性(以及构造器的关键字参数)如下所示:

  • width

    (默认: 70) 自动换行的最大行长度。 只要输入文本中没有长于 width 的单个单词,TextWrapper 就能保证没有长于 width 个字符的输出行。

  • expand_tabs

    (默认: True) 如果为真值,则 text 中所有的制表符将使用 textexpandtabs() 方法扩展为空格符。

  • tabsize

    (默认: 8) 如果 expand_tabs 为真值,则 text 中所有的制表符将扩展为零个或多个空格,具体取决于当前列位置和给定的制表宽度。

    3.3 新版功能.

  • replace_whitespace

    (default: True) 如果为真值,在制表符扩展之后、自动换行之前,wrap() 方法将把每个空白字符都替换为单个空格。 会被替换的空白字符如下:制表,换行,垂直制表,进纸和回车 ('\t\n\v\f\r')。

    注解

    如果 expand_tabs 为假值且 replace_whitespace 为真值,每个制表符将被替换为单个空格,这与制表符扩展是 一样的。

    注解

    如果 replace_whitespace 为假值,在一行的中间有可能出现换行符并导致怪异的输出。 因此,文本应当(使用 str.splitlines() 或类似方法)拆分为段落并分别进行自动换行。

  • drop_whitespace

    (默认: True) 如果为真值,每一行开头和末尾的空白字符(在包装之后、缩进之前)会被丢弃。 但是段落开头的空白字符如果后面不带任何非空白字符则不会被丢弃。 如果被丢弃的空白字符占据了一个整行,则该整行将被丢弃。

  • initial_indent

    (默认: '') 将被添加到被自动换行输出内容的第一行的字符串。 其长度会被计入第一行的长度。 空字符串不会被缩进。

  • subsequent_indent

    (default: '') 将被添加到被自动换行输出内容除第一行外的所有行的字符串。 其长度会被计入除行一行外的所有行的长度。

  • fix_sentence_endings

    (默认: False) 如果为真值,TextWrapper 将尝试检测句子结尾并确保句子间总是以恰好两个空格符分隔。 对于使用等宽字体的文本来说通常都需要这样。 但是,句子检测算法并不完美:它假定句子结尾是一个小写字母加字符 '.', '!''?' 中的一个,并可能带有字符 '"'"'",最后以一个空格结束。 此算法的问题之一是它无法区分以下文本中的 “Dr.”

    [...] Dr. Frankenstein's monster [...]

    和以下文本中的 “Spot.”

    [...] See Spot. See Spot run [...]

    fix_sentence_endings 默认为假值。

    由于句子检测算法依赖于 string.lowercase 来确定“小写字母”,以及约定在句点后使用两个空格来分隔处于同一行的句子,因此只适用于英语文本。

  • break_long_words

    (默认: True) 如果为真值,则长度超过 width 的单词将被分开以保证行的长度不会超过 width。 如果为假值,超长单词不会被分开,因而某些行的长度可能会超过 width。 (超长单词将被单独作为一行,以尽量减少超出 width 的情况。)

  • break_on_hyphens

    (默认: True) 如果为真值,将根据英语的惯例首选在空白符和复合词的连字符之后自动换行。 如果为假值,则只有空白符会被视为合适的潜在断行位置,但如果你确实不希望出现分开的单词则你必须将 break_long_words 设为假值。 之前版本的默认行为总是允许分开带有连字符的单词。

  • max_lines

    (默认: None) 如果不为 None,则输出内容将最多包含 max_lines 行,并使 placeholder 出现在输出内容的末尾。

    3.4 新版功能.

  • placeholder

    (默认: ' [...]') 该文本将在输出文本被截短时出现在文本末尾。

    3.4 新版功能.

TextWrapper 还提供了一些公有方法,类似于模块层级的便捷函数:

  • wrap(text)

    text (字符串) 中的单独段落自动换行以使每行长度最多为 width 个字符。 所有自动换行选项均获取自 TextWrapper 实例的实例属性。 返回由输出行组成的列表,行尾不带换行符。 如果自动换行输出结果没有任何内容,则返回空列表。

  • fill(text)

    text 中的单独段落自动换行并返回包含被自动换行段落的单独字符串。

unicodedata —- Unicode 数据库

此模块提供了对 Unicode Character Database (UCD) 的访问,其中定义了所有 Unicode 字符的字符属性。 此数据库中包含的数据编译自 UCD 版本 13.0.0

该模块使用与 Unicode 标准附件 #44 “Unicode 字符数据库” 中所定义的相同名称和符号。 它定义了以下函数:

unicodedata.lookup(name)

按名称查找字符。如果找到具有给定名称的字符,则返回相应的字符。 如果没有找到,则 KeyError 被引发。

在 3.3 版更改: 已添加对名称别名命名序列 的支持。

unicodedata.name(chr[, default])

返回分配给字符 chr 的名称作为字符串。如果没有定义名称,则返回 default ,如果没有给出,则 ValueError 被引发。

unicodedata.decimal(chr[, default])

返回分配给字符 chr 的十进制值作为整数。 如果没有定义这样的值,则返回 default ,如果没有给出,则 ValueError 被引发。

unicodedata.digit(chr[, default])

返回分配给字符 chr 的数字值作为整数。 如果没有定义这样的值,则返回 default ,如果没有给出,则 ValueError 被引发。

unicodedata.numeric(chr[, default])

返回分配给字符 chr 的数值作为浮点数。 如果没有定义这样的值,则返回 default ,如果没有给出,则 ValueError 被引发。

unicodedata.category(chr)

返回分配给字符 chr 的常规类别为字符串。

unicodedata.bidirectional(chr)

返回分配给字符 chr 的双向类作为字符串。如果未定义此类值,则返回空字符串。

unicodedata.combining(chr)

返回分配给字符 chr 的规范组合类作为整数。如果没有定义组合类,则返回 0

unicodedata.east_asian_width(chr)

返回分配给字符 chr 的东亚宽度作为字符串。

unicodedata.mirrored(chr)

返回分配给字符 chr 的镜像属性为整数。如果字符在双向文本中被识别为“镜像”字符,则返回 1 ,否则返回 0

unicodedata.decomposition(chr)

返回分配给字符 chr 的字符分解映射作为字符串。如果未定义此类映射,则返回空字符串。

unicodedata.normalize(form, unistr)

返回 Unicode 字符串 unistr 的正常形式 formform 的有效值为 ‘NFC’ 、 ‘NFKC’ 、 ‘NFD’ 和 ‘NFKD’ 。

Unicode 标准基于规范等价和兼容性等效的定义定义了 Unicode 字符串的各种规范化形式。在 Unicode 中,可以以各种方式表示多个字符。 例如,字符 U+00C7 (带有 CEDILLA 的 LATIN CAPITAL LETTER C )也可以表示为序列 U+0043( LATIN CAPITAL LETTER C )U+0327( COMBINING CEDILLA )。

对于每个字符,有两种正规形式:正规形式 C 和正规形式 D 。正规形式D(NFD)也称为规范分解,并将每个字符转换为其分解形式。 正规形式C(NFC)首先应用规范分解,然后再次组合预组合字符。

除了这两种形式之外,还有两种基于兼容性等效的其他常规形式。 在 Unicode 中,支持某些字符,这些字符通常与其他字符统一。 例如, U+2160(ROMAN NUMERAL ONE)与 U+0049(LATIN CAPITAL LETTER I)完全相同。 但是, Unicode 支持它与现有字符集(例如 gb2312 )的兼容性。

正规形式KD(NFKD)将应用兼容性分解,即用其等价项替换所有兼容性字符。 正规形式KC(NFKC)首先应用兼容性分解,然后是规范组合。

即使两个 unicode 字符串被规范化并且人类读者看起来相同,如果一个具有组合字符而另一个没有,则它们可能无法相等。

unicodedata.is_normalized(form, unistr)

判断 Unicode 字符串 unistr 是否为正规形式 form*。 *form 的有效值为 ‘NFC’, ‘NFKC’, ‘NFD’ 和 ‘NFKD’。

3.8 新版功能.

此外,该模块暴露了以下常量:

unicodedata.unidata_version

此模块中使用的 Unicode 数据库的版本。

unicodedata.ucd_3_2_0

这是一个与整个模块具有相同方法的对象,但对于需要此特定版本的 Unicode 数据库(如 IDNA )的应用程序,则使用 Unicode 数据库版本 3.2 。

示例:

>>> import unicodedata
>>> unicodedata.lookup('LEFT CURLY BRACKET')
'{'
>>> unicodedata.name('/')
'SOLIDUS'
>>> unicodedata.decimal('9')
9
>>> unicodedata.decimal('a')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not a decimal
>>> unicodedata.category('A')  # 'L'etter, 'u'ppercase
'Lu'
>>> unicodedata.bidirectional('\u0660') # 'A'rabic, 'N'umber
'AN'

stringprep —- 因特网字符串预备

源代码: Lib/stringprep.py


在标识因特网上的事物(例如主机名),经常需要比较这些标识是否(相等)。 这种比较的具体执行可能会取决于应用域的不同,例如是否要区分大小写等等。 有时也可能需要限制允许的标识为仅由“可打印”字符组成。

RFC 3454 定义了在因特网协议中 Unicode 字符串的“预备”过程。 在将字符串连线传输之前,它们会先使用预备过程进行处理,之后它们将具有特定的标准形式。 该 RFC 定义了一系列表格,它们可以被组合为选项配置。 每个配置必须定义所使用的表格,stringprep 过程的其他可选项也是配置的组成部分。 stringprep 配置的一个例子是 nameprep,它被用于国际化域名。

模块 stringprep 仅公开了来自 RFC 3454 的表格。 由于这些如果表格如果表示为字典或列表将会非常庞大,该模块在内部使用 Unicode 字符数据库。 该模块本身的源代码是使用 mkstringprep.py 工具生成的。

因此,这些表格以函数而非数据结构的形式公开。 在 RFC 中有两种表格:集合与映射。 对于集合,stringprep 提供了“特征函数”,即如果形参是集合的一部分则返回值为 True 的函数。 对于映射,它提供了映射函数:它会根据给定的键返回所关联的值。 以下是模块中所有可用函数的列表。

stringprep.in_table_a1(code)

确定 code 是否属于 tableA.1 (Unicode 3.2 中的未分配码位)。

stringprep.in_table_b1(code)

确定 code 是否属于 tableB.1 (通常映射为空值)。

stringprep.map_table_b2(code)

返回 code 依据 tableB.2 (配合 NFKC 使用的大小写转换映射) 所映射的值。

stringprep.map_table_b3(code)

返回 code 依据 tableB.3 (不附带正规化的大小写折叠映射) 所映射的值。

stringprep.in_table_c11(code)

确定 code 是否属于 tableC.1.1 (ASCII 空白字符)。

stringprep.in_table_c12(code)

确定 code 是否属于 tableC.1.2 (非 ASCII 空白字符)。

stringprep.in_table_c11_c12(code)

确定 code 是否属于 tableC.1 (空白字符,C.1.1 和 C.1.2 的并集)。

stringprep.in_table_c21(code)

确定 code 是否属于 tableC.2.1 (ASCII 控制字符)。

stringprep.in_table_c22(code)

确定 code 是否属于 tableC.2.2 (非 ASCII 控制字符)。

stringprep.in_table_c21_c22(code)

确定 code 是否属于 tableC.2 (控制字符,C.2.1 和 C.2.2 的并集)。

stringprep.in_table_c3(code)

确定 code 是否属于 tableC.3 (私有使用)。

stringprep.in_table_c4(code)

确定 code 是否属于 tableC.4 (非字符码位)。

stringprep.in_table_c5(code)

确定 code 是否属于 tableC.5 (替代码)。

stringprep.in_table_c6(code)

确定 code 是否属于 tableC.6 (不适用于纯文本)。

stringprep.in_table_c7(code)

确定 code 是否属于 tableC.7 (不适用于规范表示)。

stringprep.in_table_c8(code)

确定 code 是否属于 tableC.8 (改变显示属性或已弃用)。

stringprep.in_table_c9(code)

确定 code 是否属于 tableC.9 (标记字符)。

stringprep.in_table_d1(code)

确定 code 是否属于 tableD.1 (带有双向属性 “R” 或 “AL” 的字符)。

stringprep.in_table_d2(code)

确定 code 是否属于 tableD.2 (带有双向属性 “L” 的字符)。

readline —- GNU readline 接口


readline 模块定义了许多方便从 Python 解释器完成和读取/写入历史文件的函数。 此模块可以直接使用,或通过支持在交互提示符下完成 Python 标识符的 rlcompleter 模块使用。 使用此模块进行的设置会同时影响解释器的交互提示符以及内置 input() 函数提供的提示符。

Readline keybindings may be configured via an initialization file, typically .inputrc in your home directory. See Readline Init File in the GNU Readline manual for information about the format and allowable constructs of that file, and the capabilities of the Readline library in general.

注解

底层的 Readline 库 API 可能使用 libedit 库来实现而不是 GNU readline。 在 macOS 上 readline 模块会在运行时检测所使用的是哪个库。

libedit 所用的配置文件与 GNU readline 的不同。 如果你要在程序中载入配置字符串你可以在 readline.__doc__ 中检测文本 “libedit” 来区分 GNU readline 和 libedit。

如果你是在 macOS 上使用 editline/libedit readline 模拟,则位于你的主目录中的初始化文件名称为 .editrc。 例如,~/.editrc 中的以下内容将开启 vi 按键绑定以及 TAB 补全:

python:bind -vpython:bind ^I rl_complete

初始化文件

下列函数与初始化文件和用户配置有关:

readline.parse_and_bind(string)

执行在 string 参数中提供的初始化行。 此函数会调用底层库中的 rl_parse_and_bind()

readline.read_init_file([filename])

执行一个 readline 初始化文件。 默认文件名为最近所使用的文件名。 此函数会调用底层库中的 rl_read_init_file()

行缓冲区

下列函数会在行缓冲区上操作。

readline.get_line_buffer()

返回行缓冲区的当前内容 (底层库中的 rl_line_buffer)。

readline.insert_text(string)

将文本插入行缓冲区的当前游标位置。 该函数会调用底层库中的 rl_insert_text(),但会忽略其返回值。

readline.redisplay()

改变屏幕的显示以反映行缓冲区的当前内容。 该函数会调用底层库中的 rl_redisplay()

历史文件

下列函数会在历史文件上操作:

readline.read_history_file([filename])

载入一个 readline 历史文件,并将其添加到历史列表。 默认文件名为 ~/.history。 此函数会调用底层库中的 read_history()

readline.write_history_file([filename])

将历史列表保存为 readline 历史文件,覆盖任何现有文件。 默认文件名为 ~/.history。 此函数会调用底层库中的 write_history()

readline.append_history_file(nelements[, filename])

将历史列表的最后 nelements 项添加到历史文件。 默认文件名为 ~/.history。 文件必须已存在。 此函数会调用底层库中的 append_history()。 此函数仅当 Python 编译包带有支持此功能的库版本时才会存在。

3.5 新版功能.

readline.get_history_length()

readline.set_history_length(length)

设置或返回需要保存到历史文件的行数。 write_history_file() 函数会通过调用底层库中的 history_truncate_file() 以使用该值来截取历史文件。 负值意味着不限制历史文件的大小。

历史列表

以下函数会在全局历史列表上操作:

readline.clear_history()

清除当前历史。 此函数会调用底层库的 clear_history()。 此 Python 函数仅当 Python 编译包带有支持此功能的库版本时才会存在。

readline.get_current_history_length()

返回历史列表的当前项数。 (此函数不同于 get_history_length(),后者是返回将被写入历史文件的最大行数。)

readline.get_history_item(index)

返回序号为 index 的历史条目的当前内容。 条目序号从一开始。 此函数会调用底层库中的 history_get()

readline.remove_history_item(pos)

从历史列表中移除指定位置上的历史条目。 条目位置从零开始。 此函数会调用底层库中的 remove_history()

readline.replace_history_item(pos, line)

将指定位置上的历史条目替换为 line。 条目位置从零开始。 此函数会调用底层库中的 replace_history_entry()

readline.add_history(line)

line 添加到历史缓冲区,相当于是最近输入的一行。 此函数会调用底层库中的 add_history()

readline.set_auto_history(enabled)

启用或禁用当通过 readline 读取输入时自动调用 add_history()enabled 参数应为一个布尔值,当其为真值时启用自动历史,当其为假值时禁用自动历史。

3.6 新版功能.

CPython implementation detail: Auto history is enabled by default, and changes to this do not persist across multiple sessions.

启动钩子

readline.set_startup_hook([function])

设置或移除底层库的 rl_startup_hook 回调所发起调用的函数。 如果指定了 function,它将被用作新的钩子函数;如果省略或为 None,任何已安装的函数将被移除。 钩子函数将在 readline 打印第一个提示信息之前不带参数地被调用。

readline.set_pre_input_hook([function])

设置或移除底层库的 rl_pre_input_hook 回调所发起调用的函数。 如果指定了 function,它将被用作新的钩子函数;如果省略或为 None,任何已安装的函数将被移除。 钩子函数将在打印第一个提示信息之后、readline 开始读取输入字符之前不带参数地被调用。 此函数仅当 Python 编译包带有支持此功能的库版本时才会存在。

Completion

以下函数与自定义单词补全函数的实现有关。 这通常使用 Tab 键进行操作,能够提示并自动补全正在输入的单词。 默认情况下,Readline 设置为由 rlcompleter 来补全交互模式解释器的 Python 标识符。 如果 readline 模块要配合自定义的补全函数来使用,则需要设置不同的单词分隔符。

readline.set_completer([function])

设置或移除补全函数。 如果指定了 function*,它将被用作新的补全函数;如果省略或为 None,任何已安装的补全函数将被移除。 补全函数的调用形式为 function(text, state),其中 *state0, 1, 2, …, 直至其返回一个非字符串值。 它应当返回下一个以 text 开头的候选补全内容。

已安装的补全函数将由传递给底层库中 rl_completion_matches()entry_func 回调函数来发起调用。 text 字符串来自于底层库中 rl_attempted_completion_function 回调函数的第一个形参。

readline.get_completer()

获取补全函数,如果没有设置补全函数则返回 None

readline.get_completion_type()

获取正在尝试的补全类型。 此函数会将底层库中的 rl_completion_type 变量作为一个整数返回。

readline.get_begidx()

readline.get_endidx()

获取完全范围的开始和结束索引号。 这些索引号就是传递给下层库的 rl_attempted_completion_function 回调的 startend 参数。 具体值在同一个输入编辑场景中可能不同,具体取决于下层的 C readline 实现。 例如:已知 libedit 的行为就不同于 libreadline。

readline.set_completer_delims(string)

readline.get_completer_delims()

设置或获取补全的单词分隔符。 此分隔符确定了要考虑补全的单词的开始和结束位置(补全域)。 这些函数会访问底层库的 rl_completer_word_break_characters 变量。

readline.set_completion_display_matches_hook([function])

设置或移除补全显示函数。 如果指定了 function,它将被用作新的补全显示函数;如果省略或为 None,任何已安装的补全显示函数将被移除。 此函数会设置或清除底层库的 rl_completion_display_matches_hook 回调函数。 补全显示函数会在每次需要显示匹配项时以 function(substitution, [matches], longest_match_length) 的形式被调用。

示例

以下示例演示了如何使用 readline 模块的历史读取或写入函数来自动加载和保存用户主目录下名为 .python_history 的历史文件。 以下代码通常应当在交互会话期间从用户的 PYTHONSTARTUP 文件自动执行。

import atexit
import os
import readline
histfile = os.path.join(os.path.expanduser("~"), ".python_history")
try:
    readline.read_history_file(histfile)
    # default history len is -1 (infinite), which may grow unruly
    readline.set_history_length(1000)
except FileNotFoundError:
    pass
atexit.register(readline.write_history_file, histfile)

此代码实际上会在 Python 运行于 交互模式 时自动运行。

以下示例实现了同样的目标,但是通过只添加新历史的方式来支持并发的交互会话。

import atexit
import os
import readline
histfile = os.path.join(os.path.expanduser("~"), ".python_history")
try:
    readline.read_history_file(histfile)
    h_len = readline.get_current_history_length()
except FileNotFoundError:
    open(histfile, 'wb').close()
    h_len = 0
def save(prev_h_len, histfile):
    new_h_len = readline.get_current_history_length()
    readline.set_history_length(1000)
    readline.append_history_file(new_h_len - prev_h_len, histfile)
atexit.register(save, h_len, histfile)

以下示例扩展了 code.InteractiveConsole 类以支持历史保存/恢复。

import atexit
import code
import os
import readline
class HistoryConsole(code.InteractiveConsole):
    def __init__(self, locals=None, filename="<console>",
                 histfile=os.path.expanduser("~/.console-history")):
        code.InteractiveConsole.__init__(self, locals, filename)
        self.init_history(histfile)
    def init_history(self, histfile):
        readline.parse_and_bind("tab: complete")
        if hasattr(readline, "read_history_file"):
            try:
                readline.read_history_file(histfile)
            except FileNotFoundError:
                pass
            atexit.register(self.save_history, histfile)
    def save_history(self, histfile):
        readline.set_history_length(1000)
        readline.write_history_file(histfile)

rlcompleter —- GNU readline 的补全函数

源代码: Lib/rlcompleter.py


rlcompeleter 通过补全有效的 Python 标识符和关键字定义了一个适用于 readline 模块的补全函数。

当此模块在具有可用的 readline 模块的 Unix 平台被导入, 一个 Completer 实例将被自动创建并且它的 complete() 方法将设置为 readline 的补全器.

示例:

>>> import rlcompleter
>>> import readline
>>> readline.parse_and_bind("tab: complete")
>>> readline. <TAB PRESSED>
readline.__doc__          readline.get_line_buffer(  readline.read_init_file(
readline.__file__         readline.insert_text(      readline.set_completer(
readline.__name__         readline.parse_and_bind(
>>> readline.

rlcompleter 模块是为了使用 Python 的 交互模式 而设计的。 除非 Python 是通过 -S 选项运行, 这个模块总是自动地被导入且配置 。

在没有 readline 的平台, 此模块定义的 Completer 类仍然可以用于自定义行为.

Completer 对象

Completer 对象具有以下方法:

Completer.complete(text, state)

text 返回第 state 项补全。

如果指定的 text 不包含句点字符 ('.'),它将根据当前 __main__, builtins 和保留关键字(定义于 keyword 模块)所定义的名称进行补全。

如果为带有句点的名称执行调用,它将尝试尽量求值直到最后一部分为止而不产生附带影响(函数不会被求值,但它可以生成对 __getattr__() 的调用),并通过 dir() 函数来匹配剩余部分。 在对表达式求值期间引发的任何异常都会被捕获、静默处理并返回 None

二进制数据服务

下面描述的一些库 文本处理服务 也可以使用 ASCII 兼容的二进制格式(例如 re )或所有二进制数据(例如 difflib )。

  • struct —- 将字节串解读为打包的二进制数据
    • 函数和异常
    • 格式字符串
      • 字节顺序,大小和对齐方式
      • 格式字符
      • 例子
  • codecs —- 编解码器注册和相关基类
    • 编解码器基类
      • 错误处理方案
      • 无状态的编码和解码
      • 增量式的编码和解码
        • IncrementalEncoder 对象
        • IncrementalDecoder 对象
      • 流式的编码和解码
        • StreamWriter 对象
        • StreamReader 对象
        • StreamReaderWriter 对象
        • StreamRecoder 对象
    • 编码格式与 Unicode
    • 标准编码
    • Python 专属的编码格式
      • 文字编码
      • 二进制转换
      • 文字转换
    • encodings.idna —- 应用程序中的国际化域名
    • encodings.mbcs —- Windows ANSI代码页
    • encodings.utf_8_sig —- 带BOM签名的UTF-8编解码器

struct —- 将字节串解读为打包的二进制数据

源代码: Lib/struct.py


此模块可以执行 Python 值和以 Python bytes 对象表示的 C 结构之间的转换。 这可以被用来处理存储在文件中或是从网络连接等其他来源获取的二进制数据。 它使用 格式字符串 作为 C 结构布局的精简描述以及与 Python 值的双向转换。

注解

默认情况下,打包给定 C 结构的结果会包含填充字节以使得所涉及的 C 类型保持正确的对齐;类似地,对齐在解包时也会被纳入考虑。 选择此种行为的目的是使得被打包结构的字节能与相应 C 结构在内存中的布局完全一致。 要处理平台独立的数据格式或省略隐式的填充字节,请使用 standard 大小和对齐而不是 native 大小和对齐。

某些 struct 的函数(以及 Struct 的方法)接受一个 buffer 参数。 这将指向实现了 缓冲协议 并提供只读或是可读写缓冲的对象。 用于此目的的最常见类型为 bytesbytearray,但许多其他可被视为字节数组的类型也实现了缓冲协议,因此它们无需额外从 bytes 对象复制即可被读取或填充。

函数和异常

此模块定义了下列异常和函数:

exception struct.error

会在多种场合下被引发的异常;其参数为一个描述错误信息的字符串。

struct.pack(format, v1, v2, )

返回一个 bytes 对象,其中包含根据格式字符串 format 打包的值 v1, v2, … 参数个数必须与格式字符串所要求的值完全匹配。

struct.pack_into(format, buffer, offset, v1, v2, )

根据格式字符串 format 打包 v1, v2, … 等值并将打包的字节串写入可写缓冲区 bufferoffset 开始的位置。 请注意 offset 是必需的参数。

struct.unpack(format, buffer)

根据格式字符串 format 从缓冲区 buffer 解包(假定是由 pack(format, ...) 打包)。 结果为一个元组,即使其只包含一个条目。 缓冲区的字节大小必须匹配格式所要求的大小,如 calcsize() 所示。

struct.unpack_from(format, /, buffer, offset=0)

buffer 从位置 offset 开始根据格式字符串 format 进行解包。 结果为一个元组,即使其中只包含一个条目。 缓冲区的字节大小从位置 offset 开始必须至少为 calcsize() 显示的格式所要求的大小。

struct.iter_unpack(format, buffer)

根据格式字符串 format 以迭代方式从缓冲区 buffer 解包。 此函数返回一个迭代器,它将从缓冲区读取相同大小的块直至其内容全部耗尽。 缓冲区的字节大小必须整数倍于格式所要求的大小,如 calcsize() 所示。

每次迭代将产生一个如格式字符串所指定的元组。

3.4 新版功能.

struct.calcsize(format)

返回与格式字符串 format 相对应的结构的大小(亦即 pack(format, ...) 所产生的字节串对象的大小)。

格式字符串

格式字符串是用来在打包和解包数据时指定预期布局的机制。 它们使用指定被打包/解包数据类型的 格式字符 进行构建。 此外,还有一些特殊字符用来控制 字节顺序,大小和对齐方式。

字节顺序,大小和对齐方式

默认情况下,C类型以机器的本机格式和字节顺序表示,并在必要时通过跳过填充字节进行正确对齐(根据C编译器使用的规则)。

或者,根据下表,格式字符串的第一个字符可用于指示打包数据的字节顺序,大小和对齐方式:

字符 字节顺序 大小 对齐方式
@ 按原字节 按原字节 按原字节
= 按原字节 标准
< 小端 标准
> 大端 标准
! 网络(=大端) 标准

如果第一个字符不是其中之一,则假定为 '@'

本机字节顺序可能为大端或是小端,取决于主机系统的不同。 例如, Intel x86 和 AMD64 (x86-64) 是小端的;Motorola 68000 和 PowerPC G5 是大端的;ARM 和 Intel Itanium 具有可切换的字节顺序(双端)。 请使用 sys.byteorder 来检查你的系统字节顺序。

本机大小和对齐方式是使用 C 编译器的 sizeof 表达式来确定的。 这总是会与本机字节顺序相绑定。

标准大小仅取决于格式字符。

请注意 '@''=' 之间的区别:两个都使用本机字节顺序,但后者的大小和对齐方式是标准化的。

形式 '!' 代表网络字节顺序总是使用在 IETF RFC 1700 中所定义的大端序。

没有什么方式能指定非本机字节顺序(强制字节对调);请正确选择使用 '<''>'

注释:

  1. 填充只会在连续结构成员之间自动添加。 填充不会添加到已编码结构的开头和末尾。
  2. 当使用非本机大小和对齐方式即 ‘<’, ‘>’, ‘=’, and ‘!’ 时不会添加任何填充。
  3. 要将结构的末尾对齐到符合特定类型的对齐要求,请以该类型代码加重复计数的零作为格式结束。

格式字符

格式字符具有以下含义;C 和 Python 值之间的按其指定类型的转换应当是相当明显的。 ‘标准大小’列是指当使用标准大小时以字节表示的已打包值大小;也就是当格式字符串以 '<', '>', '!''=' 之一开头的情况。 当使用本机大小时,已打包值的大小取决于具体的平台。

格式 C 类型 Python 类型 标准大小 备注
x 填充字节
c char 长度为 1 的字节串 1
b signed char 整数 1 (1), (2)
B unsigned char 整数 1 (2)
? _Bool bool 1 (1)
h short 整数 2 (2)
H unsigned short 整数 2 (2)
i int 整数 4 (2)
I unsigned int 整数 4 (2)
l long 整数 4 (2)
L unsigned long 整数 4 (2)
q long long 整数 8 (2)
Q unsigned long long 整数 8 (2)
n ssize_t 整数 (3)
N size_t 整数 (3)
e (6) float 2 (4)
f float float 4 (4)
d double float 8 (4)
s char[] 字节串
p char[] 字节串
P void* 整数 (5)

在 3.3 版更改: 增加了对 'n''N' 格式的支持

在 3.6 版更改: 添加了对 'e' 格式的支持。

注释:

  1. '?' 转换码对应于 C99 定义的 _Bool 类型。 如果此类型不可用,则使用 char 来模拟。 在标准模式下,它总是以一个字节表示。

  2. 当尝试使用任何整数转换码打包一个非整数时,如果该非整数具有 __index__() 方法,则会在打包之前调用该方法将参数转换为一个整数。

    在 3.2 版更改: 增加了针对非整数使用 __index__() 方法的特性。

  3. 'n''N' 转换码仅对本机大小可用(选择为默认或使用 '@' 字节顺序字符)。 对于标准大小,你可以使用适合你的应用的任何其他整数格式。

  4. 对于 'f', 'd''e' 转换码,打包表示形式将使用 IEEE 754 binary32, binary64 或 binary16 格式 (分别对应于 'f', 'd''e'),无论平台使用何种浮点格式。

  5. 'P' 格式字符仅对本机字节顺序可用(选择为默认或使用 '@' 字节顺序字符)。 字节顺序字符 '=' 选择使用基于主机系统的小端或大端排序。 struct 模块不会将其解读为本机排序,因此 'P' 格式将不可用。

  6. IEEE 754 binary16 “半精度” 类型是在 IEEE 754 标准 的 2008 修订版中引入的。 它包含一个符号位,5 个指数位和 11 个精度位(明确存储 10 位),可以完全精确地表示大致范围在 6.1e-056.5e+04 之间的数字。 此类型并不被 C 编译器广泛支持:在一台典型的机器上,可以使用 unsigned short 进行存储,但不会被用于数学运算。 请参阅维基百科页面 half-precision floating-point format 了解详情。

格式字符之前可以带有整数重复计数。 例如,格式字符串 '4h' 的含义与 'hhhh' 完全相同。

格式之间的空白字符会被忽略;但是计数及其格式字符中不可有空白字符。

对于 's' 格式字符,计数会被解析为字节的长度,而不是像其他格式字符那样的重复计数;例如,'10s' 表示一个 10 字节的字节串,而 '10c' 表示 10 个字符。 如果未给出计数,则默认值为 1。 对于打包操作,字节串会被适当地截断或填充空字节以符合要求。 对于解包操作,结果字节对象总是恰好具有指定数量的字节。 作为特殊情况,'0s' 表示一个空字符串(而 '0c' 表示 0 个字符)。

当使用某一种整数格式 ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q') 打包值 x 时,如果 x 在该格式的有效范围之外则将引发 struct.error

在 3.1 版更改: 在之前版本中,某些整数格式包装了超范围的值并会引发 DeprecationWarning 而不是 struct.error

'p' 格式字符用于编码“Pascal 字符串”,即存储在由计数指定的 固定长度字节 中的可变长度短字符串。 所存储的第一个字节为字符串长度或 255 中的较小值。 之后是字符串对应的字节。 如果传入 pack() 的字符串过长(超过计数值减 1),则只有字符串前 count-1 个字节会被存储。 如果字符串短于 count-1,则会填充空字节以使得恰好使用了 count 个字节。 请注意对于 unpack()'p' 格式字符会消耗 count 个字节,但返回的字符串永远不会包含超过 255 个字节。

对于 '?' 格式字符,返回值为 TrueFalse。 在打包时将会使用参数对象的逻辑值。 以本机或标准 bool 类型表示的 0 或 1 将被打包,任何非零值在解包时将为 True

例子

注解

所有示例都假定使用一台大端机器的本机字节顺序、大小和对齐方式。

打包/解包三个整数的基础示例:

>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8

解包的字段可通过将它们赋值给变量或将结果包装为一个具名元组来命名:

>>> record = b'raymond   \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)
>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

格式字符的顺序可能对大小产生影响,因为满足对齐要求所需的填充是不同的:

>>> pack('ci', b'*', 0x12131415)
b'*\x00\x00\x00\x12\x13\x14\x15'
>>> pack('ic', 0x12131415, b'*')
b'\x12\x13\x14\x15*'
>>> calcsize('ci')
8
>>> calcsize('ic')
5

以下格式 'llh0l' 指定在末尾有两个填充字节,假定 long 类型按 4 个字节的边界对齐:

>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

这仅当本机大小和对齐方式生效时才会起作用;标准大小和对齐方式并不会强制进行任何对齐。

struct 模块还定义了以下类型:

class struct.Struct(format)

返回一个新的 Struct 对象,它会根据格式字符串 format 来写入和读取二进制数据。 一次性地创建 Struct 对象并调用其方法相比使用同样的格式调用 struct 函数更为高效,因为这样格式字符串只需被编译一次。

注解

传递给 Struct 和模块层级函数的已编译版最新格式字符串会被缓存,因此只使用少量格式字符串的程序无需担心重用单独的 Struct 实例。

已编译的 Struct 对象支持以下方法和属性:

  • pack(v1, v2, )

    等价于 pack() 函数,使用了已编译的格式。 (len(result) 将等于 size。)

  • pack_into(buffer, offset, v1, v2, )

    等价于 pack_into() 函数,使用了已编译的格式。

  • unpack(buffer)

    等价于 unpack() 函数,使用了已编译的格式。 缓冲区的字节大小必须等于 size

  • unpack_from(buffer, offset=0)

    等价于 unpack_from() 函数,使用了已编译的格式。 缓冲区的字节大小从位置 offset 开始必须至少为 size

  • iter_unpack(buffer)

    等价于 iter_unpack() 函数,使用了已编译的格式。 缓冲区的大小必须为 size 的整数倍。

    3.4 新版功能.

  • format

    用于构造此 Struct 对象的格式字符串。

    在 3.7 版更改: 格式字符串类型现在是 str 而不再是 bytes

  • size

    计算出对应于 format 的结构大小(亦即 pack() 方法所产生的字节串对象的大小)。

codecs —- 编解码器注册和相关基类

源代码: Lib/codecs.py


这个模块定义了标准 Python 编解码器(编码器和解码器)的基类,并提供接口用来访问内部的 Python 编解码器注册表,该注册表负责管理编解码器和错误处理的查找过程。 大多数标准编解码器都属于 文本编码,它们可将文本编码为字节串,但也提供了一些编解码器可将文本编码为文本,以及字节串编码为字节串。 自定义编解码器可以在任意类型间进行编码和解码,但某些模块特性仅适用于 文本编码 或将数据编码为 字节串 的编解码器。

该模块定义了以下用于使用任何编解码器进行编码和解码的函数:

codecs.encode(obj, encoding=’utf-8’, errors=’strict’)

使用为 encoding 注册的编解码器对 obj 进行编码。

可以给定 Errors 以设置所需要的错误处理方案。 默认的错误处理方案 'strict' 表示编码错误将引发 ValueError (或更特定编解码器相关的子类,例如 UnicodeEncodeError)。

codecs.decode(obj, encoding=’utf-8’, errors=’strict’)

使用为 encoding 注册的编解码器对 obj 进行解码。

可以给定 Errors 以设置所需要的错误处理方案。 默认的错误处理方案 'strict' 表示编码错误将引发 ValueError (或更特定编解码器相关的子类,例如 UnicodeDecodeError)。

每种编解码器的完整细节也可以直接查找获取:

codecs.lookup(encoding)

在 Python 编解码器注册表中查找编解码器信息,并返回一个 CodecInfo 对象,其定义见下文。

首先将会在注册表缓存中查找编码,如果未找到,则会扫描注册的搜索函数列表。 如果没有找到 CodecInfo 对象,则将引发 LookupError。 否则,CodecInfo 对象将被存入缓存并返回给调用者。

class codecs.CodecInfo(encode, decode, streamreader=None, streamwriter=None, incrementalencoder=None, incrementaldecoder=None, name=None)

查找编解码器注册表所得到的编解码器细节信息。 构造器参数将保存为同名的属性:

  • name

    编码名称

  • encode

    decode

    无状态的编码和解码函数。 它们必须是具有与 Codec 的 encode()decode() 方法相同接口的函数或方法。 这些函数或方法应当工作于无状态的模式。

  • incrementalencoder

    incrementaldecoder

    增量式的编码器和解码器类或工厂函数。 这些函数必须分别提供由基类 IncrementalEncoderIncrementalDecoder 所定义的接口。 增量式编解码器可以保持状态。

  • streamwriter

    streamreader

    流式写入器和读取器类或工厂函数。 这些函数必须分别提供由基类 StreamWriterStreamReader 所定义的接口。 流式编解码器可以保持状态。

为了简化对各种编解码器组件的访问,本模块提供了以下附加函数,它们使用 lookup() 来执行编解码器查找:

codecs.getencoder(encoding)

查找给定编码的编解码器并返回其编码器函数。

在编码无法找到时将引发 LookupError

codecs.getdecoder(encoding)

查找给定编码的编解码器并返回其解码器函数。

在编码无法找到时将引发 LookupError

codecs.getincrementalencoder(encoding)

查找给定编码的编解码器并返回其增量式编码器类或工厂函数。

在编码无法找到或编解码器不支持增量式编码器时将引发 LookupError

codecs.getincrementaldecoder(encoding)

查找给定编码的编解码器并返回其增量式解码器类或工厂函数。

在编码无法找到或编解码器不支持增量式解码器时将引发 LookupError

codecs.getreader(encoding)

查找给定编码的编解码器并返回其 StreamReader 类或工厂函数。

在编码无法找到时将引发 LookupError

codecs.getwriter(encoding)

查找给定编码的编解码器并返回其 StreamWriter 类或工厂函数。

在编码无法找到时将引发 LookupError

自定义编解码器的启用是通过注册适当的编解码器搜索函数:

codecs.register(search_function)

注册一个编解码器搜索函数。 搜索函数预期接收一个参数,即全部以小写字母表示的编码格式名称,其中中连字符和空格会被转换为下划线,并返回一个 CodecInfo 对象。 在搜索函数无法找到给定编码格式的情况下,它应当返回 None

在 3.9 版更改: 连字符和空格会被转换为下划线。

codecs.unregister(search_function)

注销一个编解码器搜索函数并清空注册表缓存。 如果指定搜索函数未被注册,则不做任何操作。

3.10 新版功能.

虽然内置的 open() 和相关联的 io 模块是操作已编码文本文件的推荐方式,但本模块也提供了额外的工具函数和类,允许在操作二进制文件时使用更多各类的编解码器:

codecs.open(filename, mode=’r’, encoding=None, errors=’strict’, buffering=- 1)

使用给定的 mode 打开已编码的文件并返回一个 StreamReaderWriter 的实例,提供透明的编码/解码。 默认的文件模式为 'r',表示以读取模式打开文件。

注解

下层的已编码文件总是以二进制模式打开。 在读取和写入时不会自动执行 '\n' 的转换。 mode 参数可以是内置 open() 函数所接受的任意二进制模式;'b' 会被自动添加。

encoding 指定文件所要使用的编码格式。 允许任何编码为字节串或从字节串解码的编码格式,而文件方法所支持的数据类型则取决于所使用的编解码器。

可以指定 errors 来定义错误处理方案。 默认值 'strict' 表示在出现编码错误时引发 ValueError

buffering 的含义与内置 open() 函数中的相同。 默认值 -1 表示将使用默认的缓冲区大小。

codecs.EncodedFile(file, data_encoding, file_encoding=None, errors=’strict’)

返回一个 StreamRecoder 实例,它提供了 file 的透明转码包装版本。 当包装版本被关闭时原始文件也会被关闭。

写入已包装文件的数据会根据给定的 data_encoding 解码,然后以使用 file_encoding 的字节形式写入原始文件。 从原始文件读取的字节串将根据 file_encoding 解码,其结果将使用 data_encoding 进行编码。

如果 file_encoding 未给定,则默认为 data_encoding

可以指定 errors 来定义错误处理方案。 默认值 'strict' 表示在出现编码错误时引发 ValueError

codecs.iterencode(iterator, encoding, errors=’strict’, **kwargs)

使用增量式编码器通过迭代来编码由 iterator 所提供的输入。 此函数属于 generator。 errors 参数(以及任何其他关键字参数)会被传递给增量式编码器。

此函数要求编解码器接受 str 对象形式的文本进行编码。 因此它不支持字节到字节的编码器,例如 base64_codec

codecs.iterdecode(iterator, encoding, errors=’strict’, **kwargs)

使用增量式解码器通过迭代来解码由 iterator 所提供的输入。 此函数属于 generator。 errors 参数(以及任何其他关键字参数)会被传递给增量式解码器。

此函数要求编解码器接受 bytes 对象进行解码。 因此它不支持文本到文本的编码器,例如 rot_13,但是 rot_13 可以通过同样效果的 iterencode() 来使用。

本模块还提供了以下常量,适用于读取和写入依赖于平台的文件:

codecs.BOM
codecs.BOM_BE
codecs.BOM_LE
codecs.BOM_UTF8
codecs.BOM_UTF16
codecs.BOM_UTF16_BE
codecs.BOM_UTF16_LE
codecs.BOM_UTF32
codecs.BOM_UTF32_BE
codecs.BOM_UTF32_LE

这些常量定义了多种字节序列,即一些编码格式的 Unicode 字节顺序标记(BOM)。 它们在 UTF-16 和 UTF-32 数据流中被用以指明所使用的字节顺序,并在 UTF-8 中被用作 Unicode 签名。 BOM_UTF16BOM_UTF16_BEBOM_UTF16_LE,具体取决于平台的本机字节顺序,BOMBOM_UTF16 的别名, BOM_LEBOM_UTF16_LE 的别名,BOM_BEBOM_UTF16_BE 的别名。 其他序列则表示 UTF-8 和 UTF-32 编码格式中的 BOM。

编解码器基类

codecs 模块定义了一系列基类用来定义配合编解码器对象进行工作的接口,并且也可用作定制编解码器实现的基础。

每种编解码器必须定义四个接口以便用作 Python 中的编解码器:无状态编码器、无状态解码器、流读取器和流写入器。 流读取器和写入器通常会重用无状态编码器/解码器来实现文件协议。 编解码器作者还需要定义编解码器将如何处理编码和解码错误。

错误处理方案

为了简化和标准化错误处理,编解码器可以通过接受 errors 字符串参数来实现不同的错误处理方案。 所有标准的 Python 编解码器都定义并实现了以下字符串值:

含意
‘strict’ 引发 UnicodeError (或其子类);这是默认的方案。 在 strict_errors() 中实现。
‘ignore’ 忽略错误格式的数据并且不加进一步通知就继续执行。 在 ignore_errors() 中实现。

以下错误处理方案仅适用于 文本编码:

含意
‘replace’ 使用适当的替换标记进行替换;Python 内置编解码器将在解码时使用官方 U+FFFD 替换字符,而在编码时使用 ‘?’ 。 在 replace_errors() 中实现。
‘xmlcharrefreplace’ 使用适当的 XML 字符引用进行替换(仅在编码时)。 在 xmlcharrefreplace_errors() 中实现。
‘backslashreplace’ 使用带反斜杠的转义序列进行替换。 在 backslashreplace_errors() 中实现。
‘namereplace’ 使用 \N{…} 转义序列进行替换(仅在编码时)。 在 namereplace_errors() 中实现。
‘surrogateescape’ 在解码时,将字节替换为 U+DC80U+DCFF 范围内的单个代理代码。 当在编码数据时使用 ‘surrogateescape’ 错误处理方案时,此代理将被转换回相同的字节。 (请参阅 PEP 383 了解详情。)

此外,以下错误处理方案被专门用于指定的编解码器:

编解码器 含意
‘surrogatepass’ utf-8, utf-16, utf-32, utf-16-be, utf-16-le, utf-32-be, utf-32-le 允许编码和解码代理代码。 这些编解码器通常会将出现的代理代码视为错误。

3.1 新版功能: 'surrogateescape''surrogatepass' 错误处理方案。

在 3.4 版更改: 'surrogatepass' 错误处理方案现在适用于 utf-16* 和 utf-32* 编解码器。

3.5 新版功能: 'namereplace' 错误处理方案。

在 3.5 版更改: 'backslashreplace' 错误处理方案现在适用于解码和转换。

允许的值集合可以通过注册新命名的错误处理方案来扩展:

codecs.register_error(name, error_handler)

在名称 name 之下注册错误处理函数 error_handler*。 当 *name 被指定为错误形参时,error_handler 参数所指定的对象将在编码和解码期间发生错误的情况下被调用,

对于编码操作,将会调用 error_handler 并传入一个 UnicodeEncodeError 实例,其中包含有关错误位置的信息。 错误处理程序必须引发此异常或别的异常,或者也可以返回一个元组,其中包含输入的不可编码部分的替换对象,以及应当继续进行编码的位置。 替换对象可以为 strbytes 类型。 如果替换对象为字节串,编码器将简单地将其复制到输出缓冲区。 如果替换对象为字符串,编码器将对替换对象进行编码。 对原始输入的编码操作会在指定位置继续进行。 负的位置值将被视为相对于输入字符串的末尾。 如果结果位置超出范围则将引发 IndexError

解码和转换的做法很相似,不同之处在于将把 UnicodeDecodeErrorUnicodeTranslateError 传给处理程序,并且来自错误处理程序的替换对象将被直接放入输出。

之前注册的错误处理方案(包括标准错误处理方案)可通过名称进行查找:

codecs.lookup_error(name)

返回之前在名称 name 之下注册的错误处理方案。

在处理方案无法找到时将引发 LookupError

以下标准错误处理方案也可通过模块层级函数的方式来使用:

codecs.strict_errors(exception)

实现 'strict' 错误处理方案:每个编码或解码错误都会引发 UnicodeError

codecs.replace_errors(exception)

实现 'replace' 错误处理方案 (仅用于 文本编码):编码错误替换为 '?' (并由编解码器编码),解码错误替换为 '\ufffd' (Unicode 替换字符)。

codecs.ignore_errors(exception)

实现 'ignore' 错误处理方案:忽略错误格式的数据并且不加进一步通知就继续执行。

codecs.xmlcharrefreplace_errors(exception)

实现 'xmlcharrefreplace' 错误处理方案 (仅用于 文本编码 的编码过程):不可编码的字符将以适当的 XML 字符引用进行替换。

codecs.backslashreplace_errors(exception)

实现 'backslashreplace' 错误处理方案 (仅用于 文本编码):错误格式的数据将以带反斜杠的转义序列进行替换。

codecs.namereplace_errors(exception)

实现 'namereplace' 错误处理方案 (仅用于 文本编码 的编码过程):不可编码的字符将以 \N{...} 转义序列进行替换。

3.5 新版功能.

无状态的编码和解码

基本 Codec 类定义了这些方法,同时还定义了无状态编码器和解码器的函数接口:

Codec.encode(input[, errors])

编码 input 对象并返回一个元组 (输出对象, 消耗长度)。 例如,text encoding 会使用特定的字符集编码格式 (例如 cp1252iso-8859-1) 将字符串转换为字节串对象。

errors 参数定义了要应用的错误处理方案。 默认为 'strict' 处理方案。

此方法不一定会在 Codec 实例中保存状态。 可使用必须保存状态的 StreamWriter 作为编解码器以便高效地进行编码。

编码器必须能够处理零长度的输入并在此情况下返回输出对象类型的空对象。

Codec.decode(input[, errors])

解码 input 对象并返回一个元组 (输出对象, 消耗长度)。 例如,text encoding 的解码操作会使用特定的字符集编码格式将字节串对象转换为字符串对象。

对于文本编码格式和字节到字节编解码器,input 必须为一个字节串对象或提供了只读缓冲区接口的对象 — 例如,缓冲区对象和映射到内存的文件。

errors 参数定义了要应用的错误处理方案。 默认为 'strict' 处理方案。

此方法不一定会在 Codec 实例中保存状态。 可使用必须保存状态的 StreamReader 作为编解码器以便高效地进行解码。

解码器必须能够处理零长度的输入并在此情况下返回输出对象类型的空对象。

增量式的编码和解码

IncrementalEncoderIncrementalDecoder 类提供了增量式编码和解码的基本接口。 对输入的编码/解码不是通过对无状态编码器/解码器的一次调用,而是通过对增量式编码器/解码器的 encode()/decode() 方法的多次调用。 增量式编码器/解码器会在方法调用期间跟踪编码/解码过程。

调用 encode()/decode() 方法后的全部输出相当于将所有通过无状态编码器/解码器进行编码/解码的单个输入连接在一起所得到的输出。

IncrementalEncoder 对象

IncrementalEncoder 类用来对一个输入进行分步编码。 它定义了以下方法,每个增量式编码器都必须定义这些方法以便与 Python 编解码器注册表相兼容。

class codecs.IncrementalEncoder(errors=’strict’)

IncrementalEncoder 实例的构造器。

所有增量式编码器必须提供此构造器接口。 它们可以自由地添加额外的关键字参数,但只有在这里定义的参数才会被 Python 编解码器注册表所使用。

IncrementalEncoder 可以通过提供 errors 关键字参数来实现不同的错误处理方案。

errors 参数将被赋值给一个同名的属性。 通过对此属性赋值就可以在 IncrementalEncoder 对象的生命期内在不同的错误处理策略之间进行切换。

  • encode(object[, final])

    编码 object (会将编码器的当前状态纳入考虑) 并返回已编码的结果对象。 如果这是对 encode() 的最终调用则 final 必须为真值(默认为假值)。

  • reset()

    将编码器重置为初始状态。 输出将被丢弃:调用 .encode(object, final=True),在必要时传入一个空字节串或字符串,重置编码器并得到输出。

  • getstate()

    返回编码器的当前状态,该值必须为一个整数。 实现应当确保 0 是最常见的状态。 (比整数更复杂的状态表示可以通过编组/选择状态并将结果字符串的字节数据编码为整数来转换为一个整数值)。

  • setstate(state)

    将编码器的状态设为 state*。 *state 必须为 getstate() 所返回的一个编码器状态。

IncrementalDecoder 对象

IncrementalDecoder 类用来对一个输入进行分步解码。 它定义了以下方法,每个增量式解码器都必须定义这些方法以便与 Python 编解码器注册表相兼容。

class codecs.IncrementalDecoder(errors=’strict’)

IncrementalDecoder 实例的构造器。

所有增量式解码器必须提供此构造器接口。 它们可以自由地添加额外的关键字参数,但只有在这里定义的参数才会被 Python 编解码器注册表所使用。

IncrementalDecoder 可以通过提供 errors 关键字参数来实现不同的错误处理方案。

errors 参数将被赋值给一个同名的属性。 通过对此属性赋值就可以在 IncrementalDecoder 对象的生命期内在不同的错误处理策略之间进行切换。

  • decode(object[, final])

    解码 object (会将解码器的当前状态纳入考虑) 并返回已解码的结果对象。 如果这是对 decode() 的最终调用则 final 必须为真值(默认为假值)。 如果 final 为真值则解码器必须对输入进行完全解码并且必须 刷新所有缓冲区。 如果这无法做到(例如由于在输入结束时字节串序列不完整)则它必须像在无状态的情况下那样初始化错误处理(这可能引发一个异常)。

  • reset()

    将解码器重置为初始状态。

  • getstate()

    返回解码器的当前状态。 这必须为一个二元组,第一项必须是包含尚未解码的输入的缓冲区。 第二项必须为一个整数,可以表示附加状态信息。 (实现应当确保 0 是最常见的附加状态信息。) 如果此附加状态信息为 0 则必须可以将解码器设为没有已缓冲输入并且以 0 作为附加状态信息,以便将先前已缓冲的输入馈送到解码器使其返回到先前的状态而不产生任何输出。 (比整数更复杂的附加状态信息可以通过编组/选择状态信息并将结果字符串的字节数据编码为整数来转换为一个整数值。)

  • setstate(state)

    将解码器的状态设为 state*。 *state 必须为 getstate() 所返回的一个解码器状态。

流式的编码和解码

StreamWriterStreamReader 类提供了一些泛用工作接口,可被用来非常方便地实现新的编码格式子模块。

StreamWriter 对象

StreamWriter 类是 Codec 的子类,它定义了以下方法,每个流式写入器都必须定义这些方法以便与 Python 编解码器注册表相兼容。

class codecs.StreamWriter(stream, errors=’strict’)

StreamWriter 实例的构造器。

所有流式写入器必须提供此构造器接口。 它们可以自由地添加额外的关键字参数,但只有在这里定义的参数才会被 Python 编解码器注册表所使用。

stream 参数必须为一个基于特定编解码器打开用于写入文本或二进制数据的文件类对象。

StreamWriter 可以通过提供 errors 关键字参数来实现不同的错误处理方案。

errors 参数将被赋值给一个同名的属性。 通过对此属性赋值就可以在 StreamWriter 对象的生命期内在不同的错误处理策略之间进行切换。

  • write(object)

    将编码后的对象内容写入到流。

  • writelines(list)

    将拼接后的字符串列表写入到流(可能通过重用 write() 方法)。 标准的字节到字节编解码器不支持此方法。

  • reset()

    重置用于保持内部状态的编解码器缓冲区。

    调用此方法应当确保在干净的状态下放入输出数据,以允许直接添加新的干净数据而无须重新扫描整个流来恢复状态。

除了上述的方法,StreamWriter 还必须继承来自下层流的所有其他方法和属性。

StreamReader 对象

StreamReader 类是 Codec 的子类,它定义了以下方法,每个流式读取器都必须定义这些方法以便与 Python 编解码器注册表相兼容。

class codecs.StreamReader(stream, errors=’strict’)

StreamReader 实例的构造器。

所有流式读取器必须提供此构造器接口。 它们可以自由地添加额外的关键字参数,但只有在这里定义的参数才会被 Python 编解码器注册表所使用。

stream 参数必须为一个基于特定编解码器打开用于读取文本或二进制数据的文件类对象。

StreamReader 可以通过提供 errors 关键字参数来实现不同的错误处理方案。

errors 参数将被赋值给一个同名的属性。 通过对此属性赋值就可以在 StreamReader 对象的生命期内在不同的错误处理策略之间进行切换。

errors 参数所允许的值集合可以使用 register_error() 来扩展。

  • read([size[, chars[, firstline]]])

    解码来自流的数据并返回结果对象。

    chars 参数指明要返回的解码后码位或字节数量。 read() 方法绝不会返回超出请求数量的数据,但如果可用数量不足,它可能返回少于请求数量的数据。

    size 参数指明要读取并解码的已编码字节或码位的最大数量近似值。 解码器可以适当地修改此设置。 默认值 -1 表示尽可能多地读取并解码。 此形参的目的是防止一次性解码过于巨大的文件。

    firstline 旗标指明如果在后续行发生解码错误,则仅返回第一行就足够了。

    此方法应当使用“贪婪”读取策略,这意味着它应当在编码格式定义和给定大小所允许的情况下尽可能多地读取数据,例如,如果在流上存在可选的编码结束或状态标记,这些内容也应当被读取。

  • readline([size[, keepends]])

    从输入流读取一行并返回解码后的数据。

    如果给定了 size,则将其作为 size 参数传递给流的 read() 方法。

    如果 keepends 为假值,则行结束符将从返回的行中去除。

  • readlines([sizehint[, keepends]])

    从输入流读取所有行并将其作为一个行列表返回。

    行结束符会使用编解码器的 decode() 方法来实现,并且如果 keepends 为真值则会将其包含在列表条目中。

    如果给定了 sizehint*,则将其作为 *size 参数传递给流的 read() 方法。

  • reset()

    重置用于保持内部状态的编解码器缓冲区。

    请注意不应当对流进行重定位。 使用此方法的主要目的是为了能够从解码错误中恢复。

除了上述的方法,StreamReader 还必须继承来自下层流的所有其他方法和属性。

StreamReaderWriter 对象

StreamReaderWriter 是一个方便的类,允许对同时工作于读取和写入模式的流进行包装。

其设计使得开发者可以使用 lookup() 函数所返回的工厂函数来构造实例。

class codecs.StreamReaderWriter(stream, Reader, Writer, errors=’strict’)

创建一个 StreamReaderWriter 实例。 stream 必须为一个文件类对象。 ReaderWriter 必须为分别提供了 StreamReaderStreamWriter 接口的工厂函数或类。 错误处理通过与流式读取器和写入器所定义的相同方式来完成。

StreamReaderWriter 实例定义了 StreamReaderStreamWriter 类的组合接口。 它们还继承了来自下层流的所有其他方法和属性。

StreamRecoder 对象

StreamRecoder 将数据从一种编码格式转换为另一种,这对于处理不同编码环境的情况有时会很有用。

其设计使得开发者可以使用 lookup() 函数所返回的工厂函数来构造实例。

class codecs.StreamRecoder(stream, encode, decode, Reader, Writer, errors=’strict’)

创建一个实现了双向转换的 StreamRecoder 实例: encodedecode 工作于前端 — 对代码可见的数据调用 read()write(),而 ReaderWriter 工作于后端 — stream 中的数据。

你可以使用这些对象来进行透明转码,例如从 Latin-1 转为 UTF-8 以及反向转换。

stream 参数必须为一个文件类对象。

encodedecode 参数必须遵循 Codec 接口。 ReaderWriter 必须为分别提供了 StreamReaderStreamWriter 接口对象的工厂函数或类。

错误处理通过与流式读取器和写入器所定义的相同方式来完成。

StreamRecoder 实例定义了 StreamReaderStreamWriter 类的组合接口。 它们还继承了来自下层流的所有其他方法和属性。

编码格式与 Unicode

字符串在系统内部存储为 0x00x10FFFF 范围内的码位序列。 (请参阅 PEP 393 了解有关实现的详情。) 一旦字符串对象要在 CPU 和内存以外使用,字节的大小端顺序和字节数组的存储方式就成为一个关键问题。 如同使用其他编解码器一样,将字符串序列化为字节序列被称为 编码,而从字节序列重建字符串被称为 解码。 存在许多不同的文本序列化编解码器,它们被统称为 文本编码。

最简单的文本编码格式 (称为 'latin-1''iso-8859-1') 将码位 0—255 映射为字节值 0x00xff,这意味着包含 U+00FF 以上码位的字符串对象无法使用此编解码器进行编码。 这样做将引发 UnicodeEncodeError,其形式类似下面这样(不过详细的错误信息可能会有所不同): UnicodeEncodeError: 'latin-1' codec can't encode character '\u1234' in position 3: ordinal not in range(256)

还有另外一组编码格式(所谓的字符映射编码)会选择全部 Unicode 码位的不同子集并设定如何将这些码位映射为字节值 0x00xff。 要查看这是如何实现的,只需简单地打开相应源码例如 encodings/cp1252.py (这是一个主要在 Windows 上使用的编码格式)。 其中会有一个包含 256 个字符的字符串常量,指明每个字符所映射的字节值。

所有这些编码格式只能对 Unicode 所定义的 1114112 个码位中的 256 个进行编码。 一种能够存储每个 Unicode 码位的简单而直接的办法就是将每个码位存储为四个连续的字节。 存在两种不同的可能性:以大端序存储或以小端序存储。 这两种编码格式分别被称为 UTF-32-BEUTF-32-LE。 它们的缺点可以举例说明:如果你在一台小端序的机器上使用 UTF-32-BE 则你将必须在编码和解码时翻转字节。 UTF-32 避免了这个问题:字节的排列将总是使用自然顺序。 当这些字节被具有不同字节顺序的 CPU 读取时,则必须进行字节翻转。 为了能够检测 UTF-16UTF-32 字节序列的大小端序,可以使用所谓的 BOM (“字节顺序标记”)。 这对应于 Unicode 字符 U+FEFF。 此字符可添加到每个 UTF-16UTF-32 字节序列的开头。 此字符的字节翻转版本 (0xFFFE) 是一个不可出现于 Unicode 文本中的非法字符。 因此当发现一个 UTF-16UTF-32 字节序列的首个字符是 U+FFFE 时,就必须在解码时进行字节翻转。 不幸的是字符 U+FEFF 还有第二个含义 ZERO WIDTH NO-BREAK SPACE: 即宽度为零并且不允许用来拆分单词的字符。 它可以被用来为语言分析算法提供提示。 在 Unicode 4.0 中用 U+FEFF 表示 ZERO WIDTH NO-BREAK SPACE 已被弃用(改用 U+2060 (WORD JOINER) 负责此任务)。 然而 Unicode 软件仍然必须能够处理 U+FEFF 的两个含义:作为 BOM 它被用来确定已编码字节的存储布局,并在字节序列被解码为字符串后将其去除;作为 ZERO WIDTH NO-BREAK SPACE 它是一个普通字符,将像其他字符一样被解码。

There’s another encoding that is able to encode the full range of Unicode characters: UTF-8. UTF-8 is an 8-bit encoding, which means there are no issues with byte order in UTF-8. Each byte in a UTF-8 byte sequence consists of two parts: marker bits (the most significant bits) and payload bits. The marker bits are a sequence of zero to four 1 bits followed by a 0 bit. Unicode characters are encoded like this (with x being payload bits, which when concatenated give the Unicode character):

范围 编码
U-00000000U-0000007F 0xxxxxxx
U-00000080U-000007FF 110xxxxx 10xxxxxx
U-00000800U-0000FFFF 1110xxxx 10xxxxxx 10xxxxxx
U-00010000U-0010FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Unicode 字符最不重要的一个位就是最右侧的二进制位 x。

由于 UTF-8 是一种 8 位编码格式,因此 BOM 是不必要的,并且已编码字符串中的任何 U+FEFF 字符(即使是作为第一个字符)都会被视为是 ZERO WIDTH NO-BREAK SPACE

在没有外部信息的情况下,就不可能毫无疑义地确定一个字符串使用了何种编码格式。 每种字符映射编码格式都可以解码任意的随机字节序列。 然而对 UTF-8 来说这却是不可能的,因为 UTF-8 字节序列具有不允许任意字节序列的特别结构。 为了提升 UTF-8 编码检测的可靠性,Microsoft 发明了一种 UTF-8 变体形式 (Python 2.5 称之为 "utf-8-sig") 专门用于其 Notepad 程序:在任何 Unicode 字符在被写入文件之前,会先写入一个 UTF-8 编码的 BOM (它看起来是这样一个字节序列: 0xef, 0xbb, 0xbf)。 由于任何字符映射编码后的文件都不大可能以这些字节值开头(例如它们会映射为

LATIN SMALL LETTER I WITH DIAERESIS

RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK

INVERTED QUESTION MARK

对于 iso-8859-1 编码格式来说),这提升了根据字节序列来正确猜测 utf-8-sig 编码格式的成功率。 所以在这里 BOM 的作用并不是帮助确定生成字节序列所使用的字节顺序,而是作为帮助猜测编码格式的记号。 在进行编码时 utf-8-sig 编解码器将把 0xef, 0xbb, 0xbf 作为头三个字节写入文件。 在进行解码时 utf-8-sig 将跳过这三个字节,如果它们作为文件的头三个字节出现的话。 在 UTF-8 中并不推荐使用 BOM,通常应当避免它们的出现。

标准编码

Python 自带了许多内置的编解码器,它们的实现或者是通过 C 函数,或者是通过映射表。 以下表格是按名称排序的编解码器列表,并提供了一些常见别名以及编码格式通常针对的语言。 别名和语言列表都不是详尽无遗的。 请注意仅有大小写区别或使用连字符替代下划线的拼写形式也都是有效的别名;因此,'utf-8''utf_8' 编解码器的有效别名。

CPython implementation detail: 有些常见编码格式可以绕过编解码器查找机制来提升性能。 这些优化机会对于 CPython 来说仅能通过一组有限的别名(大小写不敏感)来识别:utf-8, utf8, latin-1, latin1, iso-8859-1, iso8859-1, mbcs (Windows 专属), ascii, us-ascii, utf-16, utf16, utf-32, utf32, 也包括使用下划线替代连字符的的形式。 使用这些编码格式的其他别名可能会导致更慢的执行速度。

在 3.6 版更改: 可识别针对 us-ascii 的优化机会。

许多字符集都支持相同的语言。 它们在个别字符(例如是否支持 EURO SIGN 等)以及给字符所分配的码位方面存在差异。 特别是对于欧洲语言来说,通常存在以下几种变体:

  • 某个 ISO 8859 编码集
  • 某个 Microsoft Windows 编码页,通常是派生自某个 8859 编码集,但会用附加的图形字符来替换控制字符。
  • 某个 IBM EBCDIC 编码页
  • 某个 IBM PC 编码页,通常会兼容 ASCII
编码 别名 语言
ascii 646, us-ascii 英语
big5 big5-tw, csbig5 繁体中文
big5hkscs big5-hkscs, hkscs 繁体中文
cp037 IBM037, IBM039 英语
cp273 273, IBM273, csIBM273 德语3.4 新版功能.
cp424 EBCDIC-CP-HE, IBM424 希伯来语
cp437 437, IBM437 英语
cp500 EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500 西欧
cp720 阿拉伯语
cp737 希腊语
cp775 IBM775 波罗的海语言
cp850 850, IBM850 西欧
cp852 852, IBM852 中欧和东欧
cp855 855, IBM855 保加利亚语,白俄罗斯语,马其顿语,俄语,塞尔维亚语
cp856 希伯来语
cp857 857, IBM857 土耳其语
cp858 858, IBM858 西欧
cp860 860, IBM860 葡萄牙语
cp861 861, CP-IS, IBM861 冰岛语
cp862 862, IBM862 希伯来语
cp863 863, IBM863 加拿大语
cp864 IBM864 阿拉伯语
cp865 865, IBM865 丹麦语/挪威语
cp866 866, IBM866 俄语
cp869 869, CP-GR, IBM869 希腊语
cp874 泰语
cp875 希腊语
cp932 932, ms932, mskanji, ms-kanji 日语
cp949 949, ms949, uhc 韩语
cp950 950, ms950 繁体中文
cp1006 乌尔都语
cp1026 ibm1026 土耳其语
cp1125 1125, ibm1125, cp866u, ruscii 乌克兰语3.4 新版功能.
cp1140 ibm1140 西欧
cp1250 windows-1250 中欧和东欧
cp1251 windows-1251 保加利亚语,白俄罗斯语,马其顿语,俄语,塞尔维亚语
cp1252 windows-1252 西欧
cp1253 windows-1253 希腊语
cp1254 windows-1254 土耳其语
cp1255 windows-1255 希伯来语
cp1256 windows-1256 阿拉伯语
cp1257 windows-1257 波罗的海语言
cp1258 windows-1258 越南语
euc_jp eucjp, ujis, u-jis 日语
euc_jis_2004 jisx0213, eucjis2004 日语
euc_jisx0213 eucjisx0213 日语
euc_kr euckr, korean, ksc5601, ks_c-5601, ks_c-5601-1987, ksx1001, ks_x-1001 韩语
gb2312 chinese, csiso58gb231280, euc-cn, euccn, eucgb2312-cn, gb2312-1980, gb2312-80, iso-ir-58 简体中文
gbk 936, cp936, ms936 统一汉语
gb18030 gb18030-2000 统一汉语
hz hzgb, hz-gb, hz-gb-2312 简体中文
iso2022_jp csiso2022jp, iso2022jp, iso-2022-jp 日语
iso2022_jp_1 iso2022jp-1, iso-2022-jp-1 日语
iso2022_jp_2 iso2022jp-2, iso-2022-jp-2 日语,韩语,简体中文,西欧,希腊语
iso2022_jp_2004 iso2022jp-2004, iso-2022-jp-2004 日语
iso2022_jp_3 iso2022jp-3, iso-2022-jp-3 日语
iso2022_jp_ext iso2022jp-ext, iso-2022-jp-ext 日语
iso2022_kr csiso2022kr, iso2022kr, iso-2022-kr 韩语
latin_1 iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1 西欧
iso8859_2 iso-8859-2, latin2, L2 中欧和东欧
iso8859_3 iso-8859-3, latin3, L3 世界语,马耳他语
iso8859_4 iso-8859-4, latin4, L4 波罗的海语言
iso8859_5 iso-8859-5, cyrillic 保加利亚语,白俄罗斯语,马其顿语,俄语,塞尔维亚语
iso8859_6 iso-8859-6, arabic 阿拉伯语
iso8859_7 iso-8859-7, greek, greek8 希腊语
iso8859_8 iso-8859-8, hebrew 希伯来语
iso8859_9 iso-8859-9, latin5, L5 土耳其语
iso8859_10 iso-8859-10, latin6, L6 北欧语言
iso8859_11 iso-8859-11, thai 泰语
iso8859_13 iso-8859-13, latin7, L7 波罗的海语言
iso8859_14 iso-8859-14, latin8, L8 凯尔特语
iso8859_15 iso-8859-15, latin9, L9 西欧
iso8859_16 iso-8859-16, latin10, L10 东南欧
johab cp1361, ms1361 韩语
koi8_r 俄语
koi8_t 塔吉克3.5 新版功能.
koi8_u 乌克兰语
kz1048 kz_1048, strk1048_2002, rk1048 哈萨克语3.5 新版功能.
mac_cyrillic maccyrillic 保加利亚语,白俄罗斯语,马其顿语,俄语,塞尔维亚语
mac_greek macgreek 希腊语
mac_iceland maciceland 冰岛语
mac_latin2 maclatin2, maccentraleurope, mac_centeuro 中欧和东欧
mac_roman macroman, macintosh 西欧
mac_turkish macturkish 土耳其语
ptcp154 csptcp154, pt154, cp154, cyrillic-asian 哈萨克语
shift_jis csshiftjis, shiftjis, sjis, s_jis 日语
shift_jis_2004 shiftjis2004, sjis_2004, sjis2004 日语
shift_jisx0213 shiftjisx0213, sjisx0213, s_jisx0213 日语
utf_32 U32, utf32 所有语言
utf_32_be UTF-32BE 所有语言
utf_32_le UTF-32LE 所有语言
utf_16 U16, utf16 所有语言
utf_16_be UTF-16BE 所有语言
utf_16_le UTF-16LE 所有语言
utf_7 U7, unicode-1-1-utf-7 所有语言
utf_8 U8, UTF, utf8, cp65001 所有语言
utf_8_sig 所有语言

在 3.4 版更改: utf-16* 和 utf-32* 编码器将不再允许编码代理码位 (U+D800U+DFFF)。 utf-32* 解码器将不再解码与代理码位相对应的字节序列。

在 3.8 版更改: cp65001 现在是 utf_8 的一个别名。

Python 专属的编码格式

有一些预定义编解码器是 Python 专属的,因此它们在 Python 之外没有意义。 这些编解码器按其所预期的输入和输出类型在下表中列出(请注意虽然文本编码是编解码器最常见的使用场景,但下层的编解码器架构支持任意数据转换而不仅是文本编码)。 对于非对称编解码器,该列描述的含义是编码方向。

文字编码

以下编解码器提供了 strbytes 的编码和 bytes-like object 到 str 的解码,类似于 Unicode 文本编码。

编码 别名 含意
idna 实现 RFC 3490。仅支持 errors=’strict’
mbcs ansi, dbcs Windows 专属:根据 ANSI 代码页(CP_ACP)对操作数进行编码。
oem Windows 专属:根据 OEM 代码页(CP_OEMCP)对操作数进行编码。3.6 新版功能.
palmos PalmOS 3.5 的编码格式
punycode 实现 RFC 3492。 不支持有状态编解码器。
raw_unicode_escape Latin-1 编码格式附带对其他码位以 \uXXXX\UXXXXXXXX 进行编码。 现有反斜杠不会以任何方式转义。 它被用于 Python 的 pickle 协议。
undefined 所有转换都将引发异常,甚至对空字符串也不例外。 错误处理方案会被忽略。
unicode_escape 适合用于以 ASCII 编码的 Python 源代码中的 Unicode 字面值内容的编码格式,但引号不会被转义。 对 Latin-1 源代码进行解码。 请注意 Python 源代码实际上默认使用 UTF-8。

在 3.8 版更改: “unicode_internal” 编解码器已被移除。

二进制转换

以下编解码器提供了二进制转换: bytes-like object 到 bytes 的映射。 它们不被 bytes.decode() 所支持(该方法只生成 str 类型的输出)。

编码 别名 含意 编码器/解码器
base64_codec base64, base_64 将操作数转换为多行 MIME base64 (结果总是包含一个末尾的 ‘\n’)在 3.4 版更改: 接受任意 bytes-like object 作为输入用于编码和解码 base64.encodebytes() / base64.decodebytes()
bz2_codec bz2 使用bz2压缩操作数 bz2.compress() / bz2.decompress()
hex_codec hex 将操作数转换为十六进制表示,每个字节有两位数 binascii.b2a_hex() / binascii.a2b_hex()
quopri_codec quopri, quotedprintable, quoted_printable 将操作数转换为 MIME 带引号的可打印数据 quopri.encode()quotetabs=True / quopri.decode()
uu_codec uu 使用uuencode转换操作数 uu.encode() / uu.decode()
zlib_codec zip, zlib 使用gzip压缩操作数 zlib.compress() / zlib.decompress()

除了 字节类对象,'base64_codec' 也接受仅包含 ASCII 的 str 实例用于解码

3.2 新版功能: 恢复二进制转换。

在 3.4 版更改: 恢复二进制转换的别名。

文字转换

以下编解码器提供了文本转换: strstr 的映射。 它不被 str.encode() 所支持(该方法只生成 bytes 类型的输出)。

编码 别名 含意
rot_13 rot13 返回操作数的凯撒密码加密结果

3.2 新版功能: 恢复 rot_13 文本转换。

在 3.4 版更改: 恢复 rot13 别名。

encodings.idna —- 应用程序中的国际化域名

此模块实现了 RFC 3490 (应用程序中的国际化域名) 和 RFC 3492 (Nameprep: 用于国际化域名 (IDN) 的 Stringprep 配置文件)。 它是在 punycode 编码格式和 stringprep 的基础上构建的。

如果你需要来自 RFC 5891RFC 5895 的 IDNA 2008 标准,请使用第三方 idna 模块 https://pypi.org/project/idna/

这些 RFC 共同定义了一个在域名中支持非 ASCII 字符的协议。 一个包含非 ASCII 字符的域名 (例如 www.Alliancefrançaise.nu) 会被转换为兼容 ASCII 的编码格式 (简称 ACE,例如 www.xn--alliancefranaise-npb.nu)。 随后此域名的 ACE 形式可以用于所有由于特定协议而不允许使用任意字符的场合,例如 DNS 查询,HTTP Host 字段等等。 此转换是在应用中进行的;如有可能将对用户可见:应用应当透明地将 Unicode 域名标签转换为线上的 IDNA,并在 ACE 标签被呈现给用户之前将其转换回 Unicode。

Python 以多种方式支持这种转换: idna 编解码器执行 Unicode 和 ACE 之间的转换,基于在 section 3.1 of RFC 3490 中定义的分隔字符将输入字符串拆分为标签,再根据需要将每个标签转换为 ACE,相反地又会基于 . 分隔符将输入字节串拆分为标签,再将找到的任何 ACE 标签转换为 Unicode。 此外,socket 模块可透明地将 Unicode 主机名转换为 ACE,以便应用在将它们传给 socket 模块时无须自行转换主机名。 除此之外,许多包含以主机名作为函数参数的模块例如 http.clientftplib 都接受 Unicode 主机名(并且 http.client 也会在 Host 字段中透明地发送 IDNA 主机名,如果它需要发送该字段的话)。

当从线路接收主机名时(例如反向名称查找),到 Unicode 的转换不会自动被执行:希望向用户提供此种主机名的应用应当将它们解码为 Unicode。

encodings.idna 模块还实现了 nameprep 过程,该过程会对主机名执行特定的规范化操作,以实现国际域名的大小写不敏感特性与合并相似的字符。 如果有需要可以直接使用 nameprep 函数。

encodings.idna.nameprep(label)

返回 label 经过名称处理操作的版本。 该实现目前基于查询字符串,因此 AllowUnassigned 为真值。

encodings.idna.ToASCII(label)

将标签转换为 ASCII,规则定义见 RFC 3490UseSTD3ASCIIRules 预设为假值。

encodings.idna.ToUnicode(label)

将标签转换为 Unicode,规则定义见 RFC 3490

encodings.mbcs —- Windows ANSI代码页

此模块实现ANSI代码页(CP_ACP)。

Availability: 仅Windows可用

在 3.3 版更改: 支持任何错误处理

在 3.2 版更改: 在 3.2 版之前, errors 参数会被忽略;总是会使用 'replace' 进行编码,并使用 'ignore' 进行解码。

encodings.utf_8_sig —- 带BOM签名的UTF-8编解码器

此模块实现了 UTF-8 编解码器的一个变种:在编码时将把 UTF-8 已编码 BOM 添加到 UTF-8 编码字节数据的开头。 对于有状态编码器此操作只执行一次(当首次写入字节流时)。 在解码时将跳过数据开头作为可选项的 UTF-8 已编码 BOM。

数据类型

Python也提供一些内置数据类型,特别是,dictlistsetfrozenset、以及 tuplestr 这个类是用来存储Unicode字符串的,而 bytesbytearray 这两个类是用来存储二进制数据的。

本章包含以下模块的文档:

  • datetime —- 基本日期和时间类型
    • 感知型对象和简单型对象
    • 常量
    • 有效的类型
      • 通用的特征属性
      • 确定一个对象是感知型还是简单型
    • timedelta 类对象
      • class:timedelta 用法示例
    • date 对象
      • class:date 用法示例
    • datetime 对象
      • 用法示例: datetime
    • time 对象
      • 用法示例: time
    • tzinfo 对象
    • timezone 对象
    • strftime()strptime() 的行为
      • strftime()strptime() Format Codes
      • 技术细节
  • zoneinfo —- IANA 时区支持
    • 使用 ZoneInfo
    • 数据源
      • 配置数据源
        • 编译时配置
        • 环境配置
        • 运行时配置
    • ZoneInfo
      • 字符串表示
      • 封存序列化
    • 函数
    • 全局变量
    • 异常与警告
  • calendar —- 日历相关函数
  • collections —- 容器数据类型
    • ChainMap 对象
      • ChainMap 例子和方法
    • Counter 对象
    • deque 对象
      • deque 用法
    • defaultdict 对象
      • defaultdict 例子
    • namedtuple() 命名元组的工厂函数
    • OrderedDict 对象
      • OrderedDict 例子和用法
    • UserDict 对象
    • UserList 对象
    • UserString 对象
  • collections.abc —- 容器的抽象基类
    • 容器抽象基类
    • Collections Abstract Base Classes — Detailed Descriptions
    • Examples and Recipes
  • heapq —- 堆队列算法
    • 基本示例
    • 优先队列实现说明
    • 理论
  • bisect —- 数组二分查找算法
    • 性能说明
    • 搜索有序列表
    • 例子
  • array —- 高效的数值数组
  • weakref —- 弱引用
    • 弱引用对象
    • 示例
    • 终结器对象
    • 比较终结器与 __del__() 方法
  • types —- 动态类型创建和内置类型名称
    • 动态类型创建
    • 标准解释器类型
    • 附加工具类和函数
    • 协程工具函数
  • copy —- 浅层 (shallow) 和深层 (deep) 复制操作
  • pprint —- 数据美化输出
    • PrettyPrinter 对象
    • 示例
  • reprlib —- 另一种 repr() 实现
    • Repr 对象
    • 子类化 Repr 对象
  • enum —- 对枚举的支持
    • 模块内容
    • 创建 Enum
    • 枚举成员及其属性的编程访问
    • 重复的枚举成员和值
    • 确保唯一枚举值
    • 使用自动设定的值
    • 迭代
    • 比较运算
    • 允许的枚举成员和属性
    • 受限的 Enum 子类化
    • 封存
    • 功能性 API
    • 派生的枚举
      • IntEnum
      • IntFlag
      • 旗标
      • 其他事项
    • 何时使用 __new__()__init__()
    • 有趣的示例
      • 省略值
        • 使用 auto
        • 使用 object
        • 使用描述性字符串
        • 使用自定义的 __new__()
      • OrderedEnum
      • DuplicateFreeEnum
      • Planet
      • TimePeriod
    • 各种枚举有何区别?
      • 枚举类
      • 枚举成员(即实例)
      • 细节要点
        • 支持的 __dunder__ 名称
        • 支持的 _sunder_ 名称
        • _Private__names
        • Enum 成员类型
        • Enum 类和成员的布尔值
        • 带有方法的 Enum
        • 组合 Flag 的成员
  • graphlib —- 操作类似图的结构的功能
    • 异常

datetime —- 基本日期和时间类型

源代码:Lib/datetime.py


datetime 模块提供用于处理日期和时间的类。

在支持日期时间数学运算的同时,实现的关注点更着重于如何能够更有效地解析其属性用于格式化输出和数据操作。

感知型对象和简单型对象

日期和时间对象可以根据它们是否包含时区信息而分为“感知型”和“简单型”两类。

充分掌握应用性算法和政治性时间调整信息例如时区和夏令时的情况下,一个 感知型 对象就能相对于其他感知型对象来精确定位自身时间点。 感知型对象是用来表示一个没有解释空间的固定时间点。

简单型 对象没有包含足够多的信息来无歧义地相对于其他 date/time 对象来定位自身时间点。 不论一个简单型对象所代表的是世界标准时间(UTC)、当地时间还是某个其他时区的时间完全取决于具体程序,就像一个特定数字所代表的是米、英里还是质量完全取决于具体程序一样。 简单型对象更易于理解和使用,代价则是忽略了某些现实性考量。

对于要求感知型对象的应用,datetimetime 对象具有一个可选的时区信息属性 tzinfo,它可被设为抽象类 tzinfo 的子类的一个实例。 这些 tzinfo 对象会捕获与 UTC 时间的差值、时区名称以及夏令时是否生效等信息。

datetime 模块只提供了一个具体的 tzinfo 类,即 timezone 类。 timezone 类可以表示具有相对于 UTC 的固定时差的简单时区,例如 UTC 本身或北美的 EST 和 EDT 时区等。 支持时间的详细程度取决于具体的应用。 世界各地的时间调整规则往往是政治性多于合理性,经常会发生变化,除了 UTC 之外并没有一个能适合所有应用的标准。

常量

The datetime module exports the following constants:

datetime.MINYEAR

date 或者 datetime 对象允许的最小年份。 常量 MINYEAR1

datetime.MAXYEAR

datedatetime 对象允许最大的年份。常量 MAXYEAR9999

有效的类型

classdatetime.date

一个理想化的简单型日期,它假设当今的公历在过去和未来永远有效。 属性: year, month, and day

classdatetime.time

一个独立于任何特定日期的理想化时间,它假设每一天都恰好等于 246060 秒。 (这里没有“闰秒”的概念。) 包含属性: hour, minute, second, microsecondtzinfo

classdatetime.datetime

日期和时间的结合。属性:year, month, day, hour, minute, second, microsecond, and tzinfo.

classdatetime.timedelta

表示两个 date 对象或 time 对象,或者 datetime 对象之间的时间间隔,精确到微秒。

classdatetime.tzinfo

一个描述时区信息对象的抽象基类。 用来给 datetimetime 类提供自定义的时间调整概念(例如处理时区和/或夏令时)。

classdatetime.timezone

一个实现了 tzinfo 抽象基类的子类,用于表示相对于 世界标准时间(UTC)的偏移量。

3.2 新版功能.

这些类型的对象都是不可变的。

子类关系

object
    timedelta
    tzinfo
        timezone
    time
    date
        datetime

通用的特征属性

date, datetime, timetimezone 类型共享这些通用特性:

  • 这些类型的对象都是不可变的。
  • 这些类型的对象是可哈希的,这意味着它们可被作为字典的键。
  • 这些类型的对象支持通过 pickle 模块进行高效的封存。

确定一个对象是感知型还是简单型

date 类型的对象都是简单型的。

timedatetime 类型的对象可以是感知型或者简单型。

一个 datetime 对象 d 在以下条件同时成立时将是感知型的:

  1. d.tzinfo 不为 None
  2. d.tzinfo.utcoffset(d) 不返回 None

在其他情况下,d 将是简单型的。

一个 time 对象 t 在以下条件同时成立时将是感知型的:

  1. t.tzinfo 不为 None
  2. t.tzinfo.utcoffset(None) 不返回 None

在其他情况下,t 将是简单型的。

感知型和简单型之间的区别不适用于 timedelta 对象。

timedelta 类对象

timedelta 对象表示两个 date 或者 time 的时间间隔。

classdatetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

所有参数都是可选的并且默认为 0。 这些参数可以是整数或者浮点数,也可以是正数或者负数。

只有 days, secondsmicroseconds 会存储在内部。 参数单位的换算规则如下:

  • 1毫秒会转换成1000微秒。
  • 1分钟会转换成60秒。
  • 1小时会转换成3600秒。
  • 1星期会转换成7天。

日期、秒、微秒都是标准化的,所以它们的表达方式也是唯一的,例:

  • 0 <= microseconds < 1000000
  • 0 <= seconds < 3600*24 (一天的秒数)
  • -999999999 <= days <= 999999999

下面的例子演示了如何对 days, secondsmicroseconds 以外的任意参数执行“合并”操作并标准化为以上三个结果属性:

>>>from datetime import timedelta
>>> delta = timedelta(
...     days=50,
...     seconds=27,
...     microseconds=10,
...     milliseconds=29000,
...     minutes=5,
...     hours=8,
...     weeks=2
...)
>>># Only days, seconds, and microseconds remain
>>> delta
datetime.timedelta(days=64, seconds=29156, microseconds=10)

在有任何参数为浮点型并且 microseconds 值为小数的情况下,从所有参数中余下的微秒数将被合并,并使用四舍五入偶不入奇的规则将总计值舍入到最接近的整数微秒值。 如果没有任何参数为浮点型的情况下,则转换和标准化过程将是完全精确的(不会丢失信息)。

如果标准化后的 days 数值超过了指定范围,将会抛出 OverflowError 异常。

请注意对负数值进行标准化的结果可能会令人感到惊讶。 例如:

>>>from datetime import timedelta
>>> d = timedelta(microseconds=-1)
>>>(d.days, d.seconds, d.microseconds)
(-1,86399,999999)

类属性:

timedelta.min

The most negative timedelta object, timedelta(-999999999).

timedelta.max

The most positive timedelta object, timedelta(days=999999999, hours=23, minutes=59, seconds=59, microseconds=999999).

timedelta.resolution

两个不相等的 timedelta 类对象最小的间隔为 timedelta(microseconds=1)

需要注意的是,因为标准化的缘故,timedelta.max > -timedelta.min-timedelta.max 不可以表示一个 timedelta 类对象。

实例属性(只读):

属性
days -999999999 至 999999999 ,含999999999
seconds 0 至 86399,包含86399
microseconds 0 至 999999,包含999999

支持的运算:

运算 结果:
t1 = t2 + t3 t2t3 的和。 运算后 t1-t2 == t3 and t1-t3 == t2 必为真值。(1)
t1 = t2 - t3 t2t3 的差。 运算后 t1 == t2 - t3 and t2 == t1 + t3 必为真值。 (1)(6)
t1 = t2 *i or t1 = i* t2 乘以一个整数。运算后假如 i != 0t1 // i == t2 必为真值。
In general, t1 i == *t1** (i-1) + *t1 is true. (1)
t1 = t2 *f or t1 = f* t2 乘以一个浮点数,结果会被舍入到 timedelta 最接近的整数倍。 精度使用四舍五偶入奇不入规则。
f = t2 / t3 总时间 t2 除以间隔单位 t3 (3)。 返回一个 float 对象。
t1 = t2 / f or t1 = t2 / i 除以一个浮点数或整数。 结果会被舍入到 timedelta 最接近的整数倍。 精度使用四舍五偶入奇不入规则。
t1 = t2 // i or t1 = t2 // t3 计算底数,其余部分(如果有)将被丢弃。在第二种情况下,将返回整数。 (3)
t1 = t2 % t3 余数为一个 timedelta 对象。(3)
q, r = divmod(t1, t2) 通过 : q = t1 // t2 (3) and r = t1 % t2 计算出商和余数。q是一个整数,r是一个 timedelta 对象。
+t1 返回一个相同数值的 timedelta 对象。
-t1 等价于 timedelta(-t1.days, -t1.seconds, -t1.microseconds), 和 t1 -1. (1)(4)
abs(t) t.days >= 0``时等于 +\ t*, 当 ``t.days < 0 时 -t 。 (2)
str(t) 返回一个形如 [D day[s], ][H]H:MM:SS[.UUUUUU] 的字符串,当 t 为负数的时候, D 也为负数。 (5)
repr(t) 返回一个 timedelta 对象的字符串表示形式,作为附带正规属性值的构造器调用。

注释:

  1. 结果正确,但可能会溢出。

  2. 结果正确,不会溢出。

  3. 除以0将会抛出异常 ZeroDivisionError

  4. -timedelta.max 不是一个 timedelta 类对象。

  5. timedelta 对象的字符串表示形式类似于其内部表示形式被规范化。对于负时间增量,这会导致一些不寻常的结果。例如:

    >>> timedelta(hours=-5)
    datetime.timedelta(days=-1, seconds=68400)
    >>>print(_)
    -1 day,19:00:00
  6. 表达式 t2 - t3 通常与 t2 + (-t3) 是等价的,除非 t3 等于 timedelta.max; 在这种情况下前者会返回结果,而后者则会溢出。

除了上面列举的操作以外,timedelta 对象还支持与 datedatetime 对象进行特定的相加和相减运算(见下文)。

在 3.2 版更改: 现在已支持 timedelta 对象与另一个 timedelta 对象相整除或相除,包括求余运算和 divmod() 函数。 现在也支持 timedelta 对象加上或乘以一个 float 对象。

支持 timedelta 对象之间进行比较,但其中有一些注意事项。

==!= 比较 总是 返回一个 bool 对象,无论被比较的对象是什么类型:

>>>from datetime import timedelta
>>> delta1 = timedelta(seconds=57)
>>> delta2 = timedelta(hours=25, seconds=2)
>>> delta2 != delta1
True
>>> delta2 ==5
False

对于所有其他比较 (例如 <>),当一个 timedelta 对象与其他类型的对象比较时,将引发 TypeError:

>>> delta2 > delta1
True
>>> delta2 >5
Traceback(most recent call last):
File"<stdin>", line 1,in<module>
TypeError:'>'not supported between instances of 'datetime.timedelta'and'int'

在布尔运算中,timedelta 对象当且仅当其不等于 timedelta(0) 时则会被视为真值。

实例方法:

timedelta.total_seconds()

返回时间间隔包含了多少秒。造价于 td / timedelta(seconds=1)。对于其它单位可以直接使用除法的形式 (例如 td / timedelta(microseconds=1))。

需要注意的是,时间间隔较大时,这个方法的结果中的微秒将会失真(大多数平台上大于270年视为一个较大的时间间隔)。

3.2 新版功能.

class:timedelta 用法示例

一个标准化的附加示例:

>>># Components of another_year add up to exactly 365 days
>>>from datetime import timedelta
>>> year = timedelta(days=365)
>>> another_year = timedelta(weeks=40, days=84, hours=23,
...                          minutes=50, seconds=600)
>>> year == another_year
True
>>> year.total_seconds()
31536000.0

timedelta 算术运算的示例:

>>>from datetime import timedelta
>>> year = timedelta(days=365)
>>> ten_years =10* year
>>> ten_years
datetime.timedelta(days=3650)
>>> ten_years.days // 365
10
>>> nine_years = ten_years - year
>>> nine_years
datetime.timedelta(days=3285)
>>> three_years = nine_years // 3
>>> three_years, three_years.days // 365
(datetime.timedelta(days=1095),3)

date 对象

date 对象代表一个理想化历法中的日期(年、月和日),即当今的格列高利历向前后两个方向无限延伸。

公元 1 年 1 月 1日是第 1 日,公元 1 年 1 月 2 日是第 2 日,依此类推。

classdatetime.date(year, month, day)

所有参数都是必要的。 参数必须是在下面范围内的整数:

  • MINYEAR <= year <= MAXYEAR
  • 1 <= month <= 12
  • 1 <= 日期 <= 给定年月对应的天数

如果参数不在这些范围内,则抛出 ValueError 异常。

其它构造器,所有的类方法:

classmethoddate.today()

返回当前的本地日期。

这等价于 date.fromtimestamp(time.time())

classmethoddate.fromtimestamp(timestamp)

返回对应于 POSIX 时间戳的当地时间,例如 time.time() 返回的就是时间戳。

这可能引发 OverflowError,如果时间戳数值超出所在平台 C localtime() 函数的支持范围的话,并且会在 localtime() 出错时引发 OSError。 通常该数值会被限制在 1970 年至 2038 年之间。 请注意在时间戳概念包含闰秒的非 POSIX 系统上,闰秒会被 fromtimestamp() 所忽略。

在 3.3 版更改: 引发 OverflowError 而不是 ValueError,如果时间戳数值超出所在平台 C localtime() 函数的支持范围的话,并会在 localtime() 出错时引发 OSError 而不是 ValueError

classmethoddate.fromordinal(ordinal)

返回对应于预期格列高利历序号的日期,其中公元 1 年 1 月 1 日的序号为 1。

除非 1 <= ordinal <= date.max.toordinal() 否则会引发 ValueError。对于任意日期 ddate.fromordinal(d.toordinal()) == d

classmethoddate.fromisoformat(date_string)

返回一个对应于以 YYYY-MM-DD 格式给出的 date_stringdate 对象:

>>>from datetime import date
>>> date.fromisoformat('2019-12-04')
datetime.date(2019,12,4)

这是 date.isoformat() 的逆操作。 它只支持 YYYY-MM-DD 格式。

3.7 新版功能.

classmethoddate.fromisocalendar(year, week, day)

返回指定 year, week 和 day 所对应 ISO 历法日期的 date。 这是函数 date.isocalendar() 的逆操作。

3.8 新版功能.

类属性:

date.min

最小的日期 date(MINYEAR, 1, 1)

date.max

最大的日期 ,date(MAXYEAR, 12, 31)

date.resolution

两个日期对象的最小间隔,timedelta(days=1)

实例属性(只读):

date.year

MINYEARMAXYEAR 之间,包含边界。

date.month

1 至 12(含)

date.day

返回1到指定年月的天数间的数字。

支持的运算:

运算 结果:
date2 = date1 + timedelta date2 等于从 date1 减去 timedelta.days 天。 (1)
date2 = date1 - timedelta 计算 date2 的值使得 date2 + timedelta == date1。 (2)
timedelta = date1 - date2 (3)
date1 < date2 如果 date1 的时间在 date2 之前则认为 date1 小于 date2 。 (4)

注释:

  1. 如果 timedelta.days > 0date2 将在时间线上前进,如果 timedelta.days < 0 则将后退。 操作完成后 date2 - date1 == timedelta.daystimedelta.secondstimedelta.microseconds 会被忽略。 如果 date2.year 将小于 MINYEAR 或大于 MAXYEAR 则会引发 OverflowError
  2. timedelta.secondstimedelta.microseconds 会被忽略。
  3. 此值完全精确且不会溢出。 操作完成后 timedelta.seconds 和 timedelta.microseconds 均为 0,并且 date2 + timedelta == date1。
  4. 换句话说,当且仅当 date1.toordinal() < date2.toordinal()date1 < date2。 日期比较会引发 TypeError,如果比较目标不为 date 对象的话。 不过也可能会返回 NotImplemented,如果比较目标具有 timetuple() 属性的话。 这个钩子给予其他日期对象类型实现混合类型比较的机会。 否则,当 date 对象与不同类型的对象比较时将会引发 TypeError,除非是 ==!= 比较。 后两种情况将分别返回 FalseTrue

在布尔运算中,所有 date 对象都会被视为真值。

实例方法:

date.replace(year=self.year, month=self.month, day=self.day)

返回一个具有同样值的日期,除非通过任何关键字参数给出了某些形参的新值。

示例:

>>>from datetime import date
>>> d = date(2002,12,31)
>>> d.replace(day=26)
datetime.date(2002,12,26)

date.timetuple()

返回一个 time.struct_time,即 time.localtime() 所返回的类型。

hours, minutes 和 seconds 值均为 0,且 DST 旗标值为 -1。

d.timetuple() 等价于:

time.struct_time((d.year, d.month, d.day,0,0,0, d.weekday(), yday,-1))

其中 yday = d.toordinal() - date(d.year, 1, 1).toordinal() + 1 是当前年份中的日期序号,1 月 1 日的序号为 1

date.toordinal()

返回日期的预期格列高利历序号,其中公元 1 年 1 月 1 日的序号为 1。 对于任意 date 对象 ddate.fromordinal(d.toordinal()) == d

date.weekday()

返回一个整数代表星期几,星期一为0,星期天为6。例如, date(2002, 12, 4).weekday() == 2,表示的是星期三。

返回一个整数代表星期几,星期一为1,星期天为7。例如:date(2002, 12, 4).isoweekday() == 3,表示星期三。

date.isocalendar()

返回一个由三部分组成的 named tuple 对象: year, weekweekday

ISO 历法是一种被广泛使用的格列高利历。

ISO 年由 52 或 53 个完整星期构成,每个星期开始于星期一结束于星期日。 一个 ISO 年的第一个星期就是(格列高利)历法的一年中第一个包含星期四的星期。 这被称为 1 号星期,这个星期四所在的 ISO 年与其所在的格列高利年相同。

例如,2004 年的第一天是星期四,因此 ISO 2004 年的第一个星期开始于 2003 年 12 月 29 日星期一,结束于 2004 年 1 月 4 日星期日:

>>>from datetime import date
>>> date(2003,12,29).isocalendar()
datetime.IsoCalendarDate(year=2004, week=1, weekday=1)
>>> date(2004,1,4).isocalendar()
datetime.IsoCalendarDate(year=2004, week=1, weekday=7)

在 3.9 版更改: 结果由元组改为 named tuple。

date.isoformat()

返回一个以 ISO 8601 格式 YYYY-MM-DD 来表示日期的字符串:

>>>from datetime import date
>>> date(2002,12,4).isoformat()
'2002-12-04'

这是 date.fromisoformat() 的逆操作。

date.__str__()

对于日期对象 d, str(d) 等价于 d.isoformat()

date.ctime()

返回一个表示日期的字符串:

>>>from datetime import date
>>> date(2002,12,4).ctime()
'Wed Dec  4 00:00:00 2002'

d.ctime() 等效于:

time.ctime(time.mktime(d.timetuple()))

在原生 C ctime() 函数 (time.ctime() 会发起调用该函数,但 date.ctime() 则不会) 遵循 C 标准的平台上。

date.strftime(format)

返回一个由显式格式字符串所指明的代表日期的字符串。 表示时、分或秒的格式代码值将为 0。

date.__format__(format)

date.strftime() 相同。 此方法使得为 date 对象指定以 格式化字符串字面值 表示的格式化字符串以及使用 str.format() 进行格式化成为可能。

class:date 用法示例

计算距离特定事件天数的例子:

>>>import time
>>>from datetime import date
>>> today = date.today()
>>> today
datetime.date(2007,12,5)
>>> today == date.fromtimestamp(time.time())
True
>>> my_birthday = date(today.year,6,24)
>>>if my_birthday < today:
...     my_birthday = my_birthday.replace(year=today.year +1)
>>> my_birthday
datetime.date(2008,6,24)
>>> time_to_birthday = abs(my_birthday - today)
>>> time_to_birthday.days
202

使用 date 的更多例子:

>>>from datetime import date
>>> d = date.fromordinal(730920)# 730920th day after 1. 1. 0001
>>> d
datetime.date(2002,3,11)
>>># Methods related to formatting string output
>>> d.isoformat()
'2002-03-11'
>>> d.strftime("%d/%m/%y")
'11/03/02'
>>> d.strftime("%A %d. %B %Y")
'Monday 11. March 2002'
>>> d.ctime()
'Mon Mar 11 00:00:00 2002'
>>>'The {1} is {0:%d}, the {2} is {0:%B}.'.format(d,"day","month")
'The day is 11, the month is March.'
>>># Methods for to extracting 'components' under different calendars
>>> t = d.timetuple()
>>>for i in t:
...print(i)
2002# year
3# month
11# day
0
0
0
0# weekday (0 = Monday)
70# 70th day in the year
-1
>>> ic = d.isocalendar()
>>>for i in ic:
...print(i)
2002# ISO year
11# ISO week number
1# ISO day number ( 1 = Monday )
>>># A date object is immutable; all operations produce a new object
>>> d.replace(year=2005)
datetime.date(2005,3,11)

datetime 对象

datetime 对象是包含来自 date 对象和 time 对象的所有信息的单一对象。

date 对象一样,datetime 假定当前的格列高利历向前后两个方向无限延伸;与 time 对象一样,datetime 假定每一天恰好有 3600*24 秒。

构造器 :

classdatetime.datetime(year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, **, fold=0*)

year, monthday 参数是必须的。 tzinfo 可以是 None 或者是一个 tzinfo 子类的实例。 其余的参数必须是在下面范围内的整数:

  • MINYEAR <= year <= MAXYEAR,
  • 1 <= month <= 12,
  • 1 <= day <= 指定年月的天数,
  • 0 <= hour < 24,
  • 0 <= minute < 60,
  • 0 <= second < 60,
  • 0 <= microsecond < 1000000,
  • fold in [0, 1].

如果参数不在这些范围内,则抛出 ValueError 异常。

3.6 新版功能: 增加了 fold 参数。

其它构造器,所有的类方法:

classmethoddatetime.today()

返回表示当前地方时的 datetime 对象,其中 tzinfoNone

等价于:

datetime.fromtimestamp(time.time())

此方法的功能等价于 now(),但是不带 tz 形参。

classmethoddatetime.now(tz=None)

返回表示当前地方时的 date 和 time 对象。

如果可选参数 tzNone 或未指定,这就类似于 today(),但该方法会在可能的情况下提供比通过 time.time() 时间戳所获时间值更高的精度(例如,在提供了 C gettimeofday() 函数的平台上就可以做到这一点)。

如果 tz 不为 None,它必须是 tzinfo 子类的一个实例,并且当前日期和时间将被转换到 tz 时区。

此函数可以替代 today()utcnow()

classmethoddatetime.utcnow()

返回表示当前 UTC 时间的 date 和 time,其中 tzinfoNone

这类似于 now(),但返回的是当前 UTC 日期和时间,类型为简单型 datetime 对象。 感知型的当前 UTC 日期时间可通过调用 datetime.now(timezone.utc) 来获得。

警告

由于简单型 datetime 对象会被许多 datetime 方法当作本地时间来处理,最好是使用感知型日期时间对象来表示 UTC 时间。 因此,创建表示当前 UTC 时间的对象的推荐方式是通过调用 datetime.now(timezone.utc)

classmethoddatetime.fromtimestamp(timestamp, tz=None)

返回对应于 POSIX 时间戳例如 time.time() 的返回值的本地日期和时间。 如果可选参数 tzNone 或未指定,时间戳会被转换为所在平台的本地日期和时间,返回的 datetime 对象将为天真型。

如果 tz 不为 None,它必须是 tzinfo 子类的一个实例,并且时间戳将被转换到 tz 指定的时区。

fromtimestamp() 可能会引发 OverflowError,如果时间戳数值超出所在平台 C localtime()gmtime() 函数的支持范围的话,并会在 localtime()gmtime() 报错时引发 OSError。 通常该数值会被限制在 1970 年至 2038 年之间。 请注意在时间戳概念包含闰秒的非 POSIX 系统上,闰秒会被 fromtimestamp() 所忽略,结果可能导致两个相差一秒的时间戳产生相同的 datetime 对象。 相比 utcfromtimestamp() 更推荐使用此方法。

在 3.3 版更改: 引发 OverflowError 而不是 ValueError,如果时间戳数值超出所在平台 C localtime()gmtime() 函数的支持范围的话。 并会在 localtime()gmtime() 出错时引发 OSError 而不是 ValueError

在 3.6 版更改: fromtimestamp() 可能返回 fold 值设为 1 的实例。

classmethoddatetime.utcfromtimestamp(timestamp)

返回对应于 POSIX 时间戳的 UTC datetime,其中 tzinfo 值为 None。 (结果为简单型对象。)

这可能引发 OverflowError,如果时间戳数值超出所在平台 C gmtime() 函数的支持范围的话,并会在 gmtime() 报错时引发 OSError。 通常该数值会被限制在 1970 至 2038 年之间。

要得到一个感知型 datetime 对象,应调用 fromtimestamp():

datetime.fromtimestamp(timestamp, timezone.utc)

在 POSIX 兼容的平台上,它等价于以下表达式:

datetime(1970,1,1, tzinfo=timezone.utc)+ timedelta(seconds=timestamp)

不同之处在于后一种形式总是支持完整年份范围:从 MINYEARMAXYEAR 的开区间。

警告

由于简单型 datetime 对象会被许多 datetime 方法当作本地时间来处理,最好是使用感知型日期时间对象来表示 UTC 时间。 因此,创建表示特定 UTC 时间戳的日期时间对象的推荐方式是通过调用 datetime.fromtimestamp(timestamp, tz=timezone.utc)

在 3.3 版更改: 引发 OverflowError 而不是 ValueError,如果时间戳数值超出所在平台 C gmtime() 函数的支持范围的话。 并会在 gmtime() 出错时引发 OSError 而不是 ValueError

classmethoddatetime.fromordinal(ordinal)

返回对应于预期格列高利历序号的 datetime,其中公元 1 年 1 月 1 日的序号为 1。 除非 1 <= ordinal <= datetime.max.toordinal() 否则会引发 ValueError。 结果的 hour, minute, second 和 microsecond 值均为 0,并且 tzinfo 值为 None

classmethoddatetime.combine(date, time, tzinfo=self.tzinfo)

返回一个新的 datetime 对象,对象的日期部分等于给定的 date 对象的值,而其时间部分等于给定的 time 对象的值。 如果提供了 tzinfo 参数,其值会被用来设置结果的 tzinfo 属性,否则将使用 time 参数的 tzinfo 属性。

对于任意 datetime 对象 dd == datetime.combine(d.date(), d.time(), d.tzinfo)。 如果 date 是一个 datetime 对象,它的时间部分和 tzinfo 属性会被忽略。

在 3.6 版更改: 增加了 tzinfo 参数。

classmethoddatetime.fromisoformat(date_string)

返回一个对应于 date.isoformat()datetime.isoformat() 所提供的某一种 date_stringdatetime 对象。

特别地,此函数支持以下格式的字符串:

YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]]

其中 * 可以匹配任意的单个字符。

警告

此函数 并不 支持解析任意 ISO 8601 字符串 —— 它的目的只是作为 datetime.isoformat() 的逆操作。 在第三方包 dateutil 中提供了一个更完善的 ISO 8601 解析器 dateutil.parser.isoparse

示例:

>>>from datetime import datetime
>>> datetime.fromisoformat('2011-11-04')
datetime.datetime(2011,11,4,0,0)
>>> datetime.fromisoformat('2011-11-04T00:05:23')
datetime.datetime(2011,11,4,0,5,23)
>>> datetime.fromisoformat('2011-11-04 00:05:23.283')
datetime.datetime(2011,11,4,0,5,23,283000)
>>> datetime.fromisoformat('2011-11-04 00:05:23.283+00:00')
datetime.datetime(2011,11,4,0,5,23,283000, tzinfo=datetime.timezone.utc)
>>> datetime.fromisoformat('2011-11-04T00:05:23+04:00')
datetime.datetime(2011,11,4,0,5,23,
    tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))

3.7 新版功能.

classmethoddatetime.fromisocalendar(year, week, day)

返回以 year, week 和 day 值指明的 ISO 历法日期所对应的 datetime。 该datetime 对象的非日期部分将使用其标准默认值来填充。 这是函数 datetime.isocalendar() 的逆操作。

3.8 新版功能.

classmethoddatetime.strptime(date_string, format)

返回一个对应于 date_string*,根据 *format 进行解析得到的 datetime 对象。

这相当于:

datetime(*(time.strptime(date_string, format)[0:6]))

如果 date_string 和 format 无法被 time.strptime() 解析或它返回一个不是时间元组的值,则将引发 ValueError

类属性:

datetime.min

最早的可表示 datetimedatetime(MINYEAR, 1, 1, tzinfo=None)

datetime.max

最晚的可表示 datetimedatetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, tzinfo=None)

datetime.resolution

两个不相等的 datetime 对象之间可能的最小间隔,timedelta(microseconds=1)

实例属性(只读):

datetime.year

MINYEARMAXYEAR 之间,包含边界。

datetime.month

1 至 12(含)

datetime.day

返回1到指定年月的天数间的数字。

datetime.hour

取值范围是 range(24)

datetime.minute

取值范围是 range(60)

datetime.second

取值范围是 range(60)

datetime.microsecond

取值范围是 range(1000000)

datetime.tzinfo

作为 tzinfo 参数被传给 datetime 构造器的对象,如果没有传入值则为 None

datetime.fold

取值范围是 [0, 1]。 用于在重复的时间段中消除边界时间歧义。 (当夏令时结束时回拨时钟或由于政治原因导致当明时区的 UTC 时差减少就会出现重复的时间段。) 取值 0 (1) 表示两个时刻早于(晚于)所代表的同一边界时间。

3.6 新版功能.

支持的运算:

运算 结果:
datetime2 = datetime1 + timedelta (1)
datetime2 = datetime1 - timedelta (2)
timedelta = datetime1 - datetime2 (3)
datetime1 < datetime2 比较 datetimedatetime。 (4)
  1. datetime2 是从 datetime1 去掉了一段 timedelta 的结果,如果 timedelta.days > 0 则是在时间线上前进,如果 timedelta.days < 0 则是在时间线上后退。 该结果具有与输入的 datetime 相同的 tzinfo 属性,并且操作完成后 datetime2 - datetime1 == timedelta。 如果 datetime2.year 将要小于 MINYEAR 或大于 MAXYEAR 则会引发 OverflowError。 请注意即使输入的是一个感知型对象,该方法也不会进行时区调整。

  2. 计算 datetime2 使得 datetime2 + timedelta == datetime1。 与相加操作一样,结果具有与输入的 datetime 相同的 tzinfo 属性,即使输入的是一个感知型对象,该方法也不会进行时区调整。

  3. 从一个 datetime 减去一个 datetime 仅对两个操作数均为简单型或均为感知型时有定义。 如果一个是感知型而另一个是简单型,则会引发 TypeError

    如果两个操作数都是简单型,或都是感知型并且具有相同的 tzinfo 属性,则 tzinfo 属性会被忽略,并且结果会是一个使得 datetime2 + t == datetime1timedelta 对象 t。 在此情况下不会进行时区调整。

    如果两个操作数都是感知型且具有不同的 tzinfo 属性,a-b 操作的效果就如同 ab 首先被转换为简单型 UTC 日期时间。 结果将是 (a.replace(tzinfo=None) - a.utcoffset()) - (b.replace(tzinfo=None) - b.utcoffset()),除非具体实现绝对不溢出。

  4. datetime1 的时间在 datetime2 之前则认为 datetime1 小于 datetime2

    如果比较的一方是简单型而另一方是感知型,则如果尝试进行顺序比较将引发 TypeError。 对于相等比较,简单型实例将永远不等于感知型实例。

    如果两个比较方都是感知型,且具有相同的 tzinfo 属性,则相同的 tzinfo 属性会被忽略并对基本日期时间值进行比较。 如果两个比较方都是感知型且具有不同的 tzinfo 属性,则两个比较方将首先通过减去它们的 UTC 差值(使用 self.utcoffset() 获取)来进行调整。

    在 3.3 版更改: 感知型和简单型 datetime 实例之间的相等比较不会引发 TypeError

    注解

    为了防止比较操作回退为默认的对象地址比较方式,datetime 比较通常会引发 TypeError,如果比较目标不同样为 datetime 对象的话。 不过也可能会返回 NotImplemented,如果比较目标具有 timetuple() 属性的话。 这个钩子给予其他种类的日期对象实现混合类型比较的机会。 如果未实现,则当 datetime 对象与不同类型比较时将会引发 TypeError,除非是 ==!= 比较。 后两种情况将分别返回 FalseTrue

实例方法:

datetime.date()

返回具有同样 year, month 和 day 值的 date 对象。

datetime.time()

返回具有同样 hour, minute, second, microsecond 和 fold 值的 time 对象。 tzinfo 值为 None

在 3.6 版更改: fold 值会被复制给返回的 time 对象。

datetime.timetz()

返回具有同样 hour, minute, second, microsecond, fold 和 tzinfo 属性性的 time 对象。

在 3.6 版更改: fold 值会被复制给返回的 time 对象。

datetime.replace(year=self.year, month=self.month, day=self.day, hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo, **, fold=0*)

返回一个具有同样属性值的 datetime,除非通过任何关键字参数为某些属性指定了新值。 请注意可以通过指定 tzinfo=None 来从一个感知型 datetime 创建一个简单型 datetime 而不必转换日期和时间数据。

3.6 新版功能: 增加了 fold 参数。

datetime.astimezone(tz=None)

返回一个具有新的 tzinfo 属性 tzdatetime 对象,并会调整日期和时间数据使得结果对应的 UTC 时间与 self 相同,但为 tz 时区的本地时间。

如果给出了 tz*,则它必须是一个 tzinfo 子类的实例,并且其 utcoffset()dst() 方法不可返回 None。 如果 *self 为简单型,它会被假定为基于系统时区表示的时间。

如果调用时不传入参数 (或传入 tz=None) 则将假定目标时区为系统的本地时区。 转换后 datetime 实例的 .tzinfo 属性将被设为一个 timezone 实例,时区名称和时差值将从 OS 获取。

如果 self.tzinfotz*,self.astimezone(tz) 等于 *self: 不会对日期或时间数据进行调整。 否则结果为 tz 时区的本地时间,代表的 UTC 时间与 self 相同:在 astz = dt.astimezone(tz) 之后,astz - astz.utcoffset() 将具有与 dt - dt.utcoffset() 相同的日期和时间数据。

如果你只是想要附加一个时区对象 tz 到一个 datetime 对象 dt 而不调整日期和时间数据,请使用 dt.replace(tzinfo=tz)。 如果你只想从一个感知型 datetime 对象 dt 移除时区对象,请使用 dt.replace(tzinfo=None)

请注意默认的 tzinfo.fromutc() 方法在 tzinfo 的子类中可以被重载,从而影响 astimezone() 的返回结果。 如果忽略出错的情况,astimezone() 的行为就类似于:

def astimezone(self, tz):
    if self.tzinfo is tz:
    return self
# Convert self to UTC, and attach the new time zone object.
    utc =(self-self.utcoffset()).replace(tzinfo=tz)
# Convert from UTC to tz's local time.
return tz.fromutc(utc)

在 3.3 版更改: tz 现在可以被省略。

在 3.6 版更改: astimezone() 方法可以由简单型实例调用,这将假定其表示本地时间。

datetime.utcoffset()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.utcoffset(self),并且在后者不返回 None 或者一个幅度小于一天的 timedelta 对象时将引发异常。

在 3.7 版更改: UTC 时差不再限制为一个整数分钟值。

datetime.dst()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.dst(self),并且在后者不返回 None 或者一个幅度小于一天的 timedelta 对象时将引发异常。

在 3.7 版更改: DST 差值不再限制为一个整数分钟值。

datetime.tzname()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.tzname(self),如果后者不返回 None 或者一个字符串对象则将引发异常。

datetime.timetuple()

返回一个 time.struct_time,即 time.localtime() 所返回的类型。

d.timetuple() 等价于:

time.struct_time((d.year, d.month, d.day,
                  d.hour, d.minute, d.second,
                  d.weekday(), yday, dst))

其中 yday = d.toordinal() - date(d.year, 1, 1).toordinal() + 1 是日期在当前年份中的序号,起始序号 1 表示 1 月 1 日。 结果的 tm_isdst 旗标的设定会依据 dst() 方法:如果 tzinfoNonedst() 返回 None,则 tm_isdst 将设为 -1;否则如果 dst() 返回一个非零值,则 tm_isdst 将设为 1;在其他情况下 tm_isdst 将设为 0

datetime.utctimetuple()

如果 datetime 实例 d 为简单型,这类似于 d.timetuple(),不同之处在于 tm_isdst 会强制设为 0,无论 d.dst() 返回什么结果。 DST 对于 UTC 时间永远无效。

如果 d 为感知型, d 会通过减去 d.utcoffset() 来标准化为 UTC 时间,并返回该标准化时间所对应的 time.struct_timetm_isdst 会强制设为 0。 请注意如果 d.year 为 MINYEARMAXYEAR 并且 UTC 调整超出一年的边界则可能引发 OverflowError

警告

由于简单型 datetime 对象会被许多 datetime 方法当作本地时间来处理,最好是使用感知型日期时间来表示 UTC 时间;因此,使用 utcfromtimetuple 可能会给出误导性的结果。 如果你有一个表示 UTC 的简单型 datetime,请使用 datetime.replace(tzinfo=timezone.utc) 将其改为感知型,这样你才能使用 datetime.timetuple()

datetime.toordinal()

返回日期的预期格列高利历序号。 与 self.date().toordinal() 相同。

datetime.timestamp()

返回对应于 datetime 实例的 POSIX 时间戳。 此返回值是与 time.time() 返回值类似的 float 对象。

简单型 datetime 实例会假定为代表本地时间,并且此方法依赖于平台的 C mktime() 函数来执行转换。 由于在许多平台上 datetime 支持的范围比 mktime() 更广,对于极其遥远的过去或未来此方法可能引发 OverflowError

对于感知型 datetime 实例,返回值的计算方式为:

(dt - datetime(1970,1,1, tzinfo=timezone.utc)).total_seconds()

3.3 新版功能.

在 3.6 版更改: timestamp() 方法使用 fold 属性来消除重复间隔中的时间歧义。

注解

没有一个方法能直接从表示 UTC 时间的简单型 datetime 实例获取 POSIX 时间戳。 如果你的应用程序使用此惯例并且你的系统时区不是设为 UTC,你可以通过提供 tzinfo=timezone.utc 来获取 POSIX 时间戳:

timestamp = dt.replace(tzinfo=timezone.utc).timestamp()

或者通过直接计算时间戳:

timestamp =(dt - datetime(1970,1,1))/ timedelta(seconds=1)

datetime.weekday()

返回一个整数代表星期几,星期一为 0,星期天为 6。 相当于 self.date().weekday()

datetime.isoweekday()

返回一个整数代表星期几,星期一为 1,星期天为 7。 相当于 self.date().isoweekday()

datetime.isocalendar()

返回一个由三部分组成的 named tuple: year, weekweekday。 等同于 self.date().isocalendar()

datetime.isoformat(sep=’T’, timespec=’auto’)

返回一个以 ISO 8601 格式表示的日期和时间字符串:

  • YYYY-MM-DDTHH:MM:SS.ffffff,如果 microsecond 不为 0
  • YYYY-MM-DDTHH:MM:SS,如果 microsecond 为 0

如果 utcoffset() 返回值不为 None,则添加一个字符串来给出 UTC 时差:

  • YYYY-MM-DDTHH:MM:SS.ffffff+HH:MM[:SS[.ffffff]],如果 microsecond 不为 0
  • YYYY-MM-DDTHH:MM:SS+HH:MM[:SS[.ffffff]],如果 microsecond 为 0

示例:

>>>from datetime import datetime, timezone
>>> datetime(2019,5,18,15,17,8,132263).isoformat()
'2019-05-18T15:17:08.132263'
>>> datetime(2019,5,18,15,17, tzinfo=timezone.utc).isoformat()
'2019-05-18T15:17:00+00:00'

可选参数 sep (默认为 'T') 为单个分隔字符,会被放在结果的日期和时间两部分之间。 例如:

>>>from datetime import tzinfo, timedelta, datetime
>>>class TZ(tzinfo):
..."""A time zone with an arbitrary, constant -06:39 offset."""
...def utcoffset(self, dt):
...return timedelta(hours=-6, minutes=-39)
...
>>> datetime(2002,12,25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'
>>> datetime(2009,11,27, microsecond=100, tzinfo=TZ()).isoformat()
'2009-11-27T00:00:00.000100-06:39'

可选参数 timespec 要包含的额外时间组件值 (默认为 'auto')。它可以是以下值之一:

  • 'auto': 如果 microsecond 为 0 则与 'seconds' 相同,否则与 'microseconds' 相同。
  • 'hours': 以两个数码的 HH 格式 包含 hour
  • 'minutes': 以 HH:MM 格式包含 hourminute
  • 'seconds': 以 HH:MM:SS 格式包含 hour, minutesecond
  • 'milliseconds': 包含完整时间,但将秒值的小数部分截断至微秒。 格式为 HH:MM:SS.sss
  • 'microseconds': 以 HH:MM:SS.ffffff 格式包含完整时间。

注解

排除掉的时间部分将被截断,而不是被舍入。

对于无效的 timespec 参数将引发 ValueError:

>>>from datetime import datetime
>>> datetime.now().isoformat(timespec='minutes')
'2002-12-25T00:00'
>>> dt = datetime(2015,1,1,12,30,59,0)
>>> dt.isoformat(timespec='microseconds')
'2015-01-01T12:30:59.000000'

3.6 新版功能: 增加了 timespec 参数。

datetime.__str__()

对于 datetime 实例 dstr(d) 等价于 d.isoformat(' ')

datetime.ctime()

返回一个表示日期和时间的字符串:

>>>from datetime import datetime
>>> datetime(2002,12,4,20,30,40).ctime()
'Wed Dec  4 20:30:40 2002'

输出字符串将 并不 包括时区信息,无论输入的是感知型还是简单型。

d.ctime() 等效于:

time.ctime(time.mktime(d.timetuple()))

在原生 C ctime() 函数 (time.ctime() 会发起调用该函数,但 datetime.ctime() 则不会) 遵循 C 标准的平台上。

datetime.strftime(format)

返回一个由显式格式字符串所指明的代表日期和时间的字符串,要获取格式指令的完整列表。

datetime.__format__(format)

datetime.strftime() 相同。 此方法使得为 datetime 对象指定以 格式化字符串字面值 表示的格式化字符串以及使用 str.format() 进行格式化成为可能。 要获取格式指令的完整列表。

用法示例: datetime

使用 datetime 对象的例子:

>>>from datetime import datetime, date, time, timezone
>>># Using datetime.combine()
>>> d = date(2005,7,14)
>>> t = time(12,30)
>>> datetime.combine(d, t)
datetime.datetime(2005,7,14,12,30)
>>># Using datetime.now()
>>> datetime.now()
datetime.datetime(2007,12,6,16,29,43,79043)# GMT +1
>>> datetime.now(timezone.utc)
datetime.datetime(2007,12,6,15,29,43,79060, tzinfo=datetime.timezone.utc)
>>># Using datetime.strptime()
>>> dt = datetime.strptime("21/11/06 16:30","%d/%m/%y %H:%M")
>>> dt
datetime.datetime(2006,11,21,16,30)
>>># Using datetime.timetuple() to get tuple of all attributes
>>> tt = dt.timetuple()
>>>for it in tt:
...print(it)
...
2006# year
11# month
21# day
16# hour
30# minute
0# second
1# weekday (0 = Monday)
325# number of days since 1st January
-1# dst - method tzinfo.dst() returned None
>>># Date in ISO format
>>> ic = dt.isocalendar()
>>>for it in ic:
...print(it)
...
2006# ISO year
47# ISO week
2# ISO weekday
>>># Formatting a datetime
>>> dt.strftime("%A, %d. %B %Y %I:%M%p")
'Tuesday, 21. November 2006 04:30PM'
>>>'The {1} is {0:%d}, the {2} is {0:%B}, the {3} is {0:%I:%M%p}.'.format(dt,"day","month","time")
'The day is 21, the month is November, the time is 04:30PM.'

以下示例定义了一个 tzinfo 子类,它捕获 Kabul, Afghanistan 时区的信息,该时区使用 +4 UTC 直到 1945 年,之后则使用 +4:30 UTC:

from datetime import timedelta, datetime, tzinfo, timezone
classKabulTz(tzinfo):
# Kabul used +4 until 1945, when they moved to +4:30
    UTC_MOVE_DATE = datetime(1944,12,31,20, tzinfo=timezone.utc)
def utcoffset(self, dt):
if dt.year <1945:
return timedelta(hours=4)
elif(1945,1,1,0,0)<= dt.timetuple()[:5]<(1945,1,1,0,30):
# An ambiguous ("imaginary") half-hour range representing
# a 'fold' in time due to the shift from +4 to +4:30.
# If dt falls in the imaginary range, use fold to decide how
# to resolve. See PEP495.
return timedelta(hours=4, minutes=(30if dt.fold else0))
else:
return timedelta(hours=4, minutes=30)
def fromutc(self, dt):
# Follow same validations as in datetime.tzinfo
ifnot isinstance(dt, datetime):
raiseTypeError("fromutc() requires a datetime argument")
if dt.tzinfo isnotself:
raiseValueError("dt.tzinfo is not self")
# A custom implementation is required for fromutc as
# the input to this function is a datetime with utc values
# but with a tzinfo set to self.
# See datetime.astimezone or fromtimestamp.
if dt.replace(tzinfo=timezone.utc)>=self.UTC_MOVE_DATE:
return dt + timedelta(hours=4, minutes=30)
else:
return dt + timedelta(hours=4)
def dst(self, dt):
# Kabul does not observe daylight saving time.
return timedelta(0)
def tzname(self, dt):
if dt >=self.UTC_MOVE_DATE:
return"+04:30"
return"+04"

上述 KabulTz 的用法:

>>> tz1 =KabulTz()
>>># Datetime before the change
>>> dt1 = datetime(1900,11,21,16,30, tzinfo=tz1)
>>>print(dt1.utcoffset())
4:00:00
>>># Datetime after the change
>>> dt2 = datetime(2006,6,14,13,0, tzinfo=tz1)
>>>print(dt2.utcoffset())
4:30:00
>>># Convert datetime to another time zone
>>> dt3 = dt2.astimezone(timezone.utc)
>>> dt3
datetime.datetime(2006,6,14,8,30, tzinfo=datetime.timezone.utc)
>>> dt2
datetime.datetime(2006,6,14,13,0, tzinfo=KabulTz())
>>> dt2 == dt3
True

time 对象

一个 time 对象代表某日的(本地)时间,它独立于任何特定日期,并可通过 tzinfo 对象来调整。

classdatetime.time(hour=0, minute=0, second=0, microsecond=0, tzinfo=None, **, fold=0*)

所有参数都是可选的。 tzinfo 可以是 None,或者是一个 tzinfo 子类的实例。 其余的参数必须是在下面范围内的整数:

  • 0 <= hour < 24,
  • 0 <= minute < 60,
  • 0 <= second < 60,
  • 0 <= microsecond < 1000000,
  • fold in [0, 1].

如果给出一个此范围以外的参数,则会引发 ValueError。 所有参数值默认为 0,只有 tzinfo 默认为 None

类属性:

time.min

早最的可表示 time, time(0, 0, 0, 0)

time.max

最晚的可表示 time, time(23, 59, 59, 999999)

time.resolution

两个不相等的 time 对象之间可能的最小间隔,timedelta(microseconds=1),但是请注意 time 对象并不支持算术运算。

实例属性(只读):

time.hour

取值范围是 range(24)

time.minute

取值范围是 range(60)

time.second

取值范围是 range(60)

time.microsecond

取值范围是 range(1000000)

time.tzinfo

作为 tzinfo 参数被传给 time 构造器的对象,如果没有传入值则为 None

time.fold

取值范围是 [0, 1]。 用于在重复的时间段中消除边界时间歧义。 (当夏令时结束时回拨时钟或由于政治原因导致当明时区的 UTC 时差减少就会出现重复的时间段。) 取值 0 (1) 表示两个时刻早于(晚于)所代表的同一边界时间。

3.6 新版功能.

time 对象支持 timetime 的比较,当 a 时间在 b 之前时,则认为 a 小于 b。 如果比较的一方是简单型而另一方是感知型,则如果尝试进行顺序比较将引发 TypeError。 对于相等比较,简单型实例将永远不等于感知型实例。

如果两个比较方都是感知型,且具有相同的 tzinfo 属性,相同的 tzinfo 属性会被忽略并对基本时间值进行比较。 如果两个比较方都是感知型且具有不同的 tzinfo 属性,两个比较方将首先通过减去它们的 UTC 时差(从 self.utcoffset() 获取)来进行调整。 为了防止将混合类型比较回退为基于对象地址的默认比较,当 time 对象与不同类型的对象比较时,将会引发 TypeError,除非比较运算符是 ==!=。 在后两种情况下将分别返回 FalseTrue

在 3.3 版更改: 感知型和简单型 time 实例之间的相等比较不会引发 TypeError

在布尔运算时,time 对象总是被视为真值。

在 3.5 版更改: 在 Python 3.5 之前,如果一个 time 对象代表 UTC 午夜零时则会被视为假值。 此行为被认为容易引发困惑和错误,因此从 Python 3.5 起已被去除。

其他构造方法:

classmethodtime.fromisoformat(time_string)

返回对应于 time.isoformat() 所提供的某种 time_string 格式的 time。 特别地,此函数支持以下格式的字符串:

HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]

警告

此方法 并不 支持解析任意 ISO 8601 字符串。 它的目的只是作为 time.isoformat() 的逆操作。

示例:

>>>from datetime import time
>>> time.fromisoformat('04:23:01')
datetime.time(4,23,1)
>>> time.fromisoformat('04:23:01.000384')
datetime.time(4,23,1,384)
>>> time.fromisoformat('04:23:01+04:00')
datetime.time(4,23,1, tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))

3.7 新版功能.

实例方法:

time.replace(hour=self.hour, minute=self.minute, second=self.second, microsecond=self.microsecond, tzinfo=self.tzinfo, **, fold=0*)

返回一个具有同样属性值的 time,除非通过任何关键字参数指定了某些属性值。 请注意可以通过指定 tzinfo=None 从一个感知型 time 创建一个简单型 time,而不必转换时间数据。

3.6 新版功能: 增加了 fold 参数。

time.isoformat(timespec=’auto’)

返回表示为下列 ISO 8601 格式之一的时间字符串:

  • HH:MM:SS.ffffff,如果 microsecond 不为 0
  • HH:MM:SS,如果 microsecond 为 0
  • HH:MM:SS.ffffff+HH:MM[:SS[.ffffff]],如果 utcoffset() 不返回 None
  • HH:MM:SS+HH:MM[:SS[.ffffff]],如果 microsecond 为 0 并且 utcoffset() 不返回 None

可选参数 timespec 要包含的额外时间组件值 (默认为 'auto')。它可以是以下值之一:

  • 'auto': 如果 microsecond 为 0 则与 'seconds' 相同,否则与 'microseconds' 相同。
  • 'hours': 以两个数码的 HH 格式 包含 hour
  • 'minutes': 以 HH:MM 格式包含 hourminute
  • 'seconds': 以 HH:MM:SS 格式包含 hour, minutesecond
  • 'milliseconds': 包含完整时间,但将秒值的小数部分截断至微秒。 格式为 HH:MM:SS.sss
  • 'microseconds': 以 HH:MM:SS.ffffff 格式包含完整时间。

注解

排除掉的时间部分将被截断,而不是被舍入。

对于无效的 timespec 参数将引发 ValueError

示例:

>>>from datetime import time
>>> time(hour=12, minute=34, second=56, microsecond=123456).isoformat(timespec='minutes')
'12:34'
>>> dt = time(hour=12, minute=34, second=56, microsecond=0)
>>> dt.isoformat(timespec='microseconds')
'12:34:56.000000'
>>> dt.isoformat(timespec='auto')
'12:34:56'

3.6 新版功能: 增加了 timespec 参数。

time.__str__()

对于时间对象 t, str(t) 等价于 t.isoformat()

time.strftime(format)

返回一个由显式格式字符串所指明的代表时间的字符串。

time.__format__(format)

time.strftime() 相同。 此方法使得为 time 对象指定以 格式化字符串字面值 表示的格式化字符串以及使用 str.format() 进行格式化成为可能。

time.utcoffset()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.utcoffset(None),并且在后者不返回 None 或一个幅度小于一天的 a timedelta 对象时将引发异常。

在 3.7 版更改: UTC 时差不再限制为一个整数分钟值。

time.dst()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.dst(None),并且在后者不返回 None 或者一个幅度小于一天的 timedelta 对象时将引发异常。

在 3.7 版更改: DST 差值不再限制为一个整数分钟值。

time.tzname()

如果 tzinfoNone,则返回 None,否则返回 self.tzinfo.tzname(None),如果后者不返回 None 或者一个字符串对象则将引发异常。

用法示例: time

使用 time 对象的例子:

>>>from datetime import time, tzinfo, timedelta
>>>class TZ1(tzinfo):
...def utcoffset(self, dt):
...return timedelta(hours=1)
...def dst(self, dt):
...return timedelta(0)
...def tzname(self,dt):
...return"+01:00"
...def  __repr__(self):
...return f"{self.__class__.__name__}()"
...
>>> t = time(12,10,30, tzinfo=TZ1())
>>> t
datetime.time(12,10,30, tzinfo=TZ1())
>>> t.isoformat()
'12:10:30+01:00'
>>> t.dst()
datetime.timedelta(0)
>>> t.tzname()
'+01:00'
>>> t.strftime("%H:%M:%S %Z")
'12:10:30 +01:00'
>>>'The {} is {:%H:%M}.'.format("time", t)
'The time is 12:10.'

tzinfo 对象

classdatetime.tzinfo

这是一个抽象基类,也就是说该类不应被直接实例化。 请定义 tzinfo 的子类来捕获有关特定时区的信息。

tzinfo 的(某个实体子类)的实例可以被传给 datetimetime 对象的构造器。 这些对象会将它们的属性视为对应于本地时间,并且 tzinfo 对象支持展示本地时间与 UTC 的差值、时区名称以及 DST 差值的方法,都是与传给它们的日期或时间对象的相对值。

你需要派生一个实体子类,并且(至少)提供你使用 datetime 方法所需要的标准 tzinfo 方法的实现。 datetime 模块提供了 timezone,这是 tzinfo 的一个简单实体子类,它能以与 UTC 的固定差值来表示不同的时区,例如 UTC 本身或北美的 EST 和 EDT。

对于封存操作的特殊要求:一个 tzinfo 子类必须具有可不带参数调用的 __init__() 方法,否则它虽然可以被封存,但可能无法再次解封。 这是个技术性要求,在未来可能会被取消。

一个 tzinfo 的实体子类可能需要实现以下方法。 具体需要实现的方法取决于感知型 datetime 对象如何使用它。 如果有疑问,可以简单地全都实现。

tzinfo.utcoffset(dt)

将本地时间与 UTC 时差返回为一个 timedelta 对象,如果本地时区在 UTC 以东则为正值。 如果本地时区在 UTC 以西则为负值。

这表示与 UTC 的 总计 时差;举例来说,如果一个 tzinfo 对象同时代表时区和 DST 调整,则 utcoffset() 应当返回两者的和。 如果 UTC 时差不确定则返回 None。 在其他情况下返回值必须为一个 timedelta 对象,其取值严格限制于 -timedelta(hours=24)timedelta(hours=24) 之间(差值的幅度必须小于一天)。 大多数 utcoffset() 的实现看起来可能像是以下两者之一:

return CONSTANT                 # fixed-offset class
return CONSTANT +self.dst(dt)# daylight-aware class

如果 utcoffset() 返回值不为 None,则 dst() 也不应返回 None

默认的 utcoffset() 实现会引发 NotImplementedError

在 3.7 版更改: UTC 时差不再限制为一个整数分钟值。

tzinfo.dst(dt)

将夏令时(DST)调整返回为一个 timedelta 对象,如果 DST 信息未知则返回 None

如果 DST 未启用则返回 timedelta(0)。 如果 DST 已启用则将差值作为一个 timedelta 对象返回。 请注意 DST 差值如果可用,就会直接被加入 utcoffset() 所返回的 UTC 时差,因此无需额外查询 dst() 除非你希望单独获取 DST 信息。 例如,datetime.timetuple() 会调用其 tzinfo 属性的 dst() 方法来确定应该如何设置 tm_isdst 旗标,而 tzinfo.fromutc() 会调用 dst() 来在跨越时区时处理 DST 的改变。

一个可以同时处理标准时和夏令时的 tzinfo 子类的实例 tz 必须在此情形中保持一致:

tz.utcoffset(dt) - tz.dst(dt)

必须为具有同样的 tzinfo 子类实例且 dt.tzinfo == tz 的每个 datetime 对象 dt 返回同样的结果,此表达式会产生时区的“标准时差”,它不应取决于具体日期或时间,只取决于地理位置。 datetime.astimezone() 的实现依赖此方法,但无法检测违反规则的情况;确保符合规则是程序员的责任。 如果一个 tzinfo 子类不能保证这一点,也许可以重载 tzinfo.fromutc() 的默认实现以便在任何情况下与 astimezone() 正确配合。

大多数 dst() 的实现可能会如以下两者之一:

def dst(self, dt):
# a fixed-offset class:  doesn't account for DST
return timedelta(0)

或者:

def dst(self, dt):
# Code to set dston and dstoff to the time zone's DST
# transition times based on the input dt.year, and expressed
# in standard local time.
if dston <= dt.replace(tzinfo=None)< dstoff:
return timedelta(hours=1)
else:
return timedelta(0)

默认的 dst() 实现会引发 NotImplementedError

在 3.7 版更改: DST 差值不再限制为一个整数分钟值。

tzinfo.tzname(dt)

将对应于 datetime 对象 dt 的时区名称作为字符串返回。 datetime 模块没有定义任何字符串名称相关内容,也不要求名称有任何特定含义。 例如 “GMT”, “UTC”, “-500”, “-5:00”, “EDT”, “US/Eastern”, “America/New York” 都是有效的返回值。 如果字符串名称未知则返回 None。 请注意这是一个方法而不是一个固定的字符串,这主要是因为某些 tzinfo 子类可能需要根据所传入的特定 dt 值返回不同的名称,特别是当 tzinfo 类要负责处理夏令时的时候。

默认的 tzname() 实现会引发 NotImplementedError

这些方法会被 datetimetime 对象调用,用来与它们的同名方法相对应。 datetime 对象会将自身作为传入参数,而 time 对象会将 None 作为传入参数。 这样 tzinfo 子类的方法应当准备好接受 dt 参数值为 None 或是 datetime 类的实例。

当传入 None 时,应当由类的设计者来决定最佳回应方式。 例如,返回 None 适用于希望该类提示时间对象不参与 tzinfo 协议处理。 让 utcoffset(None) 返回标准 UTC 时差也许会更有用处,因为并没有其他可用于发现标准时差的约定惯例。

当传入一个 datetime 对象来回应 datetime 方法时,dt.tzinfoself 是同一对象。 tzinfo 方法可以依赖这一点,除非用户代码直接调用了 tzinfo 方法。 此行为的目的是使得 tzinfo 方法将 dt 解读为本地时间,而不需要担心其他时区的相关对象。

还有一个额外的 tzinfo 方法,某个子类可能会希望重载它:

tzinfo.fromutc(dt)

此方法会由默认的 datetime.astimezone() 实现来调用。 当被其调用时,dt.tzinfoself*,并且 *dt 的日期和时间数据会被视为表示 UTC 时间,fromutc() 的目标是调整日期和时间数据,返回一个等价的 datetime 来表示 self 的本地时间。

大多数 tzinfo 子类应该能够毫无问题地继承默认的 fromutc() 实现。 它的健壮性足以处理固定差值的时区以及同时负责标准时和夏令时的时区,对于后者甚至还能处理 DST 转换时间在各个年份有变化的情况。 一个默认 fromutc() 实现可能无法在所有情况下正确处理的例子是(与 UTC 的)标准时差取决于所经过的特定日期和时间,这种情况可能由于政治原因而出现。 默认的 astimezone()fromutc() 实现可能无法生成你希望的结果,如果这个结果恰好是跨越了标准时差发生改变的时刻当中的某个小时值的话。

忽略针对错误情况的代码,默认 fromutc() 实现的行为方式如下:

def fromutc(self, dt):
# raise ValueError error if dt.tzinfo is not self
    dtoff = dt.utcoffset()
    dtdst = dt.dst()
# raise ValueError if dtoff is None or dtdst is None
    delta = dtoff - dtdst  # this is self's standard offset
if delta:
        dt += delta   # convert to standard local time
        dtdst = dt.dst()
# raise ValueError if dtdst is None
if dtdst:
return dt + dtdst
else:
return dt

在以下 tzinfo_examples.py 文件中有一些 tzinfo 类的例子:

from datetime import tzinfo, timedelta, datetime
ZERO = timedelta(0)
HOUR = timedelta(hours=1)
SECOND = timedelta(seconds=1)
# A class capturing the platform's idea of local time.
# (May result in wrong values on historical times in
#  timezones where UTC offset and/or the DST rules had
#  changed in the past.)
import time as _time
STDOFFSET = timedelta(seconds =-_time.timezone)
if _time.daylight:
    DSTOFFSET = timedelta(seconds =-_time.altzone)
else:
    DSTOFFSET = STDOFFSET
DSTDIFF = DSTOFFSET - STDOFFSET
classLocalTimezone(tzinfo):
def fromutc(self, dt):
assert dt.tzinfo isself
        stamp =(dt - datetime(1970,1,1, tzinfo=self))// SECOND
        args = _time.localtime(stamp)[:6]
        dst_diff = DSTDIFF // SECOND
# Detect fold
        fold =(args == _time.localtime(stamp - dst_diff))
return datetime(*args, microsecond=dt.microsecond,
                        tzinfo=self, fold=fold)
def utcoffset(self, dt):
ifself._isdst(dt):
return DSTOFFSET
else:
return STDOFFSET
def dst(self, dt):
ifself._isdst(dt):
return DSTDIFF
else:
return ZERO
def tzname(self, dt):
return _time.tzname[self._isdst(dt)]
def _isdst(self, dt):
        tt =(dt.year, dt.month, dt.day,
              dt.hour, dt.minute, dt.second,
              dt.weekday(),0,0)
        stamp = _time.mktime(tt)
        tt = _time.localtime(stamp)
return tt.tm_isdst >0
Local=LocalTimezone()
# A complete implementation of current DST rules for major US time zones.
def first_sunday_on_or_after(dt):
    days_to_go =6- dt.weekday()
if days_to_go:
        dt += timedelta(days_to_go)
return dt
# US DST Rules
#
# This is a simplified (i.e., wrong for a few cases) set of rules for US
# DST start and end times. For a complete and up-to-date set of DST rules
# and timezone definitions, visit the Olson Database (or try pytz):
# http://www.twinsun.com/tz/tz-link.htm
# http://sourceforge.net/projects/pytz/ (might not be up-to-date)
#
# In the US, since 2007, DST starts at 2am (standard time) on the second
# Sunday in March, which is the first Sunday on or after Mar 8.
DSTSTART_2007 = datetime(1,3,8,2)
# and ends at 2am (DST time) on the first Sunday of Nov.
DSTEND_2007 = datetime(1,11,1,2)
# From 1987 to 2006, DST used to start at 2am (standard time) on the first
# Sunday in April and to end at 2am (DST time) on the last
# Sunday of October, which is the first Sunday on or after Oct 25.
DSTSTART_1987_2006 = datetime(1,4,1,2)
DSTEND_1987_2006 = datetime(1,10,25,2)
# From 1967 to 1986, DST used to start at 2am (standard time) on the last
# Sunday in April (the one on or after April 24) and to end at 2am (DST time)
# on the last Sunday of October, which is the first Sunday
# on or after Oct 25.
DSTSTART_1967_1986 = datetime(1,4,24,2)
DSTEND_1967_1986 = DSTEND_1987_2006
def us_dst_range(year):
# Find start and end times for US DST. For years before 1967, return
# start = end for no DST.
if2006< year:
        dststart, dstend = DSTSTART_2007, DSTEND_2007
elif1986< year <2007:
        dststart, dstend = DSTSTART_1987_2006, DSTEND_1987_2006
elif1966< year <1987:
        dststart, dstend = DSTSTART_1967_1986, DSTEND_1967_1986
else:
return(datetime(year,1,1),)*2
    start = first_sunday_on_or_after(dststart.replace(year=year))
end= first_sunday_on_or_after(dstend.replace(year=year))
return start,end
classUSTimeZone(tzinfo):
def __init__(self, hours, reprname, stdname, dstname):
self.stdoffset = timedelta(hours=hours)
self.reprname = reprname
self.stdname = stdname
self.dstname = dstname
def __repr__(self):
returnself.reprname
def tzname(self, dt):
ifself.dst(dt):
returnself.dstname
else:
returnself.stdname
def utcoffset(self, dt):
returnself.stdoffset +self.dst(dt)
def dst(self, dt):
if dt isNoneor dt.tzinfo isNone:
# An exception may be sensible here, in one or both cases.
# It depends on how you want to treat them.  The default
# fromutc() implementation (called by the default astimezone()
# implementation) passes a datetime with dt.tzinfo is self.
return ZERO
assert dt.tzinfo isself
        start,end= us_dst_range(dt.year)
# Can't compare naive to aware objects, so strip the timezone from
# dt first.
        dt = dt.replace(tzinfo=None)
if start + HOUR <= dt <end- HOUR:
# DST is in effect.
return HOUR
ifend- HOUR <= dt <end:
# Fold (an ambiguous hour): use dt.fold to disambiguate.
return ZERO if dt.fold else HOUR
if start <= dt < start + HOUR:
# Gap (a non-existent hour): reverse the fold rule.
return HOUR if dt.fold else ZERO
# DST is off.
return ZERO
def fromutc(self, dt):
assert dt.tzinfo isself
        start,end= us_dst_range(dt.year)
        start = start.replace(tzinfo=self)
end=end.replace(tzinfo=self)
        std_time = dt +self.stdoffset
        dst_time = std_time + HOUR
ifend<= dst_time <end+ HOUR:
# Repeated hour
return std_time.replace(fold=1)
if std_time < start or dst_time >=end:
# Standard time
return std_time
if start <= std_time <end- HOUR:
# Daylight saving time
return dst_time
Eastern=USTimeZone(-5,"Eastern","EST","EDT")
Central=USTimeZone(-6,"Central","CST","CDT")
Mountain=USTimeZone(-7,"Mountain","MST","MDT")
Pacific=USTimeZone(-8,"Pacific","PST","PDT")

请注意同时负责标准时和夏令时的 tzinfo 子类在每年两次的 DST 转换点上会出现不可避免的微妙问题。具体而言,考虑美国东部时区 (UTC -0500),它的 EDT 从三月的第二个星期天 1:59 (EST) 之后一分钟开始,并在十一月的第一天星期天 1:59 (EDT) 之后一分钟结束:

  UTC   3:MM  4:MM  5:MM  6:MM  7:MM  8:MM
  EST  22:MM 23:MM  0:MM  1:MM  2:MM  3:MM
  EDT  23:MM  0:MM  1:MM  2:MM  3:MM  4:MM
start  22:MM 23:MM  0:MM  1:MM  3:MM  4:MM
end23:MM  0:MM  1:MM  1:MM  2:MM  3:MM

当 DST 开始时(即 “start” 行),本地时钟从 1:59 跳到 3:00。 形式为 2:MM 的时间值在那一天是没有意义的,因此在 DST 开始那一天 astimezone(Eastern) 不会输出包含 hour == 2 的结果。 例如,在 2016 年春季时钟向前调整时,我们得到:

>>>from datetime import datetime, timezone
>>>from tzinfo_examples import HOUR,Eastern
>>> u0 = datetime(2016,3,13,5, tzinfo=timezone.utc)
>>>for i in range(4):
...     u = u0 + i*HOUR
...     t = u.astimezone(Eastern)
...print(u.time(),'UTC =', t.time(), t.tzname())
...
05:00:00 UTC =00:00:00 EST
06:00:00 UTC =01:00:00 EST
07:00:00 UTC =03:00:00 EDT
08:00:00 UTC =04:00:00 EDT

当 DST 结束时(见 “end” 行),会有更糟糕的潜在问题:本地时间值中有一个小时是不可能没有歧义的:夏令时的最后一小时。 即以北美东部时间表示当天夏令时结束时的形式为 5:MM UTC 的时间。 本地时钟从 1:59 (夏令时) 再次跳回到 1:00 (标准时)。 形式为 1:MM 的本地时间就是有歧义的。 此时 astimezone() 是通过将两个相邻的 UTC 小时映射到两个相同的本地小时来模仿本地时钟的行为。 在这个北美东部时间的示例中,形式为 5:MM 和 6:MM 的 UTC 时间在转换为北美东部时间时都将被映射到 1:MM,但前一个时间会将 fold 属性设为 0 而后一个时间会将其设为 1。 例如,在 2016 年秋季时钟往回调整时,我们得到:

>>> u0 = datetime(2016,11,6,4, tzinfo=timezone.utc)
>>>for i in range(4):
...     u = u0 + i*HOUR
...     t = u.astimezone(Eastern)
...print(u.time(),'UTC =', t.time(), t.tzname(), t.fold)
...
04:00:00 UTC =00:00:00 EDT 0
05:00:00 UTC =01:00:00 EDT 0
06:00:00 UTC =01:00:00 EST 1
07:00:00 UTC =02:00:00 EST 0

请注意不同的 datetime 实例仅通过 fold 属性值来加以区分,它们在比较时会被视为相等。

不允许时间显示存在歧义的应用需要显式地检查 fold 属性的值,或者避免使用混合式的 tzinfo 子类;当使用 timezone 或者任何其他固定差值的 tzinfo 子类例如仅表示 EST(固定差值 -5 小时)或仅表示 EDT(固定差值 -4 小时)的类时是不会有歧义的。

datetime 模块有一个基本 timezone 类(用来处理任意与 UTC 的固定时差)及其 timezone.utc 属性(一个 UTC 时区实例)。

dateutil.tz 库将 IANA 时区数据库 (又名 Olson 数据库) 引入 Python 并推荐使用。

IANA 时区数据库

该时区数据库 (通常称为 tz, tzdata 或 zoneinfo) 包含大量代码和数据用来表示全球许多有代表性的地点的本地时间的历史信息。 它会定期进行更新以反映各政治实体对时区边界、UTC 差值和夏令时规则的更改。

timezone 对象

timezone 类是 tzinfo 的子类,它的每个实例都代表一个以与 UTC 的固定时差来定义的时区。

此类的对象不可被用于代表某些特殊地点的时区信息,这些地点在一年的不同日期会使用不同的时差,或是在历史上对民用时间进行过调整。

classdatetime.timezone(offset, name=None)

offset 参数必须指定为一个 timedelta 对象,表示本地时间与 UTC 的时差。 它必须严格限制于 -timedelta(hours=24)timedelta(hours=24) 之间,否则会引发 ValueError

name 参数是可选的。 如果指定则必须为一个字符串,它将被用作 datetime.tzname() 方法的返回值。

3.2 新版功能.

在 3.7 版更改: UTC 时差不再限制为一个整数分钟值。

timezone.utcoffset(dt)

返回当 timezone 实例被构造时指定的固定值。

dt 参数会被忽略。 返回值是一个 timedelta 实例,其值等于本地时间与 UTC 之间的时差。

在 3.7 版更改: UTC 时差不再限制为一个整数分钟值。

timezone.tzname(dt)

返回当 timezone 实例被构造时指定的固定值。

如果没有在构造器中提供 name*,则 tzname(dt) 所返回的名称将根据 offset 值按以下规则生成。 如果 *offsettimedelta(0),则名称为“UTC”,否则为字符串 UTC±HH:MM,其中 ± 为 offset 的正负符号,HH 和 MM 分别为表示 offset.hoursoffset.minutes 的两个数码。

在 3.6 版更改: 由 offset=timedelta(0) 生成的名称现在为简单的 ‘UTC’ 而不再是 'UTC+00:00'

timezone.dst(dt)

总是返回 None

timezone.fromutc(dt)

返回 dt + offsetdt 参数必须为一个感知型 datetime 实例,其中 tzinfo 值设为 self

类属性:

timezone.utc

UTC 时区,timezone(timedelta(0))

strftime()strptime() 的行为

date, datetimetime 对象都支持 strftime(format) 方法,可用来创建由一个显式格式字符串所控制的表示时间的字符串。

相反地,datetime.strptime() 类会根据表示日期和时间的字符串和相应的格式字符串来创建一个 datetime 对象。

下表提供了 strftime()strptime() 的高层级比较:

strftime strptime
用法 根据给定的格式将对象转换为字符串 将字符串解析为给定相应格式的 datetime 对象
方法类型 实例方法 类方法
方法 date; datetime; time datetime
签名 strftime(format) strptime(date_string, format)

strftime()strptime() Format Codes

以下列表显示了 1989 版 C 标准所要求的全部格式代码,它们在带有标准 C 实现的所有平台上均可用。

指令 含意 示例 备注
%a 当地工作日的缩写。 Sun, Mon, …, Sat (en_US);So, Mo, …, Sa (de_DE) (1)
%A 本地化的星期中每日的完整名称。 Sunday, Monday, …, Saturday (en_US);Sonntag, Montag, …, Samstag (de_DE) (1)
%w 以十进制数显示的工作日,其中0表示星期日,6表示星期六。 0, 1, …, 6
%d 补零后,以十进制数显示的月份中的一天。 01, 02, …, 31 (9)
%b 当地月份的缩写。 Jan, Feb, …, Dec (en_US);Jan, Feb, …, Dez (de_DE) (1)
%B 本地化的月份全名。 January, February, …, December (en_US);Januar, Februar, …, Dezember (de_DE) (1)
%m 补零后,以十进制数显示的月份。 01, 02, …, 12 (9)
%y 补零后,以十进制数表示的,不带世纪的年份。 00, 01, …, 99 (9)
%Y 十进制数表示的带世纪的年份。 0001, 0002, …, 2013, 2014, …, 9998, 9999 (2)
%H 以补零后的十进制数表示的小时(24 小时制)。 00, 01, …, 23 (9)
%I 以补零后的十进制数表示的小时(12 小时制)。 01, 02, …, 12 (9)
%p 本地化的 AM 或 PM 。 AM, PM (en_US);am, pm (de_DE) (1), (3)
%M 补零后,以十进制数显示的分钟。 00, 01, …, 59 (9)
%S 补零后,以十进制数显示的秒。 00, 01, …, 59 (4), (9)
%f 以十进制数表示的微秒,在左侧补零。 000000, 000001, …, 999999 (5)
%z UTC 偏移量,格式为 ±HHMM[SS[.ffffff]] (如果是简单型对象则为空字符串)。 (空), +0000, -0400, +1030, +063415, -030712.345216 (6)
%Z 时区名称(如果对象为简单型则为空字符串)。 (空), UTC, GMT (6)
%j 以补零后的十进制数表示的一年中的日序号。 001, 002, …, 366 (9)
%U 以补零后的十进制数表示的一年中的周序号(星期日作为每周的第一天)。 在新的一年中第一个星期日之前的所有日子都被视为是在第 0 周。 00, 01, …, 53 (7), (9)
%W 以十进制数表示的一年中的周序号(星期一作为每周的第一天)。 在新的一年中第一个第期一之前的所有日子都被视为是在第 0 周。 00, 01, …, 53 (7), (9)
%c 本地化的适当日期和时间表示。 Tue Aug 16 21:30:00 1988 (en_US);Di 16 Aug 21:30:00 1988 (de_DE) (1)
%x 本地化的适当日期表示。 08/16/88 (None);08/16/1988 (en_US);16.08.1988 (de_DE) (1)
%X 本地化的适当时间表示。 21:30:00 (en_US);21:30:00 (de_DE) (1)
%% 字面的 ‘%’ 字符。 %

为了方便起见,还包括了C89标准不需要的其他一些指令。这些参数都对应于ISO 8601日期值。

指令 含意 示例 备注
%G 带有世纪的 ISO 8601 年份,表示包含大部分 ISO 星期 (%V) 的年份。 0001, 0002, …, 2013, 2014, …, 9998, 9999 (8)
%u 以十进制数显示的 ISO 8601 星期中的日序号,其中 1 表示星期一。 1, 2, …, 7
%V 以十进制数显示的 ISO 8601 星期,以星期一作为每周的第一天。 第 01 周为包含 1 月 4 日的星期。 01, 02, …, 53 (8), (9)

这些代码可能不是在所有平台上都可与 strftime() 方法配合使用。 ISO 8601 年份和 ISO 8601 星期指令并不能与上面的年份和星期序号指令相互替代。 调用 strptime() 时传入不完整或有歧义的 ISO 8601 指令将引发 ValueError

The full set of format codes supported varies across platforms, because Python calls the platform C library’s strftime() function, and platform variations are common. To see the full set of format codes supported on your platform, consult the strftime(3) documentation. There are also differences between platforms in handling of unsupported format specifiers.

3.6 新版功能: 增加了 %G, %u%V

技术细节

总体而言,d.strftime(fmt) 类似于 time 模块的 time.strftime(fmt, d.timetuple()),但是并非所有对象都支持 timetuple() 方法。

对于 datetime.strptime() 类方法,默认值为 1900-01-01T00:00:00.000: 任何未在格式字符串中指定的部分都将从默认值中提取。

使用 datetime.strptime(date_string, format) 等价于:

datetime(*(time.strptime(date_string, format)[0:6]))

除非格式中包含秒以下的部分或时区差值信息,它们在 datetime.strptime 中受支持但会被 time.strptime 所丢弃。

对于 time 对象,年、月、日的格式代码不应被使用,因为 time 对象没有这些值。 如果它们被使用,则年份将被替换为 1900,而月和日将被替换为 1

对于 date 对象,时、分、秒和微秒的格式代码不应被使用,因为 date 对象没有这些值。 如果它们被使用,则它们都将被替换为 0

出于相同的原因,对于包含当前区域设置字符集所无法表示的 Unicode 码位的格式字符串的处理方式也取决于具体平台。 在某些平台上这样的码位会不加修改地原样输出,而在其他平台上 strftime 则可能引发 UnicodeError 或只返回一个空字符串。

注释:

  1. 由于此格式依赖于当前区域设置,因此对具体输出值应当保持谨慎预期。 字段顺序会发生改变(例如 “month/day/year” 与 “day/month/year”),并且输出可能包含使用区域设置所指定的默认编码格式的 Unicode 字符(例如如果当前区域为 ja_JP,则默认编码格式可能为 eucJP, SJISutf-8 中的一个;使用 locale.getlocale() 可确定当前区域设置的编码格式)。

  2. strptime() 方法能够解析整个 [1, 9999] 范围内的年份,但 < 1000 的年份必须加零填充为 4 位数字宽度。

    在 3.2 版更改: 在之前的版本中,strftime() 方法只限于 >= 1900 的年份。

    在 3.3 版更改: 在版本3.2中,strftime() 方法只限于 years >= 1000。

  3. 当与 strptime() 方法一起使用时,如果使用 %I 指令来解析小时,%p 指令只影响输出小时字段。

  4. time 模块不同的是, datetime 模块不支持闰秒。

  5. 当与 strptime() 方法一起使用时,%f 指令可接受一至六个数码及左边的零填充。 %f 是对 C 标准中格式字符集的扩展(但单独在 datetime 对象中实现,因此它总是可用)。

  6. 对于简单型对象,%z and %Z 格式代码会被替换为空字符串。

    对于一个感知型对象而言:

    %z

    utcoffset() 会被转换为 ±HHMM[SS[.ffffff]] 形式的字符串,其中 HH 为给出 UTC 时差的小时部分的 2 位数码字符串,MM 为给出 UTC 时差的分钟部分的 2 位数码字符串,SS 为给出 UTC 时差的秒部分的 2 位数码字符串,而 ffffff 为给出 UTC 时差的微秒部分的 6 位数码字符串。 当时差为整数秒时 ffffff 部分将被省略,而当时差为整数分钟时 ffffffSS 部分都将被省略。 例如,如果 utcoffset() 返回 timedelta(hours=-3, minutes=-30),则 %z 会被替换为字符串 '-0330'

    在 3.7 版更改: UTC 时差不再限制为一个整数分钟值。

    在 3.7 版更改: 当提供 %z 指令给 strptime() 方法时,UTC 差值可以在时、分和秒之间使用冒号分隔符。 例如,'+01:00:00' 将被解读为一小时的差值。 此外,提供 'Z' 就相当于 '+00:00'

    %Z

    strftime() 中,如果 tzname() 返回 None%Z 会被替换为一个空字符串;在其他情况下 %Z 会被替换为返回值,该值必须为一个字符串。

    strptime() 仅接受特定的 %Z 值:

    1. 你的机器的区域设置可以是 time.tzname 中的任何值
    2. 硬编码的值 UTCGMT

    这样生活在日本的人可用的值为 JST, UTCGMT,但可能没有 EST。 它将引发 ValueError 表示无效的值。

    在 3.2 版更改: 当提供 %z 指令给 strptime() 方法时,将产生一个感知型 datetime 对象。 结果的 tzinfo 将被设为一个 timezone 实例。

  7. 当与 strptime() 方法一起使用时,%U%W 仅用于指定星期几和日历年份 (%Y) 的计算。

  8. 类似于 %U%W%V 仅用于在 strptime() 格式字符串中指定星期几和 ISO 年份 (%G) 的计算。 还要注意 %G%Y 是不可交换的。

  9. 当于 strptime() 方法一起使用时,前导的零在格式 %d, %m, %H, %I, %M, %S, %J, %U, %W%V 中是可选的。 格式 %y 不要求有前导的零。

zoneinfo —- IANA 时区支持

3.9 新版功能.


zoneinfo 模块根据 PEP 615 的最初说明提供了具体的时区实现来支持 IANA 时区数据库。 按照默认设置,zoneinfo 会在可能的情况下使用系统的时区数据;如果系统时区数据不可用,该库将回退为使用 PyPI 上提供的 tzdata 第一方包。

由 CPython 核心开发者维护以通过 PyPI 提供时区数据的第一方包。

使用 ZoneInfo

ZoneInfodatetime.tzinfo 抽象基类的具体实现,其目标是通过构造器、 datetime.replace 方法或 datetime.astimezone 来与 tzinfo 建立关联:

>>> from zoneinfo import ZoneInfo
>>> from datetime import datetime, timedelta
>>> dt = datetime(2020, 10, 31, 12, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(dt)
2020-10-31 12:00:00-07:00
>>> dt.tzname()
'PDT'

以此方式构造的日期时间对象可兼容日期时间运算并可在无需进一步干预的情况下处理夏令时转换:

>>> dt_add = dt + timedelta(days=1)
>>> print(dt_add)
2020-11-01 12:00:00-08:00
>>> dt_add.tzname()
'PST'

这些时区还支持在 PEP 495 中引入的 fold。 在可能导致时间歧义的时差转换中(例如夏令时到标准时的转换),当 fold=0 时会使用转换 之前 的时差,而当 fold=1 时则使用转换 之后 的时差,例如:

>>> dt = datetime(2020, 11, 1, 1, tzinfo=ZoneInfo("America/Los_Angeles"))
>>> print(dt)
2020-11-01 01:00:00-07:00
>>> print(dt.replace(fold=1))
2020-11-01 01:00:00-08:00

当执行来自另一时区的转换时,fold 将被设置为正确的值:

>>> from datetime import timezone
>>> LOS_ANGELES = ZoneInfo("America/Los_Angeles")
>>> dt_utc = datetime(2020, 11, 1, 8, tzinfo=timezone.utc)
>>> # Before the PDT -> PST transition
>>> print(dt_utc.astimezone(LOS_ANGELES))
2020-11-01 01:00:00-07:00
>>> # After the PDT -> PST transition
>>> print((dt_utc + timedelta(hours=1)).astimezone(LOS_ANGELES))
2020-11-01 01:00:00-08:00

数据源

zoneinfo 模块不直接提供时区数据,而是在可能的情况下从系统时区数据库或 PyPI 上的第一方包 tzdata 获取时区信息。 某些系统,重要的一点是 Windows 系统也包括在内,并没有可用的 IANA 数据库,因此对于要保证获取时区信息的跨平台兼容性的项目,推荐对 tzdata 声明依赖。 如果系统数据和 tzdata 均不可用,则所有对 ZoneInfo 的调用都将引发 ZoneInfoNotFoundError

配置数据源

ZoneInfo(key) 被调用时,此构造器首先会在 TZPATH 所指定的目录下搜索匹配 key 的文件,失败时则会在 tzdata 包中查找匹配。 此行为可通过三种方式来配置:

  1. 默认的 TZPATH 未通过其他方式指定时可在 编译时 进行配置。
  2. TZPATH 可使用 环境变量 进行配置。
  3. 在 运行时,搜索路径可使用 reset_tzpath() 函数来修改。
编译时配置

默认的 TZPATH 包括一些时区数据库的通用部署位置(Windows 除外,该系统没有时区数据的“通用”位置)。 在 POSIX 系统中,下游分发者和从源码编译 Python 的开发者知道系统时区数据部署位置,它们可以通过指定编译时选项 TZPATH (或者更常见的是通过 配置旗标 --with-tzpath) 来改变默认的时区路径,该选项应当是一个由 os.pathsep 分隔的字符串。

在所有平台上,配置值会在 sysconfig.get_config_var() 中以 TZPATH 键的形式提供。

环境配置

当初始化 TZPATH 时(在导入时或不带参数调用 reset_tzpath() 时),zoneinfo 模块将使用环境变量 PYTHONTZPATH,如果变量存在则会设置搜索路径。

PYTHONTZPATH

这是一个以 os.pathsep 分隔的字符串,其中包含要使用的时区搜索路径。 它必须仅由绝对路径而非相对路径组成。 在 PYTHONTZPATH 中指定的相对路径部分将不会被使用,但在其他情况下当指定相对路径时的行为该实现是有定义的;CPython 将引发 InvalidTZPathWarning,而其他实现可自由地忽略错误部分或是引发异常。

要设置让系统忽略系统数据并改用 tzdata 包,请设置 PYTHONTZPATH=""

运行时配置

TZ 搜索路径也可在运行时使用 reset_tzpath() 函数来配置。 通常并不建议如此操作,不过在需要使用指定时区路径(或者需要禁止访问系统时区)的测试函数中使用它则是合理的。

ZoneInfo

class zoneinfo.ZoneInfo(key)

一个具体的 datetime.tzinfo 子类,它代表一个由字符串 key 所指定的 IANA 时区。 对主构造器的调用将总是返回可进行标识比较的对象;但是另一种方式,对所有的 key 值通过 ZoneInfo.clear_cache() 禁止缓存失效,对以下断言将总是为真值:

a = ZoneInfo(key)
b = ZoneInfo(key)
assert a is b

key 必须采用相对的标准化 POSIX 路径的形式,其中没有对上一层级的引用。 如果传入了不合要求的键则构造器将引发 ValueError

如果没有找到匹配 key 的文件,构造器将引发 ZoneInfoNotFoundError

ZoneInfo 类具有两个替代构造器:

classmethod ZoneInfo.from_file(fobj, /, key=None)

基于一个返回字节串的文件类对象(例如一个以二进制模式打开的文件或是一个 io.BytesIO 对象)构造 ZoneInfo 对象。 不同于主构造器,此构造器总是会构造一个新对象。

key 形参设置时区名称以供 __str__()__repr__() 使用。

由此构造器创建的对象不可被封存。

classmethod ZoneInfo.no_cache(key)

一个绕过构造器缓存的替代构造器。 它与主构造器很相似,但每次调用都会返回一个新对象。 此构造器在进行测试或演示时最为适用,但它也可以被用来创建具有不同缓存失效策略的系统。

由此构造器创建的对象在被解封时也会绕过反序列化进程的缓存。

警告

使用此构造器可以会以令人惊讶的方式改变日期时间对象的语义,只有在你确定你的需求时才使用它。

也可以使用以下的类方法:

classmethod ZoneInfo.clear_cache(**, only_keys=None*)

一个可在 ZoneInfo 类上禁用缓存的方法。 如果不传入参数,则会禁用所有缓存并且下次对每个键调用主构造器将返回一个新实例。

如果将一个键名称的可迭代对象传给 only_keys 形参,则将只有指定的键会被从缓存中移除。 传给 only_keys 但在缓存中找不到的键会被忽略。

警告

发起调用此函数可能会以令人惊讶的方式改变使用 ZoneInfo 的日期时间对象的语义;这会修改进程范围内的全局状态并因此可能产生大范围的影响。 只有在你确定你的需求时才使用它。

该类具有一个属性:

ZoneInfo.key

这是一个只读的 attribute,它返回传给构造器的 key 的值,该值应为一个 IANA 时区数据库的查找键 (例如 America/New_York, Europe/ParisAsia/Tokyo)。

对于不指定 key 形参而是基于文件构造时区,该属性将设为 None

注解

尽管将这些信息暴露给最终用户是一种比较普通的做法,但是这些值被设计作为代表相关时区的主键而不一定是面向用户的元素。 CLDR (Unicode 通用区域数据存储库) 之类的项目可被用来根据这些键获取更为用户友好的字符串。

字符串表示

当在 ZoneInfo 对象上调用 str 时返回的字符串表示默认会使用 ZoneInfo.key 属性(参见该属性文档中的用法注释):

>>> zone = ZoneInfo("Pacific/Kwajalein")
>>> str(zone)
'Pacific/Kwajalein'
>>> dt = datetime(2020, 4, 1, 3, 15, tzinfo=zone)
>>> f"{dt.isoformat()} [{dt.tzinfo}]"
'2020-04-01T03:15:00+12:00 [Pacific/Kwajalein]'

对于基于文件而非指定 key 形参所构建的对象,str 会回退为调用 repr()ZoneInforepr 是由具体实现定义的并且不一定会在不同版本间保持稳定,但它保证不会是一个有效的 ZoneInfo 键。

封存序列化

ZoneInfo 对象的序列化是基于键的,而不是序列化所有过渡数据,并且基于文件构造的 ZoneInfo 对象(即使是指定了 key 值的对象)不能被封存。

ZoneInfo 文件的行为取决于它的构造方式:

  1. ZoneInfo(key): 当使用主构造器构造时,会基于键序列化一个 ZoneInfo 对象,而当反序列化时,反序列化过程会使用主构造器,因此预期它们与其他对同一时区的引用会是同一对象。 例如,如果 europe_berlin_pkl 是一个包含基于 ZoneInfo("Europe/Berlin") 构建的封存数据的字符串,你可以预期出现以下的行为:

    >>> a = ZoneInfo("Europe/Berlin")
    >>> b = pickle.loads(europe_berlin_pkl)
    >>> a is b
    True
  2. ZoneInfo.no_cache(key): 当通过绕过缓存的构造器构造时,ZoneInfo 对象也会基于键序列化,但当反序列化时,反序列化过程会使用绕过缓存的构造器。 如果 europe_berlin_pkl_nc 是一个包含基于 ZoneInfo.no_cache("Europe/Berlin") 构造的封存数据的字符串,你可以预期出现以下的行为:

    >>> a = ZoneInfo("Europe/Berlin")
    >>> b = pickle.loads(europe_berlin_pkl_nc)
    >>> a is b
    False
  3. ZoneInfo.from_file(fobj, /, key=None): 当通过文件构造时,ZoneInfo 对象会在封存时引发异常。 如果最终用户想要封存通过文件构造的 ZoneInfo,则推荐他们使用包装类型或自定义序列化函数:或者基于键序列化,或者存储文件对象的内容并将其序列化。

该序列化方法要求所需键的时区数据在序列化和反序列化中均可用,类似于在序列化和反序列化环境中都预期存在对类和函数的引用的方式。 这还意味着在具有不同时区数据版本的环境中当解封被封存的 ZoneInfo 时并不会保证结果的一致性。

函数

zoneinfo.available_timezones()

获取一个包含可用 IANA 时区的在时区路径的任何位置均可用的全部有效键的集合。 每次调用该函数时都会重新计算。

此函数仅包括规范时区名称而不包括“特殊”时区如位于 posix/right/ 目录下的时区或 posixrules 时区。

警告

此函数可能会打开大量的文件,因为确定时区路径上某个文件是否为有效时区的最佳方式是读取开头位置的“魔术字符串”。

注解

这些值并不被设计用来对外公开给最终用户;对于面向用户的元素,应用程序应当使用 CLDR (Unicode 通用区域数据存储库) 之类来获取更为用户友好的字符串。

zoneinfo.reset_tzpath(to=None)

设置或重置模块的时区搜索路径 (TZPATH)。 当不带参数调用时,TZPATH 会被设为默认值。

调用 reset_tzpath 将不会使 ZoneInfo 缓存失效,因而在缓存未命中的情况下对主 ZoneInfo 构造器的调用将只使用新的 TZPATH

to 形参必须是由字符串或 os.PathLike 组成的 sequence 或而不是字符串,它们必须都是绝对路径。 如果所传入的不是绝对路径则将引发 ValueError

全局变量

zoneinfo.TZPATH

一个表示时区搜索路径的只读序列 — 当通过键构造 ZoneInfo 时,键会与 TZPATH 中的每个条目进行合并,并使用所找到的第一个文件。

TZPATH 可以只包含绝对路径,绝不包含相对路径,无论它是如何配置的。

zoneinfo.TZPATH 所指向的对象可能随着对 reset_tzpath() 的调用而改变,因此推荐使用 zoneinfo.TZPATH 而不是从 zoneinfo 导入 TZPATH 或是将 zoneinfo.TZPATH 赋值给一个长期变量。

异常与警告

exception zoneinfo.ZoneInfoNotFoundError

当一个 ZoneInfo 对象的构造由于在系统中找不到指定的键而失败时引发。 这是 KeyError 的一个子类。

exception zoneinfo.InvalidTZPathWarning

PYTHONTZPATH 包含将被过滤掉的无效组件,例如一个相对路径时引发。

calendar —- 日历相关函数

源代码: Lib/calendar.py


这个模块让你可以输出像 Unix cal 那样的日历,它还提供了其它与日历相关的实用函数。 默认情况下,这些日历把星期一当作一周的第一天,星期天为一周的最后一天(按照欧洲惯例)。 可以使用 setfirstweekday() 方法设置一周的第一天为星期天 (6) 或者其它任意一天。 使用整数作为指定日期的参数。

在这个模块中定义的函数和类都基于一个理想化的日历,现行公历向过去和未来两个方向无限扩展。这与 Dershowitz 和 Reingold 的书 “历法计算” 中所有计算的基本日历 — “proleptic Gregorian” 日历的定义相符合。 ISO 8601标准还规定了 0 和 负数年份。0年指公元前1年, -1年指公元前2年,依此类推。

class calendar.Calendar(firstweekday=0)

创建一个 Calendar 对象。 firstweekday 是一个整数,用于指定一周的第一天。 0 是星期一(默认值),6 是星期天。

Calendar 对象提供了一些可被用于准备日历数据格式化的方法。 这个类本身不执行任何格式化操作。 这部分任务应由子类来完成。

Calendar 类的实例有下列方法:

  • iterweekdays()

    返回一个迭代器,迭代器的内容为一星期的数字。迭代器的第一个值与 firstweekday 属性的值一至。

  • itermonthdates(year, month)

    返回一个迭代器,迭代器的内容为 yearmonth 月(1-12)的日期。这个迭代器返回当月的所有日期 ( datetime.date 对象),日期包含了本月头尾用于组成完整一周的日期。

  • itermonthdays(year, month)

    返回一个迭代器,迭代器的内容与 itermonthdates() 类似,为 yearmonth 月的日期,但不受 datetime.date 范围限制。返回的日期为当月每一天的日期对应的天数。对于不在当月的日期,显示为 0

  • itermonthdays2(year, month)

    返回一个迭代器,迭代器的内容与 itermonthdates() 类似为 yearmonth 月的日期,但不受 datetime.date 范围的限制。迭代器中的元素为一个由日期和代表星期几的数字组成的的元组。

  • itermonthdays3(year, month)

    返回一个迭代器,迭代器的内容与 itermonthdates() 类似为 yearmonth 月的日期,但不受 datetime.date 范围的限制。迭代器的元素为一个由年,月,日组成的元组。

    3.7 新版功能.

  • itermonthdays4(year, month)

    返回一个迭代器,迭代器的内容与 itermonthdates() 类似为 yearmonth 月的日期,但不受 datetime.date 范围的限制。迭代器的元素为一个由年,月,日和代表星期几的数字组成的元组。

    3.7 新版功能.

  • monthdatescalendar(year, month)

    返回一个表示指定年月的周列表。周列表由七个 datetime.date 对象组成。

  • monthdays2calendar(year, month)

    返回一个表示指定年月的周列表。周列表由七个代表日期的数字和代表周几的数字组成的二元元组。

  • monthdayscalendar(year, month)

    返回一个表示指定年月的周列表。周列表由七个代表日期的数字组成。

  • yeardatescalendar(year, width=3)

    返回可以用来格式化的指定年月的数据。返回的值是一个列表,列表是月份组成的行。每一行包含了最多 width 个月(默认为3)。每个月包含了4到6周,每周包含1—7天。每一天使用 datetime.date 对象。

  • yeardays2calendar(year, width=3)

    返回可以用来模式化的指定年月的数据(与 yeardatescalendar() 类似)。周列表的元素是由表示日期的数字和表示星期几的数字组成的元组。不在这个月的日子为0。

  • yeardayscalendar(year, width=3)

    返回可以用来模式化的指定年月的数据(与 yeardatescalendar() 类似)。周列表的元素是表示日期的数字。不在这个月的日子为0。

class calendar.TextCalendar(firstweekday=0)

可以使用这个类生成纯文本日历。

TextCalendar 实例有以下方法:

  • formatmonth(theyear, themonth, w=0, l=0)

    返回一个多行字符串来表示指定年月的日历。w 为日期的宽度,但始终保持日期居中。l 指定了每星期占用的行数。以上这些还依赖于构造器或者 setfirstweekday() 方法指定的周的第一天是哪一天。

  • prmonth(theyear, themonth, w=0, l=0)

    formatmonth() 方法一样,返回一个月的日历。

  • formatyear(theyear, w=2, l=1, c=6, m=3)

    返回一个多行字符串,这个字符串为一个 m 列日历。可选参数 w, l, 和 c 分别表示日期列数, 周的行数, 和月之间的间隔。同样,以上这些还依赖于构造器或者 setfirstweekday() 指定哪一天为一周的第一天。日历的第一年由平台依赖于使用的平台。

  • pryear(theyear, w=2, l=1, c=6, m=3)

    formatyear() 方法一样,返回一整年的日历。

class calendar.HTMLCalendar(firstweekday=0)

可以使用这个类生成 HTML 日历。

HTMLCalendar 实例有以下方法:

  • formatmonth(theyear, themonth, withyear=True)

    返回一个 HTML 表格作为指定年月的日历。 withyear 为真,则年份将会包含在表头,否则只显示月份。

  • formatyear(theyear, width=3)

    返回一个 HTML 表格作为指定年份的日历。 width (默认为3) 用于规定每一行显示月份的数量。

  • formatyearpage(theyear, width=3, css=’calendar.css’, encoding=None)

    返回一个完整的 HTML 页面作为指定年份的日历。 width\(默认为3) 用于规定每一行显示的月份数量。 css *为层叠样式表的名字。如果不使用任何层叠样式表,可以使用 None encoding* 为输出页面的编码 (默认为系统的默认编码)。

HTMLCalendar 有以下属性,你可以重载它们来自定义应用日历的样式。

  • cssclasses

    一个对应星期一到星期天的 CSS class 列表。默认列表为

    cssclasses = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]

    可以向每天加入其它样式

    cssclasses = ["mon text-bold", "tue", "wed", "thu", "fri", "sat", "sun red"]

    需要注意的是,列表的长度必须为7。

  • cssclass_noday

    工作日的 CSS 类在上个月或下个月发生。

    3.7 新版功能.

  • cssclasses_weekday_head

    用于标题行中的工作日名称的 CSS 类 列表。默认值与 cssclasses 相同。

    3.7 新版功能.

  • cssclass_month_head

    月份的头 CSS 类(由 formatmonthname() 使用)。默认值为 "month"

    3.7 新版功能.

  • cssclass_month

    某个月的月历的 CSS 类(由 formatmonth() 使用)。默认值为 "month"

    3.7 新版功能.

  • cssclass_year

    某年的年历的 CSS 类(由 formatyear() 使用)。默认值为 "year"

    3.7 新版功能.

  • cssclass_year_head

    年历的·表头 CSS 类(由 formatyear() 使用)。默认值为 "year"

    3.7 新版功能.

需要注意的是,尽管上面命名的样式类都是单独出现的(如: cssclass_month cssclass_noday), 但我们可以使用空格将样式类列表中的多个元素分隔开,例如:

"text-bold text-red"

下面是一个如何自定义 HTMLCalendar 的示例

class CustomHTMLCal(calendar.HTMLCalendar):
    cssclasses = [style + " text-nowrap" for style in
                  calendar.HTMLCalendar.cssclasses]
    cssclass_month_head = "text-center month-head"
    cssclass_month = "text-center month"
    cssclass_year = "text-italic lead"

class calendar.LocaleTextCalendar(firstweekday=0, locale=None)

这个子类 TextCalendar 可以在构造函数中传递一个语言环境名称,并且返回月份和星期几的名称在特定语言环境中。如果此语言环境包含编码,则包含月份和工作日名称的所有字符串将作为 unicode 返回。

class calendar.LocaleHTMLCalendar(firstweekday=0, locale=None)

This subclass of HTMLCalendar can be passed a locale name in the constructor and will return month and weekday names in the specified locale. If this locale includes an encoding all strings containing month and weekday names will be returned as unicode.

注解

这两个类的 formatweekday()formatmonthname() 方法临时更改dang当前区域至给定 locale 。由于当前的区域设置是进程范围的设置,因此它们不是线程安全的。

对于简单的文本日历,这个模块提供了以下方法。

calendar.setfirstweekday(weekday)

设置每一周的开始(0 表示星期一,6 表示星期天)。calendar还提供了 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAYSUNDAY 几个常量方便使用。例如,设置每周的第一天为星期天

import calendar
calendar.setfirstweekday(calendar.SUNDAY)

calendar.firstweekday()

返回当前设置的每星期的第一天的数值。

calendar.isleap(year)

如果 year 是闰年则返回 True ,否则返回 False

calendar.leapdays(y1, y2)

返回在范围 y1y2 (包含 y1 和 y2 )之间的闰年的年数,其中 y1y2 是年份。

此函数适用于跨越一个世纪变化的范围。

calendar.weekday(year, month, day)

返回某年( 1970 — …),某月( 112 ),某日( 131 )是星期几( 0 是星期一)。

calendar.weekheader(n)

返回一个包含星期几的缩写名的头。 n 指定星期几缩写的字符宽度。

calendar.monthrange(year, month)

返回指定 年份 的指定 月份 的第一天是星期几和这个月的天数。

calendar.monthcalendar(year, month)

返回表示一个月的日历的矩阵。 每一行代表一周;此月份外的日子由零表示。 每周从周一开始,除非使用 setfirstweekday() 改变设置。

calendar.prmonth(theyear, themonth, w=0, l=0)

打印由 month() 返回的一个月的日历。

calendar.month(theyear, themonth, w=0, l=0)

使用 TextCalendar 类的 formatmonth() 以多行字符串形式返回月份日历。

calendar.prcal(year, w=0, l=0, c=6, m=3)

打印由 calendar() 返回的整年的日历。

calendar.calendar(year, w=2, l=1, c=6, m=3)

使用 TextCalendar 类的 formatyear() 返回整年的3列的日历以多行字符串的形式。

calendar.timegm(tuple)

一个不相关但很好用的函数,它接受一个时间元组例如 time 模块中的 gmtime() 函数的返回并返回相应的 Unix 时间戳值,假定 1970 年开始计数, POSIX 编码。实际上, time.gmtime()timegm() 是彼此相反的。

calendar 模块导出以下数据属性:

calendar.day_name

在当前语言环境下表示星期几的数组。

calendar.day_abbr

在当前语言环境下表示星期几缩写的数组。

calendar.month_name

在当前语言环境下表示一年中月份的数组。这遵循一月的月号为 1 的通常惯例,所以它的长度为 13 且 month_name[0] 是空字符串。

calendar.month_abbr

在当前语言环境下表示月份简写的数组。这遵循一月的月号为 1 的通常惯例,所以它的长度为 13 且 month_abbr[0] 是空字符串。

collections —- 容器数据类型

Source code: Lib/collections/init.py


这个模块实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择。

namedtuple() 创建命名元组子类的工厂函数
deque 类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
ChainMap 类似字典(dict)的容器类,将多个映射集合到一个视图里面
Counter 字典的子类,提供了可哈希对象的计数功能
OrderedDict 字典的子类,保存了他们被添加的顺序
defaultdict 字典的子类,提供了一个工厂函数,为字典查询提供一个默认值
UserDict 封装了字典对象,简化了字典子类化
UserList 封装了列表对象,简化了列表子类化
UserString 封装了字符串对象,简化了字符串子类化

ChainMap 对象

3.3 新版功能.

一个 ChainMap 类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update() 要快很多。

这个类可以用于模拟嵌套作用域,并且在模版化的时候比较有用。

class collections.ChainMap(\maps*)

一个 ChainMap 将多个字典或者其他映射组合在一起,创建一个单独的可更新的视图。 如果没有 maps 被指定,就提供一个默认的空字典,这样一个新链至少有一个映射。

底层映射被存储在一个列表中。这个列表是公开的,可以通过 maps 属性存取和更新。没有其他的状态。

搜索查询底层映射,直到一个键被找到。不同的是,写,更新和删除只操作第一个映射。

一个 ChainMap 通过引用合并底层映射。 所以,如果一个底层映射更新了,这些更改会反映到 ChainMap

支持所有常用字典方法。另外还有一个 maps 属性(attribute),一个创建子上下文的方法(method), 一个存取它们首个映射的属性(property):

  • maps

    一个可以更新的映射列表。这个列表是按照第一次搜索到最后一次搜索的顺序组织的。它是仅有的存储状态,可以被修改。列表最少包含一个映射。

  • new_child(m=None, **kwargs)

    返回一个新的 ChainMap,其中包含一个新的映射,后面跟随当前实例中的所有映射。 如果指定了 m,它会成为新的映射加在映射列表的前面;如果未指定,则会使用一个空字典,因此调用 d.new_child() 就等价于 ChainMap({}, *d.maps)。 如果指定了任何关键字参数,它们会更新所传入的映射或新的空字典。 此方法被用于创建子上下文,它可在不改变任何上级映射的情况下被更新。

    在 3.4 版更改: 添加了 m 可选参数。

    在 3.10 版更改: 增加了对关键字参数的支持。

  • parents

    属性返回一个新的 ChainMap 包含所有的当前实例的映射,除了第一个。这样可以在搜索的时候跳过第一个映射。 使用的场景类似在 nested scopes 嵌套作用域中使用 nonlocal 关键词。用例也可以类比内建函数 super() 。一个 d.parents 的引用等价于 ChainMap(*d.maps[1:])

注意,一个 ChainMap() 的迭代顺序是通过从后往前扫描所有映射来确定的:

>>> baseline = {'music': 'bach', 'art': 'rembrandt'}
>>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
>>> list(ChainMap(adjustments, baseline))
['music', 'art', 'opera']

这给出了与 dict.update() 调用序列相同的顺序,从最后一个映射开始:

>>> combined = baseline.copy()
>>> combined.update(adjustments)
>>> list(combined)
['music', 'art', 'opera']

在 3.9 版更改: 增加了对 ||= 运算符的支持,相关说明见 PEP 584

ChainMap 例子和方法

这一节提供了多个使用链映射的案例。

模拟Python内部lookup链的例子

import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))

让用户指定的命令行参数优先于环境变量,优先于默认值的例子

import os, argparse
defaults = {'color': 'red', 'user': 'guest'}
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}
combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])

ChainMap 类模拟嵌套上下文的例子

c = ChainMap()        # Create root context
d = c.new_child()     # Create nested child context
e = c.new_child()     # Child of c, independent from d
e.maps[0]             # Current context dictionary -- like Python's locals()
e.maps[-1]            # Root context -- like Python's globals()
e.parents             # Enclosing context chain -- like Python's nonlocals
d['x'] = 1            # Set value in current context
d['x']                # Get first key in the chain of contexts
del d['x']            # Delete from current context
list(d)               # All nested values
k in d                # Check all nested values
len(d)                # Number of nested values
d.items()             # All nested items
dict(d)               # Flatten into a regular dictionary

ChainMap 类只更新链中的第一个映射,但lookup会搜索整个链。 然而,如果需要深度写和删除,也可以很容易的通过定义一个子类来实现它

class DeepChainMap(ChainMap):
    'Variant of ChainMap that allows direct updates to inner scopes'
    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                mapping[key] = value
                return
        self.maps[0][key] = value
    def __delitem__(self, key):
        for mapping in self.maps:
            if key in mapping:
                del mapping[key]
                return
        raise KeyError(key)
>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'         # update an existing key two levels down
>>> d['snake'] = 'red'           # new keys get added to the topmost dict
>>> del d['elephant']            # remove an existing key one level down
>>> d                            # display result
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

Counter 对象

一个计数器工具提供快速和方便的计数。比如

>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})
>>> # Find the ten most common words in Hamlet
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
 ('you', 554),  ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]

class collections.Counter([iterable-or-mapping])

一个 Counter 是一个 dict 的子类,用于计数可哈希对象。它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数。 Counter 类有点像其他语言中的 bags或multisets。

元素从一个 iterable 被计数或从其他的 mapping (or counter)初始化:

>>> c = Counter()                           # a new, empty counter
>>> c = Counter('gallahad')                 # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args

Counter对象有一个字典接口,如果引用的键没有任何记录,就返回一个0,而不是弹出一个 KeyError :

>>> c = Counter(['eggs', 'ham'])
>>> c['bacon']                              # count of a missing element is zero
0

设置一个计数为0不会从计数器中移去一个元素。使用 del 来删除它:

>>> c['sausage'] = 0                        # counter entry with a zero count
>>> del c['sausage']                        # del actually removes the entry

3.1 新版功能.

在 3.7 版更改: 作为 dict 的子类,Counter 继承了记住插入顺序的功能。 Counter 对象进行数学运算时同样会保持顺序。 结果会先按每个元素在运算符左边的出现时间排序,然后再按其在运算符右边的出现时间排序。

计数器对象除了字典方法以外,还提供了三个其他的方法:

  • elements()

    返回一个迭代器,其中每个元素将重复出现计数值所指定次。 元素会按首次出现的顺序返回。 如果一个元素的计数值小于一,elements() 将会忽略它。

    >>> c = Counter(a=4, b=2, c=0, d=-2)
    >>> sorted(c.elements())
    ['a', 'a', 'a', 'a', 'b', 'b']
  • most_common([n])

    返回一个列表,其中包含 n 个最常见的元素及出现次数,按常见程度由高到低排序。 如果 n 被省略或为 Nonemost_common() 将返回计数器中的 所有 元素。 计数值相等的元素按首次出现的顺序排序:

    >>> Counter('abracadabra').most_common(3)
    [('a', 5), ('b', 2), ('r', 2)]
  • subtract([iterable-or-mapping])

    迭代对象映射对象 减去元素。像 dict.update() 但是是减去,而不是替换。输入和输出都可以是0或者负数。

    >>> c = Counter(a=4, b=2, c=0, d=-2)
    >>> d = Counter(a=1, b=2, c=3, d=4)
    >>> c.subtract(d)
    >>> c
    Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

    3.2 新版功能.

  • total()

    计算总计数值。

    >>> c = Counter(a=10, b=5, c=0)
    >>> c.total()
    15

    3.10 新版功能.

通常字典方法都可用于 Counter 对象,除了有两个方法工作方式与字典并不相同。

  • fromkeys(iterable)

    这个类方法没有在 Counter 中实现。

  • update([iterable-or-mapping])

    迭代对象 计数元素或者 从另一个 映射对象 (或计数器) 添加。 像 dict.update() 但是是加上,而不是替换。另外,迭代对象 应该是序列元素,而不是一个 (key, value) 对。

计数对象支持相等性、子集和超集关系等富比较运算符: ==, !=, <, <=, >, >=。 所有这些检测会将不存在的元素当作计数值为零,因此 Counter(a=1) == Counter(a=1, b=0) 将返回真值。

3.10 新版功能: 增加了富比较运算

在 3.10 版更改: 在相等性检测中,不存在的元素会被当作计数值为零。 在此之前,Counter(a=3)Counter(a=3, b=0) 会被视为不同。

Counter 对象的常用案例

c.total()                       # total of all counts
c.clear()                       # reset all counts
list(c)                         # list unique elements
set(c)                          # convert to a set
dict(c)                         # convert to a regular dictionary
c.items()                       # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs))    # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1]       # n least common elements
+c                              # remove zero and negative counts

提供了几个数学操作,可以结合 Counter 对象,以生产 multisets (计数器中大于0的元素)。 加和减,结合计数器,通过加上或者减去元素的相应计数。交集和并集返回相应计数的最小或最大值。每种操作都可以接受带符号的计数,但是输出会忽略掉结果为零或者小于零的计数。

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # add two counters together:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d                       # intersection:  min(c[x], d[x]) 
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})

单目加和减(一元操作符)意思是从空计数器加或者减去。

>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})

3.3 新版功能: 添加了对一元加,一元减和位置集合操作的支持。

注解

计数器主要是为了表达运行的正的计数而设计;但是,小心不要预先排除负数或者其他类型。为了帮助这些用例,这一节记录了最小范围和类型限制。

  • Counter 类是一个字典的子类,不限制键和值。值用于表示计数,但你实际上 可以 存储任何其他值。
  • most_common() 方法在值需要排序的时候用。
  • 原地操作比如 c[key] += 1 , 值类型只需要支持加和减。 所以分数,小数,和十进制都可以用,负值也可以支持。这两个方法 update()subtract() 的输入和输出也一样支持负数和0。
  • Multiset多集合方法只为正值的使用情况设计。输入可以是负数或者0,但只输出计数为正的值。没有类型限制,但值类型需要支持加,减和比较操作。
  • elements() 方法要求正整数计数。忽略0和负数计数。

deque 对象

class collections.deque([iterable[, maxlen]])

返回一个新的双向队列对象,从左到右初始化(用方法 append()) ,从 iterable (迭代对象) 数据创建。如果 iterable 没有指定,新队列为空。

Deque队列是由栈或者queue队列生成的(发音是 “deck”,”double-ended queue”的简称)。Deque 支持线程安全,内存高效添加(append)和弹出(pop),从两端都可以,两个方向的大概开销都是 O(1) 复杂度。

虽然 list 对象也支持类似操作,不过这里优化了定长操作和 pop(0)insert(0, v) 的开销。它们引起 O(n) 内存移动的操作,改变底层数据表达的大小和位置。

如果 maxlen 没有指定或者是 None ,deques 可以增长到任意长度。否则,deque就限定到指定最大长度。一旦限定长度的deque满了,当新项加入时,同样数量的项就从另一端弹出。限定长度deque提供类似Unix filter tail 的功能。它们同样可以用与追踪最近的交换和其他数据池活动。

双向队列(deque)对象支持以下方法:

  • append(x)

    添加 x 到右端。

  • appendleft(x)

    添加 x 到左端。

  • clear()

    移除所有元素,使其长度为0.

  • copy()

    创建一份浅拷贝。

    3.5 新版功能.

  • count(x)

    计算 deque 中元素等于 x 的个数。

    3.2 新版功能.

  • extend(iterable)

    扩展deque的右侧,通过添加iterable参数中的元素。

  • extendleft(iterable)

    扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。

  • index(x[, start[, stop]])

    返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发 ValueError

    3.5 新版功能.

  • insert(i, x)

    在位置 i 插入 x

    如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError

    3.5 新版功能.

  • pop()

    移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError

  • popleft()

    移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError

  • remove(value)

    移除找到的第一个 value。 如果没有的话就引发 ValueError

  • reverse()

    将deque逆序排列。返回 None

    3.2 新版功能.

  • rotate(n=1)

    向右循环移动 n 步。 如果 n 是负数,就向左循环。

    如果deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft())

Deque对象同样提供了一个只读属性:

  • maxlen

    Deque的最大尺寸,如果没有限定的话就是 None

    3.1 新版功能.

除了以上操作,deque 还支持迭代、封存、len(d)reversed(d)copy.copy(d)copy.deepcopy(d)、成员检测运算符 in 以及下标引用例如通过 d[0] 访问首个元素等。 索引访问在两端的复杂度均为 O(1) 但在中间则会低至 O(n)。 如需快速随机访问,请改用列表。

Deque从版本3.5开始支持 __add__(), __mul__(), 和 __imul__()

示例:

>>> from collections import deque
>>> d = deque('ghi')                 # make a new deque with three items
>>> for elem in d:                   # iterate over the deque's elements
...     print(elem.upper())
G
H
I
>>> d.append('j')                    # add a new entry to the right side
>>> d.appendleft('f')                # add a new entry to the left side
>>> d                                # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop()                          # return and remove the rightmost item
'j'
>>> d.popleft()                      # return and remove the leftmost item
'f'
>>> list(d)                          # list the contents of the deque
['g', 'h', 'i']
>>> d[0]                             # peek at leftmost item
'g'
>>> d[-1]                            # peek at rightmost item
'i'
>>> list(reversed(d))                # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d                         # search the deque
True
>>> d.extend('jkl')                  # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)                      # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)                     # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d))               # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()                        # empty the deque
>>> d.pop()                          # cannot pop from an empty deque
Traceback (most recent call last):
    File "<pyshell#6>", line 1, in -toplevel-
        d.pop()
IndexError: pop from an empty deque
>>> d.extendleft('abc')              # extendleft() reverses the input order
>>> d
deque(['c', 'b', 'a'])

deque 用法

这一节展示了deque的多种用法。

限长deque提供了类似Unix tail 过滤功能

def tail(filename, n=10):
    'Return the last n lines of a file'
    with open(filename) as f:
        return deque(f, n)

另一个用法是维护一个近期添加元素的序列,通过从右边添加和从左边弹出

def moving_average(iterable, n=3):
    # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
    # http://en.wikipedia.org/wiki/Moving_average
    it = iter(iterable)
    d = deque(itertools.islice(it, n-1))
    d.appendleft(0)
    s = sum(d)
    for elem in it:
        s += elem - d.popleft()
        d.append(elem)
        yield s / n

一个 轮询调度器 可以通过在 deque 中放入迭代器来实现。值从当前迭代器的位置0被取出并暂存(yield)。 如果这个迭代器消耗完毕,就用 popleft() 将其从对列中移去;否则,就通过 rotate() 将它移到队列的末尾

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    iterators = deque(map(iter, iterables))
    while iterators:
        try:
            while True:
                yield next(iterators[0])
                iterators.rotate(-1)
        except StopIteration:
            # Remove an exhausted iterator.
            iterators.popleft()

rotate() 方法提供了一种方式来实现 deque 切片和删除。 例如, 一个纯的Python del d[n] 实现依赖于 rotate() 来定位要弹出的元素

def delete_nth(d, n):
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

要实现 deque 切片, 使用一个类似的方法,应用 rotate() 将目标元素放到左边。通过 popleft() 移去老的条目(entries),通过 extend() 添加新的条目, 然后反向 rotate。这个方法可以最小代价实现命令式的栈操作,诸如 dup, drop, swap, over, pick, rot, 和 roll

defaultdict 对象

class collections.defaultdict(default_factory=None, /[, ])

返回一个新的类似字典的对象。 defaultdict 是内置 dict 类的子类。 它重载了一个方法并添加了一个可写的实例变量。 其余的功能与 dict 类相同因而不在此文档中写明。

本对象包含一个名为 default_factory 的属性,构造时,第一个参数用于为该属性提供初始值,默认为 None。所有其他参数(包括关键字参数)都相当于传递给 dict 的构造函数。

defaultdict 对象除了支持标准 dict 的操作,还支持以下方法作为扩展:

  • __missing__(key)

    如果 default_factory 属性为 None,则调用本方法会抛出 KeyError 异常,附带参数 key

    如果 default_factory 不为 None,则它会被(不带参数地)调用来为 key 提供一个默认值,这个值和 key 作为一对键值对被插入到字典中,并作为本方法的返回值返回。

    如果调用 default_factory 时抛出了异常,这个异常会原封不动地向外层传递。

    在无法找到所需键值时,本方法会被 dict 中的 __getitem__() 方法调用。无论本方法返回了值还是抛出了异常,都会被 __getitem__() 传递。

    注意,__missing__() 不会__getitem__() 以外的其他方法调用。意味着 get() 会像正常的 dict 那样返回 None,而不是使用 default_factory

defaultdict 对象支持以下实例变量:

  • default_factory

    本属性由 __missing__() 方法来调用。如果构造对象时提供了第一个参数,则本属性会被初始化成那个参数,如果未提供第一个参数,则本属性为 None

在 3.9 版更改: 增加了合并 (|) 与更新 (|=) 运算符,相关说明见 PEP 584

defaultdict 例子

使用 list 作为 default_factory,很轻松地将(键-值对组成的)序列转换为(键-列表组成的)字典:

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

当每个键第一次遇见时,它还没有在字典里面,所以自动创建该条目,即调用 default_factory 方法,返回一个空的 listlist.append() 操作添加值到这个新的列表里。当再次存取该键时,就正常操作,list.append() 添加另一个值到列表中。这个计数比它的等价方法 dict.setdefault() 要快速和简单:

>>> d = {}
>>> for k, v in s:
...     d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

设置 default_factoryint,使 defaultdict 用于计数(类似其他语言中的 bag 或 multiset):

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]

当一个字母首次遇到时,它会查询失败,则 default_factory 会调用 int() 来提供一个整数 0 作为默认值。后续的自增操作建立起对每个字母的计数。

函数 int() 总是返回 0,这是常数函数的特殊情况。一个更快和灵活的方法是使用 lambda 函数,可以提供任何常量值(不只是0):

>>> def constant_factory(value):
...     return lambda: value
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'

设置 default_factoryset 使 defaultdict 用于构建 set 集合:

>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
...     d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]

namedtuple() 命名元组的工厂函数

命名元组赋予每个位置一个含义,提供可读性和自文档性。它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的。

collections.namedtuple(typename, field_names, **, rename=False, defaults=None, module=None*)

返回一个新的元组子类,名为 typename 。这个新的子类用于创建类元组的对象,可以通过字段名来获取属性值,同样也可以通过索引和迭代获取值。子类实例同样有文档字符串(类名和字段名)另外一个有用的 __repr__() 方法,以 name=value 格式列明了元组内容。

field_names 是一个像 [‘x’, ‘y’] 一样的字符串序列。另外 field_names 可以是一个纯字符串,用空白或逗号分隔开元素名,比如 'x y' 或者 'x, y'

任何有效的Python 标识符都可以作为字段名,除了下划线开头的那些。有效标识符由字母,数字,下划线组成,但首字母不能是数字或下划线,另外不能是关键词 keyword 比如 class, for, return, global, pass, 或 raise

如果 rename 为真, 无效字段名会自动转换成位置名。比如 ['abc', 'def', 'ghi', 'abc'] 转换成 ['abc', '_1', 'ghi', '_3'] , 消除关键词 def 和重复字段名 abc

defaults 可以为 None 或者是一个默认值的 iterable 。如果一个默认值域必须跟其他没有默认值的域在一起出现,defaults 就应用到最右边的参数。比如如果域名 ['x', 'y', 'z'] 和默认值 (1, 2) ,那么 x 就必须指定一个参数值 ,y 默认值 1z 默认值 2

如果 module 值有定义,命名元组的 __module__ 属性值就被设置。

命名元组实例没有字典,所以它们要更轻量,并且占用更小内存。

要支持封存操作,应当将命名元组类赋值给一个匹配 typename 的变量。

在 3.1 版更改: 添加了对 rename 的支持。

在 3.6 版更改: verboserename 参数成为 仅限关键字参数.

在 3.6 版更改: 添加了 module 参数。

在 3.7 版更改: 移除了 verbose 形参和 _source 属性。

在 3.7 版更改: 添加了 defaults 参数和 _field_defaults 属性。

>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22)     # instantiate with positional or keyword arguments
>>> p[0] + p[1]             # indexable like the plain tuple (11, 22)
33
>>> x, y = p                # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y               # fields also accessible by name
33
>>> p                       # readable __repr__ with a name=value style
Point(x=11, y=22)

命名元组尤其有用于赋值 csv sqlite3 模块返回的元组

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print(emp.name, emp.title)

除了继承元组的方法,命名元组还支持三个额外的方法和两个属性。为了防止字段名冲突,方法和属性以下划线开始。

classmethod somenamedtuple._make(iterable)

类方法从存在的序列或迭代实例创建一个新实例。

>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)

somenamedtuple._asdict()

返回一个新的 dict ,它将字段名称映射到它们对应的值:

>>> p = Point(x=11, y=22)
>>> p._asdict()
{'x': 11, 'y': 22}

在 3.1 版更改: 返回一个 OrderedDict 而不是 dict

在 3.8 版更改: 返回一个常规 dict 而不是 OrderedDict。 因为自 Python 3.7 起,常规字典已经保证有序。 如果需要 OrderedDict 的额外特性,推荐的解决方案是将结果转换为需要的类型: OrderedDict(nt._asdict())

somenamedtuple._replace(**kwargs)

返回一个新的命名元组实例,并将指定域替换为新的值

>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)
>>> for partnum, record in inventory.items():
...     inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())

字符串元组列出了字段名。用于提醒和从现有元组创建一个新的命名元组类型。

>>> p._fields            # view the field names
('x', 'y')
>>> Color = namedtuple('Color', 'red green blue')
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)

字典将字段名称映射到默认值。

>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults
{'balance': 0}
>>> Account('premium')
Account(type='premium', balance=0)

要获取这个名字域的值,使用 getattr() 函数 :

>>> getattr(p, 'x')
11

转换一个字典到命名元组,使用 ** 两星操作符 (所述如 解包实参列表):

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

因为一个命名元组是一个正常的Python类,它可以很容易的通过子类更改功能。这里是如何添加一个计算域和定宽输出打印格式:

>>> class Point(namedtuple('Point', ['x', 'y'])):
...     __slots__ = ()
...     @property
...     def hypot(self):
...         return (self.x ** 2 + self.y ** 2) ** 0.5
...     def __str__(self):
...         return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)
>>> for p in Point(3, 4), Point(14, 5/7):
...     print(p)
Point: x= 3.000  y= 4.000  hypot= 5.000
Point: x=14.000  y= 0.714  hypot=14.018

上面的子类设置 __slots__ 为一个空元组。通过阻止创建实例字典保持了较低的内存开销。

子类化对于添加和存储新的名字域是无效的。应当通过 _fields 创建一个新的命名元组来实现它:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

文档字符串可以自定义,通过直接赋值给 __doc__ 属性:

>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'

在 3.5 版更改: 文档字符串属性变成可写。

OrderedDict 对象

有序词典就像常规词典一样,但有一些与排序操作相关的额外功能。由于内置的 dict 类获得了记住插入顺序的能力(在 Python 3.7 中保证了这种新行为),它们变得不那么重要了。

一些与 dict 的不同仍然存在:

  • 常规的 dict 被设计为非常擅长映射操作。 跟踪插入顺序是次要的。
  • OrderedDict 旨在擅长重新排序操作。 空间效率、迭代速度和更新操作的性能是次要的。
  • 算法上, OrderedDict 可以比 dict 更好地处理频繁的重新排序操作。 这使其适用于跟踪最近的访问(例如在 LRU cache 中)。
  • 对于 OrderedDict ,相等操作检查匹配顺序。
  • OrderedDict 类的 popitem() 方法有不同的签名。它接受一个可选参数来指定弹出哪个元素。
  • OrderedDict 类有一个 move_to_end() 方法,可以有效地将元素移动到任一端。
  • Python 3.8之前, dict 缺少 __reversed__() 方法。

class collections.OrderedDict([items])

返回一个 dict 子类的实例,它具有专门用于重新排列字典顺序的方法。

3.1 新版功能.

  • popitem(last=True)

    有序字典的 popitem() 方法移除并返回一个 (key, value) 键值对。 如果 last 值为真,则按 LIFO 后进先出的顺序返回键值对,否则就按 FIFO 先进先出的顺序返回键值对。

  • move_to_end(key, last=True)

    将现有 key 移动到有序字典的任一端。 如果 last 为真值(默认)则将元素移至末尾;如果 last 为假值则将元素移至开头。如果 key 不存在则会触发 KeyError:

    >>> d = OrderedDict.fromkeys('abcde')
    >>> d.move_to_end('b')
    >>> ''.join(d.keys())
    'acdeb'
    >>> d.move_to_end('b', last=False)
    >>> ''.join(d.keys())
    'bacde'

    3.2 新版功能.

相对于通常的映射方法,有序字典还另外提供了逆序迭代的支持,通过 reversed()

OrderedDict 之间的相等测试是顺序敏感的,实现为 list(od1.items())==list(od2.items())OrderedDict 对象和其他的 Mapping 的相等测试,是顺序敏感的字典测试。这允许 OrderedDict 替换为任何字典可以使用的场所。

在 3.5 版更改: OrderedDict 的项(item),键(key)和值(value) 视图 现在支持逆序迭代,通过 reversed()

在 3.6 版更改: PEP 468 赞成将关键词参数的顺序保留, 通过传递给 OrderedDict 构造器和它的 update() 方法。

在 3.9 版更改: 增加了合并 (|) 与更新 (|=) 运算符,相关说明见 PEP 584

OrderedDict 例子和用法

创建记住键值 最后 插入顺序的有序字典变体很简单。 如果新条目覆盖现有条目,则原始插入位置将更改并移至末尾:

class LastUpdatedOrderedDict(OrderedDict):
    'Store items in the order the keys were last added'
    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        self.move_to_end(key)

一个 OrderedDict 对于实现 functools.lru_cache() 的变体也很有用:

from time import time
class TimeBoundedLRU:
    "LRU Cache that invalidates and refreshes old entries."
    def __init__(self, func, maxsize=128, maxage=30):
        self.cache = OrderedDict()      # { args : (timestamp, result)}
        self.func = func
        self.maxsize = maxsize
        self.maxage = maxage
    def __call__(self, *args):
        if args in self.cache:
            self.cache.move_to_end(args)
            timestamp, result = self.cache[args]
            if time() - timestamp <= self.maxage:
                return result
        result = self.func(*args)
        self.cache[args] = time(), result
        if len(self.cache) > self.maxsize:
            self.cache.popitem(0)
        return result

UserDict 对象

UserDict 类是用作字典对象的外包装。对这个类的需求已部分由直接创建 dict 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字典可以作为属性来访问。

class collections.UserDict([initialdata])

模拟字典的类。 这个实例的内容保存在一个常规字典中,它可以通过 UserDict 实例的 data 属性来访问。 如果提供了 initialdata*,则 data 会用其内容来初始化;请注意对 *initialdata 的引用将不会被保留,以允许它被用于其他目的。

UserDict 实例提供了以下属性作为扩展方法和操作的支持:

  • data

    一个真实的字典,用于保存 UserDict 类的内容。

UserList 对象

这个类封装了列表对象。它是一个有用的基础类,对于你想自定义的类似列表的类,可以继承和覆盖现有的方法,也可以添加新的方法。这样我们可以对列表添加新的行为。

对这个类的需求已部分由直接创建 list 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的列表可以作为属性来访问。

class collections.UserList([list])

模拟一个列表。这个实例的内容被保存为一个正常列表,通过 UserListdata 属性存取。实例内容被初始化为一个 list 的copy,默认为 [] 空列表。 list 可以是迭代对象,比如一个Python列表,或者一个 UserList 对象。

UserList 提供了以下属性作为可变序列的方法和操作的扩展:

  • data

    一个 list 对象用于存储 UserList 的内容。

子类化的要求: UserList 的子类需要提供一个构造器,可以无参数调用,或者一个参数调用。返回一个新序列的列表操作需要创建一个实现类的实例。它假定了构造器可以以一个参数进行调用,这个参数是一个序列对象,作为数据源。

如果一个分离的类不希望依照这个需求,所有的特殊方法就必须重写;请参照源代码进行修改。

UserString 对象

UserString 类是用作字符串对象的外包装。对这个类的需求已部分由直接创建 str 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字符串可以作为属性来访问。

class collections.UserString(seq)

模拟一个字符串对象。这个实例对象的内容保存为一个正常字符串,通过 UserStringdata 属性存取。实例内容初始化设置为 seq 的copy。seq 参数可以是任何可通过内建 str() 函数转换为字符串的对象。

UserString 提供了以下属性作为字符串方法和操作的额外支持:

  • data

    一个真正的 str 对象用来存放 UserString 类的内容。

在 3.5 版更改: 新方法 __getnewargs__, __rmod__, casefold, format_map, isprintable, 和 maketrans

collections.abc —- 容器的抽象基类

3.3 新版功能: 该模块曾是 collections 模块的组成部分。

源代码: Lib/_collections_abc.py


该模块定义了一些 抽象基类,它们可用于判断一个具体类是否具有某一特定的接口;例如,这个类是否可哈希,或其是否为映射类。

An issubclass() or isinstance() test for an interface works in one of three ways.

\1) A newly written class can inherit directly from one of the abstract base classes. The class must supply the required abstract methods. The remaining mixin methods come from inheritance and can be overridden if desired. Other methods may be added as needed:

class C(Sequence):                      # Direct inheritance
    def __init__(self): ...             # Extra method not required by the ABC
    def __getitem__(self, index):  ...  # Required abstract method
    def __len__(self):  ...             # Required abstract method
    def count(self, value): ...         # Optionally override a mixin method

>>> issubclass(C, Sequence)
True
>>> isinstance(C(), Sequence)
True

\2) Existing classes and built-in classes can be registered as “virtual subclasses” of the ABCs. Those classes should define the full API including all of the abstract methods and all of the mixin methods. This lets users rely on issubclass() or isinstance() tests to determine whether the full interface is supported. The exception to this rule is for methods that are automatically inferred from the rest of the API:

class D:                                 # No inheritance
    def __init__(self): ...              # Extra method not required by the ABC
    def __getitem__(self, index):  ...   # Abstract method
    def __len__(self):  ...              # Abstract method
    def count(self, value): ...          # Mixin method
    def index(self, value): ...          # Mixin method
Sequence.register(D)                     # Register instead of inherit


>>> issubclass(D, Sequence)
True
>>> isinstance(D(), Sequence)
True

In this example, class D does not need to define __contains__, __iter__, and __reversed__ because the in-operator, the iteration logic, and the reversed() function automatically fall back to using __getitem__ and __len__.

\3) Some simple interfaces are directly recognizable by the presence of the required methods (unless those methods have been set to None):

class E:
    def __iter__(self): ...
    def __next__(next): ...

>>> issubclass(E, Iterable)
True
>>> isinstance(E(), Iterable)
True

Complex interfaces do not support this last technique because an interface is more than just the presence of method names. Interfaces specify semantics and relationships between methods that cannot be inferred solely from the presence of specific method names. For example, knowing that a class supplies __getitem__, __len__, and __iter__ is insufficient for distinguishing a Sequence from a Mapping.

容器抽象基类

这个容器模块提供了以下 ABCs:

抽象基类 继承自 抽象方法 Mixin 方法
Container **contains**
Hashable **hash**
Iterable **iter**
Iterator Iterable **next** **iter**
Reversible Iterable **reversed**
Generator Iterator send, throw close, **iter**, **next**
Sized **len**
Callable **call**
Collection Sized, Iterable, Container **contains**, **iter**, **len**
Sequence Reversible, Collection **getitem**, **len** **contains**, **iter**, **reversed**, index, and count
MutableSequence Sequence **getitem**, **setitem**, **delitem**, **len**, insert 继承自 Sequence 的方法,以及 append, reverse, extend, pop, remove,和 **iadd**
ByteString Sequence **getitem**, **len** 继承自 Sequence 的方法
Set Collection **contains**, **iter**, **len** **le**, **lt**, **eq**, **ne**, **gt**, **ge**, **and**, **or**, **sub**, **xor**, and isdisjoint
MutableSet Set **contains**, **iter**, **len**, add, discard 继承自 Set 的方法以及 clear, pop, remove, **ior**, **iand**, **ixor**,和 **isub**
Mapping Collection **getitem**, **iter**, **len** **contains**, keys, items, values, get, **eq**, and **ne**
MutableMapping Mapping **getitem**, **setitem**, **delitem**, **iter**, **len** 继承自 Mapping 的方法以及 pop, popitem, clear, update,和 setdefault
MappingView Sized **len**
ItemsView MappingView, Set **contains**, **iter**
KeysView MappingView, Set **contains**, **iter**
ValuesView MappingView, Collection **contains**, **iter**
Awaitable **await**
Coroutine Awaitable send, throw close
AsyncIterable **aiter**
AsyncIterator AsyncIterable **anext** **aiter**
AsyncGenerator AsyncIterator asend, athrow aclose, **aiter**, **anext**

These ABCs override object.__subclasshook__() to support testing an interface by verifying the required methods are present and have not been set to None. This only works for simple interfaces. More complex interfaces require registration or direct subclassing.

Checking isinstance(obj, Iterable) detects classes that are registered as Iterable or that have an __iter__() method, but it does not detect classes that iterate with the __getitem__() method. The only reliable way to determine whether an object is iterable is to call iter(obj).

Collections Abstract Base Classes — Detailed Descriptions

class collections.abc.Container

提供了 __contains__() 方法的抽象基类。

class collections.abc.Hashable

提供了 __hash__() 方法的抽象基类。

class collections.abc.Sized

提供了 __len__() 方法的抽象基类。

class collections.abc.Callable

提供了 __call__() 方法的抽象基类。

class collections.abc.Iterable

提供了 __iter__() 方法的抽象基类。

使用 isinstance(obj, Iterable) 可以检测一个类是否已经注册到了 Iterable 或者实现了 __iter__() 函数,但是无法检测这个类是否能够使用 __getitem__() 方法进行迭代。检测一个对象是否是 iterable 的唯一可信赖的方法是调用 iter(obj)

class collections.abc.Collection

集合了 Sized 和 Iterable 类的抽象基类。

3.6 新版功能.

class collections.abc.Iterator

提供了 __iter__()__next__() 方法的抽象基类。参见 iterator 的定义。

class collections.abc.Reversible

为可迭代类提供了 __reversed__() 方法的抽象基类。

3.6 新版功能.

class collections.abc.Generator

生成器类,实现了 PEP 342 中定义的协议,继承并扩展了迭代器,提供了 send(), throw()close() 方法。

3.5 新版功能.

class collections.abc.Sequence

class collections.abc.MutableSequence

class collections.abc.ByteString

只读且可变的序列 sequences 的抽象基类。

实现笔记:一些混入(Maxin)方法比如 __iter__(), __reversed__()index() 会重复调用底层的 __getitem__() 方法。因此,如果实现的 __getitem__() 是常数级访问速度,那么相应的混入方法会有一个线性的表现;然而,如果底层方法是线性实现(例如链表),那么混入方法将会是平方级的表现,这也许就需要被重构了。

在 3.5 版更改: index() 方法支持 stopstart 参数。

class collections.abc.Set

class collections.abc.MutableSet

只读且可变的集合的抽象基类。

class collections.abc.Mapping

class collections.abc.MutableMapping

只读且可变的映射 mappings 的抽象基类。

class collections.abc.MappingView

class collections.abc.ItemsView

class collections.abc.KeysView

class collections.abc.ValuesView

映射及其键和值的视图 views 的抽象基类。

class collections.abc.Awaitable

为可等待对象 awaitable 提供的类,可以被用于 await 表达式中。习惯上必须实现 __await__() 方法。

协程 对象和 Coroutine ABC 的实例都是这个 ABC 的实例。

注解

在 CPython 里,基于生成器的协程(使用 types.coroutine()asyncio.coroutine() 包装的生成器)都是 可等待对象,即使他们不含有 __await__() 方法。使用 isinstance(gencoro, Awaitable) 来检测他们会返回 False。要使用 inspect.isawaitable() 来检测他们。

3.5 新版功能.

class collections.abc.Coroutine

用于协程兼容类的抽象基类。实现了如下定义在 协程对象: 里的方法: send()throw()close()。通常的实现里还需要实现 __await__() 方法。所有的 Coroutine 实例都必须是 Awaitable 实例。

注解

在 CPython 里,基于生成器的协程(使用 types.coroutine()asyncio.coroutine() 包装的生成器)都是 可等待对象,即使他们不含有 __await__() 方法。使用 isinstance(gencoro, Coroutine) 来检测他们会返回 False。要使用 inspect.isawaitable() 来检测他们。

3.5 新版功能.

class collections.abc.AsyncIterable

提供了 __aiter__ 方法的抽象基类。

3.5 新版功能.

class collections.abc.AsyncIterator

提供了 __aiter____anext__ 方法的抽象基类。

3.5 新版功能.

class collections.abc.AsyncGenerator

为异步生成器类提供的抽象基类,这些类实现了定义在 PEP 525PEP 492 里的协议。

3.6 新版功能.

Examples and Recipes

ABCs allow us to ask classes or instances if they provide particular functionality, for example:

size = None
if isinstance(myvar, collections.abc.Sized):
    size = len(myvar)

有些抽象基类也可以用作混入类(mixin),这可以更容易地开发支持容器 API 的类。例如,要写一个支持完整 Set API 的类,只需要提供下面这三个方法: __contains__(), __iter__()__len__()。抽象基类会补充上其余的方法,比如 __and__()isdisjoint():

class ListBasedSet(collections.abc.Set):
    ''' Alternate set implementation favoring space over speed
        and not requiring the set elements to be hashable. '''
    def __init__(self, iterable):
        self.elements = lst = []
        for value in iterable:
            if value not in lst:
                lst.append(value)
    def __iter__(self):
        return iter(self.elements)
    def __contains__(self, value):
        return value in self.elements
    def __len__(self):
        return len(self.elements)
s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2            # The __and__() method is supported automatically

当把 SetMutableSet 用作混入类时需注意:

  1. 由于某些集合操作会创建新集合,默认的混入方法需要一种从可迭代对象里创建新实例的方式。 假定类构造器具有 ClassName(iterable) 形式的签名。 这样它将执行一个名为 _from_iterable() 的内部类方法,该方法会调用 cls(iterable) 来产生一个新集合。 如果 Set 混入类在具有不同构造器签名的类中被使用,你将需要通过类方法或常规方法来重载 _from_iterable(),以便基于可迭代对象参数来构造新的实例。
  2. 重载比较符时时(想必是为了速度,因为其语义都是固定的),只需要重定义 __le__()__ge__() 函数,然后其他的操作会自动跟进。
  3. 混入集合类 Set 提供了一个 _hash() 方法为集合计算哈希值,然而, __hash__() 函数却没有被定义,因为并不是所有集合都是可哈希并且不可变的。为了使用混入类为集合添加哈希能力,可以同时继承 Set()Hashable() 类,然后定义 __hash__ = Set._hash

heapq —- 堆队列算法

源码:Lib/heapq.py


这个模块提供了堆队列算法的实现,也称为优先队列算法。

堆是一个二叉树,它的每个父节点的值都只会小于或等于所有孩子节点(的值)。 它使用了数组来实现:从零开始计数,对于所有的 k ,都有 heap[k] <= heap[2*k+1]heap[k] <= heap[2*k+2]。 为了便于比较,不存在的元素被认为是无限大。 堆最有趣的特性在于最小的元素总是在根结点:heap[0]

这个API与教材的堆算法实现有所不同,具体区别有两方面:(a)我们使用了从零开始的索引。这使得节点和其孩子节点索引之间的关系不太直观但更加适合,因为 Python 使用从零开始的索引。 (b)我们的 pop 方法返回最小的项而不是最大的项(这在教材中称为“最小堆”;而“最大堆”在教材中更为常见,因为它更适用于原地排序)。

基于这两方面,把堆看作原生的Python list也没什么奇怪的: heap[0] 表示最小的元素,同时 heap.sort() 维护了堆的不变性!

要创建一个堆,可以使用list来初始化为 [] ,或者你可以通过一个函数 heapify() ,来把一个list转换成堆。

定义了以下函数:

heapq.heappush(heap, item)

item 的值加入 heap 中,保持堆的不变性。

heapq.heappop(heap)

弹出并返回 heap 的最小的元素,保持堆的不变性。如果堆为空,抛出 IndexError 。使用 heap[0] ,可以只访问最小的元素而不弹出它。

heapq.heappushpop(heap, item)

item 放入堆中,然后弹出并返回 heap 的最小元素。该组合操作比先调用 heappush() 再调用 heappop() 运行起来更有效率。

heapq.heapify(x)

将list x 转换成堆,原地,线性时间内。

heapq.heapreplace(heap, item)

弹出并返回 heap 中最小的一项,同时推入新的 item。 堆的大小不变。 如果堆为空则引发 IndexError

这个单步骤操作比 heappop()heappush() 更高效,并且在使用固定大小的堆时更为适宜。 pop/push 组合总是会从堆中返回一个元素并将其替换为 item

返回的值可能会比添加的 item 更大。 如果不希望如此,可考虑改用 heappushpop()。 它的 push/pop 组合会返回两个值中较小的一个,将较大的值留在堆中。

该模块还提供了三个基于堆的通用功能函数。

heapq.merge(\iterables, key=None, reverse=False*)

将多个已排序的输入合并为一个已排序的输出(例如,合并来自多个日志文件的带时间戳的条目)。 返回已排序值的 iterator。

类似于 sorted(itertools.chain(*iterables)) 但返回一个可迭代对象,不会一次性地将数据全部放入内存,并假定每个输入流都是已排序的(从小到大)。

具有两个可选参数,它们都必须指定为关键字参数。

key 指定带有单个参数的 key function,用于从每个输入元素中提取比较键。 默认值为 None (直接比较元素)。

reverse 为一个布尔值。 如果设为 True,则输入元素将按比较结果逆序进行合并。 要达成与 sorted(itertools.chain(*iterables), reverse=True) 类似的行为,所有可迭代对象必须是已从大到小排序的。

在 3.5 版更改: 添加了可选的 keyreverse 形参。

heapq.nlargest(n, iterable, key=None)

iterable 所定义的数据集中返回前 n 个最大元素组成的列表。 如果提供了 key 则其应指定一个单参数的函数,用于从 iterable 的每个元素中提取比较键 (例如 key=str.lower)。 等价于: sorted(iterable, key=key, reverse=True)[:n]

heapq.nsmallest(n, iterable, key=None)

iterable 所定义的数据集中返回前 n 个最小元素组成的列表。 如果提供了 key 则其应指定一个单参数的函数,用于从 iterable 的每个元素中提取比较键 (例如 key=str.lower)。 等价于: sorted(iterable, key=key)[:n]

后两个函数在 n 值较小时性能最好。 对于更大的值,使用 sorted() 函数会更有效率。 此外,当 n==1 时,使用内置的 min()max() 函数会更有效率。 如果需要重复使用这些函数,请考虑将可迭代对象转为真正的堆。

基本示例

堆排序 可以通过将所有值推入堆中然后每次弹出一个最小值项来实现。

>>> def heapsort(iterable):
...     h = []
...     for value in iterable:
...         heappush(h, value)
...     return [heappop(h) for i in range(len(h))]
...
>>> heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

这类似于 sorted(iterable),但与 sorted() 不同的是这个实现是不稳定的。

堆元素可以为元组。 这适用于将比较值(例如任务优先级)与跟踪的主记录进行赋值的场合:

>>> h = []
>>> heappush(h, (5, 'write code'))
>>> heappush(h, (7, 'release product'))
>>> heappush(h, (1, 'write spec'))
>>> heappush(h, (3, 'create tests'))
>>> heappop(h)
(1, 'write spec')

优先队列实现说明

优先队列 是堆的常用场合,并且它的实现包含了多个挑战:

  • 排序稳定性:你该如何令相同优先级的两个任务按它们最初被加入时的顺序返回?
  • 如果优先级相同且任务没有默认比较顺序,则 (priority, task) 对的元组比较将会中断。
  • 如果任务优先级发生改变,你该如何将其移至堆中的新位置?
  • 或者如果一个挂起的任务需要被删除,你该如何找到它并将其移出队列?

针对前两项挑战的一种解决方案是将条目保存为包含优先级、条目计数和任务对象 3 个元素的列表。 条目计数可用来打破平局,这样具有相同优先级的任务将按它们的添加顺序返回。 并且由于没有哪两个条目计数是相同的,元组比较将永远不会直接比较两个任务。

不可比较任务问题的另一种解决方案是创建一个忽略任务条目并且只比较优先级字段的包装器类:

from dataclasses import dataclass, field
from typing import Any
@dataclass(order=True)
class PrioritizedItem:
    priority: int
    item: Any=field(compare=False)

其余的挑战主要包括找到挂起的任务并修改其优先级或将其完全移除。 找到一个任务可使用一个指向队列中条目的字典来实现。

移除条目或改变其优先级的操作实现起来更为困难,因为它会破坏堆结构不变量。 因此,一种可能的解决方案是将条目标记为已移除,再添加一个改变了优先级的新条目:

pq = []                         # list of entries arranged in a heap
entry_finder = {}               # mapping of tasks to entries
REMOVED = '<removed-task>'      # placeholder for a removed task
counter = itertools.count()     # unique sequence count
def add_task(task, priority=0):
    'Add a new task or update the priority of an existing task'
    if task in entry_finder:
        remove_task(task)
    count = next(counter)
    entry = [priority, count, task]
    entry_finder[task] = entry
    heappush(pq, entry)
def remove_task(task):
    'Mark an existing task as REMOVED.  Raise KeyError if not found.'
    entry = entry_finder.pop(task)
    entry[-1] = REMOVED
def pop_task():
    'Remove and return the lowest priority task. Raise KeyError if empty.'
    while pq:
        priority, count, task = heappop(pq)
        if task is not REMOVED:
            del entry_finder[task]
            return task
    raise KeyError('pop from an empty priority queue')

理论

堆是通过数组来实现的,其中的元素从 0 开始计数,对于所有的 k 都有 a[k] <= a[2*k+1]a[k] <= a[2*k+2]。 为了便于比较,不存在的元素被视为无穷大。 堆最有趣的特性在于 a[0] 总是其中最小的元素。

上面的特殊不变量是用来作为一场锦标赛的高效内存表示。 下面的数字是 k 而不是 a[k]:

                               0
              1                                 2
      3               4                5               6
  7       8       9       10      11      12      13      14
15 16   17 18   19 20   21 22   23 24   25 26   27 28   29 30

在上面的树中,每个 k 单元都位于 2*k+12*k+2 之上。 体育运动中我们经常见到二元锦标赛模式,每个胜者单元都位于另两个单元之上,并且我们可以沿着树形图向下追溯胜者所遇到的所有对手。 但是,在许多采用这种锦标赛模式的计算机应用程序中,我们并不需要追溯胜者的历史。 为了获得更高的内存利用效率,当一个胜者晋级时,我们会用较低层级的另一条目来替代它,因此规则变为一个单元和它之下的两个单元包含三个不同条目,上方单元“胜过”了两个下方单元。

如果此堆的不变量始终受到保护,则序号 0 显然是最后的赢家。 删除它并找出“下一个”赢家的最简单算法方式是家某个输家(让我们假定是上图中的 30 号单元)移至 0 号位置,然后将这个新的 0 号沿树下行,不断进行值的交换,直到不变量重新建立。 这显然会是树中条目总数的对数。 通过迭代所有条目,你将得到一个 O(n log n) 复杂度的排序。

此排序有一个很好的特性就是你可以在排序进行期间高效地插入新条目,前提是插入的条目不比你最近取出的 0 号元素“更好”。 这在模拟上下文时特别有用,在这种情况下树保存的是所有传入事件,“胜出”条件是最小调度时间。 当一个事件将其他事件排入执行计划时,它们的调试时间向未来方向延长,这样它们可方便地入堆。 因此,堆结构很适宜用来实现调度器,我的 MIDI 音序器就是用的这个 :-)。

用于实现调度器的各种结构都得到了充分的研究,堆是非常适宜的一种,因为它们的速度相当快,并且几乎是恒定的,最坏的情况与平均情况没有太大差别。 虽然还存在其他总体而言更高效的实现方式,但其最坏的情况却可能非常糟糕。

堆在大磁盘排序中也非常有用。 你应该已经了解大规模排序会有多个“运行轮次”(即预排序的序列,其大小通常与 CPU 内存容量相关),随后这些轮次会进入合并通道,轮次合并的组织往往非常巧妙。 非常重要的一点是初始排序应产生尽可能长的运行轮次。 锦标赛模式是达成此目标的好办法。 如果你使用全部有用内存来进行锦标赛,替换和安排恰好适合当前运行轮次的条目,你将可以对于随机输入生成两倍于内存大小的运行轮次,对于模糊排序的输入还会有更好的效果。

另外,如果你输出磁盘上的第 0 个条目并获得一个可能不适合当前锦标赛的输入(因为其值要“胜过”上一个输出值),它无法被放入堆中,因此堆的尺寸将缩小。 被释放的内存可以被巧妙地立即重用以逐步构建第二个堆,其增长速度与第一个堆的缩减速度正好相同。 当第一个堆完全消失时,你可以切换新堆并启动新的运行轮次。 这样做既聪明又高效!

总之,堆是值得了解的有用内存结构。 我在一些应用中用到了它们,并且认为保留一个 ‘heap’ 模块是很有意义的。 :-)

bisect —- 数组二分查找算法

源代码: Lib/bisect.py


这个模块对有序列表提供了支持,使得他们可以在插入新数据仍然保持有序。对于长列表,如果其包含元素的比较操作十分昂贵的话,这可以是对更常见方法的改进。这个模块叫做 bisect 因为其使用了基本的二分(bisection)算法。源代码也可以作为很棒的算法示例(边界判断也做好啦!)

定义了以下函数:

bisect.bisect_left(a, x, lo=0, hi=len(a), **, key=None*)

a 中找到 x 合适的插入点以维持有序。参数 lohi 可以被用于确定需要考虑的子集;默认情况下整个列表都会被使用。如果 x 已经在 a 里存在,那么插入点会在已存在元素之前(也就是左边)。如果 a 是列表(list)的话,返回值是可以被放在 list.insert() 的第一个参数的。

返回的插入点 i 将数组 a 分成两半,使得 all(val < x for val in a[lo : i]) 在左半边而 all(val >= x for val in a[i : hi]) 在右半边。

key 指定带有单个参数的 key function,用于从每个输入元素中提取比较键。 默认值为 None (直接比较元素)。

在 3.10 版更改: 增加了 key 形参。

bisect.bisect_right(a, x, lo=0, hi=len(a), **, key=None*)

bisect.bisect(a, x, lo=0, hi=len(a))

类似于 bisect_left(),但是返回的插入点是 a 中已存在元素 x 的右侧。

返回的插入点 i 将数组 a 分成两半,使得左半边为 all(val <= x for val in a[lo : i]) 而右半边为 all(val > x for val in a[i : hi])

key 指定带有单个参数的 key function,用于从每个输入元素中提取比较键。 默认值为 None (直接比较元素)。

在 3.10 版更改: 增加了 key 形参。

bisect.insort_left(a, x, lo=0, hi=len(a), **, key=None*)

按照已排序顺序将 x 插入到 a 中。

key 指定带有单个参数的 key function,用于从每个输入元素中提取比较键。 默认值为 None (直接比较元素)。

此函数首先会运行 bisect_left() 来定位一个插入点。 然后,它会在 a 上运行 insert() 方法在正确的位置插入 x 以保持排序顺序。

请记住 O(log n) 搜索是由缓慢的 O(n) 抛入步骤主导的。

在 3.10 版更改: 增加了 key 形参。

bisect.insort_right(a, x, lo=0, hi=len(a), **, key=None*)

bisect.insort(a, x, lo=0, hi=len(a))

类似于 insort_left(),但是把 x 插入到 a 中已存在元素 x 的右侧。

key 指定带有单个参数的 key function,用于从每个输入元素中提取比较键。 默认值为 None (直接比较元素)。

此函数首先会运行 bisect_right() 来定位一个插入点。 然后,它会在 a 上运行 insert() 方法在正确的位置插入 x 以保持排序顺序。

请记住 O(log n) 搜索是由缓慢的 O(n) 抛入步骤主导的。

在 3.10 版更改: 增加了 key 形参。

性能说明

当使用 bisect()insort() 编写时间敏感的代码时,请记住以下概念。

  • 二分法对于搜索一定范围的值是很高效的。 对于定位特定的值,则字典的性能更好。
  • insort() 函数的时间复杂度为 O(n) 因为对数时间的搜索步骤被线性时间的插入步骤所主导。
  • 这些搜索函数都是无状态的并且会在它们被使用后丢弃键函数的结果。 因此,如果在一个循环中使用搜索函数,则键函数可能会在同一个数据元素上被反复调用。 如果键函数速度不快,请考虑用 functools.cache() 来包装它以避免重复计算。 另外,也可以考虑搜索一个预先计算好的键数组来定位插入点(如下面的示例节所演示的)。

搜索有序列表

上面的 bisect() 函数对于找到插入点是有用的,但在一般的搜索任务中可能会有点尴尬。下面 5 个函数展示了如何将其转变成有序列表中的标准查找函数

def index(a, x):
    'Locate the leftmost value exactly equal to x'
    i = bisect_left(a, x)
    if i != len(a) and a[i] == x:
        return i
    raise ValueError
def find_lt(a, x):
    'Find rightmost value less than x'
    i = bisect_left(a, x)
    if i:
        return a[i-1]
    raise ValueError
def find_le(a, x):
    'Find rightmost value less than or equal to x'
    i = bisect_right(a, x)
    if i:
        return a[i-1]
    raise ValueError
def find_gt(a, x):
    'Find leftmost value greater than x'
    i = bisect_right(a, x)
    if i != len(a):
        return a[i]
    raise ValueError
def find_ge(a, x):
    'Find leftmost item greater than or equal to x'
    i = bisect_left(a, x)
    if i != len(a):
        return a[i]
    raise ValueError

例子

函数 bisect() 还可以用于数字表查询。这个例子是使用 bisect() 从一个给定的考试成绩集合里,通过一个有序数字表,查出其对应的字母等级:90 分及以上是 ‘A’,80 到 89 是 ‘B’,以此类推

>>> def grade(score, breakpoints=[60, 70, 80, 90], grades='FDCBA'):
...     i = bisect(breakpoints, score)
...     return grades[i]
...
>>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
['F', 'A', 'C', 'C', 'B', 'A', 'A']

一种避免重复调用键函数的技巧是搜索一个预先计算好的键函数列表来找出记录的索引:

>>> data = [('red', 5), ('blue', 1), ('yellow', 8), ('black', 0)]
>>> data.sort(key=lambda r: r[1])       # Or use operator.itemgetter(1).
>>> keys = [r[1] for r in data]         # Precompute a list of keys.
>>> data[bisect_left(keys, 0)]
('black', 0)
>>> data[bisect_left(keys, 1)]
('blue', 1)
>>> data[bisect_left(keys, 5)]
('red', 5)
>>> data[bisect_left(keys, 8)]
('yellow', 8)

array — 高效的数值数组

此模块定义了一种对象类型,可以紧凑地表示基本类型值的数组:字符、整数、浮点数等。 数组属于序列类型,其行为与列表非常相似,不同之处在于其中存储的对象类型是受限的。 类型在对象创建时使用单个字符的 类型码 来指定。 已定义的类型码如下:

类型码 C 类型 Python 类型 以字节表示的最小尺寸 备注
‘b’ signed char int 1
‘B’ unsigned char int 1
‘u’ wchar_t Unicode 字符 2 (1)
‘h’ signed short int 2
‘H’ unsigned short int 2
‘i’ signed int int 2
‘I’ unsigned int int 2
‘l’ signed long int 4
‘L’ unsigned long int 4
‘q’ signed long long int 8
‘Q’ unsigned long long int 8
‘f’ float float 4
‘d’ double float 8

注释:

  1. 由于平台的不同它可能为 16 位或 32 位。

    在 3.9 版更改: array('u') 现在使用 wchar_t 作为 C 类型而不再是已弃用的 Py_UNICODE。 这个改变不会影响其行为,因为 Py_UNICODE 自 Python 3.3 起就是 wchar_t 的别名。

    Deprecated since version 3.3, will be removed in version 4.0.

值的实际表示会由机器的架构决定(严格地说是由 C 实现决定)。 实际大小可通过 itemsize 属性来获取。

这个模块定义了以下类型:

class array.array(typecode[, initializer])

一个包含由 typecode 限制类型的条目的新数组,并由可选的 initializer 值进行初始化,该值必须为一个列表、bytes-like object 或包含正确类型元素的可迭代对象。

如果给定一个列表或字符串,该 initializer 会被传给新数组的 fromlist(), frombytes()fromunicode() 方法(见下文)以将初始条目添加到数组中。 否则会将可迭代对象作为 initializer 传给 extend() 方法。

引发一个 审计事件 array.__new__ 附带参数 typecode, initializer

array.typecodes

一个包含所有可用类型码的字符串。

数组对象支持普通的序列操作如索引、切片、拼接和重复等。 当使用切片赋值时,所赋的值必须为具有相同类型码的数组对象;所有其他情况都将引发 TypeError。 数组对象也实现了缓冲区接口,可以用于所有支持 字节类对象 的场合。

以下数据项和方法也受到支持:

array.typecode

用于创建数组的类型码字符。

array.itemsize

在内部表示中一个数组项的字节长度。

array.append(x)

添加一个值为 x 的新项到数组末尾。

array.buffer_info()

返回一个元组 (address, length) 以给出用于存放数组内容的缓冲区元素的当前内存地址和长度。 以字节表示的内存缓冲区大小可通过 array.buffer_info()[1] * array.itemsize 来计算。 这在使用需要内存地址的低层级(因此不够安全) I/O 接口时会很有用,例如某些 ioctl() 操作。 只要数组存在并且没有应用改变长度的操作,返回数值就是有效的。

注解

当在 C 或 C++ 编写的代码中使用数组对象时(这是有效使用此类信息的唯一方式),使用数组对象所支持的缓冲区接口更为适宜。 此方法仅保留用作向下兼容,应避免在新代码中使用。

array.byteswap()

“字节对调”所有数组项。 此方法只支持大小为 1, 2, 4 或 8 字节的值;对于其他值类型将引发 RuntimeError。 它适用于从不同字节序机器所生成的文件中读取数据的情况。

array.count(x)

返回 x 在数组中的出现次数。

array.extend(iterable)

将来自 iterable 的项添加到数组末尾。 如果 iterable 是另一个数组,它必须具有 完全 相同的类型码;否则将引发 TypeError。 如果 iterable 不是一个数组,则它必须为可迭代对象并且其元素必须为可添加到数组的适当类型。

array.frombytes(s)

添加来自字符串的项,将字符串解读为机器值的数组(相当于使用 fromfile() 方法从文件中读取数据)。

3.2 新版功能: fromstring() 重命名为 frombytes() 以使其含义更清晰。

array.fromfile(f, n)

从 file object f 中读取 n 项并将它们添加到数组末尾。 如果可用数据少于 n 项,则会引发 EOFError,但可用的项仍然会被插入数组。

array.fromlist(list)

添加来自 list 的项。 这等价于 for x in list: a.append(x),区别在于如果发生类型错误,数组将不会被改变。

array.fromunicode(s)

使用来自给定 Unicode 字符串的数组扩展数组。 数组必须是类型为 'u' 的数组;否则将引发 ValueError。 请使用 array.frombytes(unicodestring.encode(enc)) 来将 Unicode 数据添加到其他类型的数组。

array.index(x[, start[, stop]])

返回最小的 i 使得 i 为数组中首次出现的 x 的索引号。 指定可选参数 startstop 以便在数组的一个子部分内部搜索 x。 如果未找到 x 则会引发 ValueError

在 3.10 版更改: 添加了可选的 startstop 形参。

array.insert(i, x)

将值 x 作为新项插入数组的 i 位置之前。 负值将被视为相对于数组末尾的位置。

array.pop([i])

从数组中移除序号为 i 的项并将其返回。 可选参数值默认为 -1,因此默认将移除并返回末尾项。

array.remove(x)

从数组中移除首次出现的 x

array.reverse()

反转数组中各项的顺序。

array.tobytes()

将数组转换为一个机器值数组并返回其字节表示(即相当与通过 tofile() 方法写入到文件的字节序列。)

3.2 新版功能: tostring() 被重命名为 tobytes() 以使其含义更清晰。

array.tofile(f)

将所有项(作为机器值)写入到 file object f

array.tolist()

将数组转换为包含相同项的普通列表。

array.tounicode()

将数组转换为一个 Unicode 字符串。 数组必须是类型为 'u' 的数组;否则将引发 ValueError。 请使用 array.tobytes().decode(enc) 来从其他类型的数组生成 Unicode 字符串。

当一个数组对象被打印或转换为字符串时,它会表示为 array(typecode, initializer)。 如果数组为空则 initializer 会被省略,否则如果 typecode'u' 则它是一个字符串,否则它是一个数字列表。 使用 eval() 保证能将字符串转换回具有相同类型和值的数组,只要 array 类已通过 from array import array 被引入。 例如:

array('l')
array('u', 'hello \u2641')
array('l', [1, 2, 3, 4, 5])
array('d', [1.0, 2.0, 3.14])

weakref —- 弱引用

源码: Lib/weakref.py


weakref 模块允许Python程序员创建对象的 weak references

在下文中,术语 referent 表示由弱引用引用的对象。

对对象的弱引用不能保证对象存活:当对像的引用只剩弱引用时, garbage collection 可以销毁引用并将其内存重用于其他内容。但是,在实际销毁对象之前,即使没有强引用,弱引用也一直能返回该对象。

弱引用的主要用途是实现保存大对象的高速缓存或映射,但又不希望大对象仅仅因为它出现在高速缓存或映射中而保持存活。

例如,如果您有许多大型二进制图像对象,则可能希望将名称与每个对象关联起来。如果您使用Python字典将名称映射到图像,或将图像映射到名称,则图像对象将保持活动状态,因为它们在字典中显示为值或键。 weakref 模块提供的 WeakKeyDictionaryWeakValueDictionary 类可以替代Python字典,使用弱引用来构造映射,这些映射不会仅仅因为它们出现在映射对象中而使对象保持存活。例如,如果一个图像对象是 WeakValueDictionary 中的值,那么当对该图像对象的剩余引用是弱映射对象所持有的弱引用时,垃圾回收可以回收该对象并将其在弱映射对象中相应的条目删除。

WeakKeyDictionaryWeakValueDictionary 在它们的实现中使用弱引用,在弱引用上设置回调函数,当键或值被垃圾回收回收时通知弱字典。 WeakSet 实现了 set 接口,但像 WeakKeyDictionary 一样,只持有其元素的弱引用。

finalize 提供了注册一个对象被垃圾收集时要调用的清理函数的方式。这比在原始弱引用上设置回调函数更简单,因为模块会自动确保对象被回收前终结器一直保持存活。

这些弱容器类型之一或者 finalize 就是大多数程序所需要的 - 通常不需要直接创建自己的弱引用。weakref 模块暴露了低级机制,以便于高级用途。

并非所有对象都可以被弱引用;可以被弱引用的对象包括类实例,用 Python(而不是用 C)编写的函数,实例方法、集合、冻结集合,某些 文件对象,生成器,类型对象,套接字,数组,双端队列,正则表达式模式对象以及代码对象等。

在 3.2 版更改: 添加了对thread.lock,threading.Lock和代码对象的支持。

几个内建类型如 listdict 不直接支持弱引用,但可以通过子类化添加支持:

class Dict(dict):
    pass
obj = Dict(red=1, green=2, blue=3)   # this object is weak referenceable

CPython implementation detail: 其他内置类型例如 tupleint 不支持弱引用,即使通过子类化也不支持。

Extension types can easily be made to support weak references; see Weak Reference Support.

class weakref.ref(object[, callback])

返回对 对象 的弱引用。如果原始对象仍然存活,则可以通过调用引用对象来检索原始对象;如果引用的原始对象不再存在,则调用引用对象将得到 None 。如果提供了 回调 而且值不是 None ,并且返回的弱引用对象仍然存活,则在对象即将终结时将调用回调;弱引用对象将作为回调的唯一参数传递;指示物将不再可用。

许多弱引用也允许针对相同对象来构建。 为每个弱引用注册的回调将按从最近注册的回调到最早注册的回调的顺序被调用。

回调所引发的异常将记录于标准错误输出,但无法被传播;它们会按与对象的 __del__() 方法所引发的异常相同的方式被处理。

如果 object 可哈希,则弱引用也为 hashable。 即使在 object 被删除之后它们仍将保持其哈希值。 如果 hash()object 被删除之后才首次被调用,则该调用将引发 TypeError

弱引用支持相等检测,但不支持排序比较。 如果被引用对象仍然存在,两个引用具有与它们的被引用对象一致的相等关系(无论 callback 是否相同)。 如果删除了任一被引用对象,则仅在两个引用对象为同一对象时两者才相等。

这是一个可子类化的类型而非一个工厂函数。

  • __callback__

    这个只读属性会返回当前关联到弱引用的回调。 如果回调不存在或弱引用的被引用对象已不存在,则此属性的值为 None

在 3.4 版更改: 添加了 __callback__ 属性。

weakref.proxy(object[, callback])

返回 object 的一个使用弱引用的代理。 此函数支持在大多数上下文中使用代理,而不要求显式地对所使用的弱引用对象解除引用。 返回的对象类型将为 ProxyTypeCallableProxyType,具体取决于 object 是否可调用。 Proxy 对象不是 hashable 对象,无论被引用对象是否可哈希;这可避免与它们的基本可变性质相关的多种问题,并可防止它们被用作字典键。 callbackref() 函数的同名形参含义相同。

在 3.8 版更改: 扩展代理对象所支持的运算符,包括矩阵乘法运算符 @@=

weakref.getweakrefcount(object)

返回指向 object 的弱引用和代理的数量。

weakref.getweakrefs(object)

返回由指向 object 的所有弱引用和代理构成的列表。

class weakref.WeakKeyDictionary([dict])

弱引用键的映射类。 当不再存在对键的强引用时,字典中的条目将被丢弃。 这可被用来将额外数据关联到一个应用中其他部分所拥有的对象而无需在那些对象中添加属性。 这对于重载了属性访问的对象来说特别有用。

在 3.9 版更改: 增加了对 ||= 运算符的支持,相关说明见 PEP 584

WeakKeyDictionary 对象具有一个额外方法可以直接公开内部引用。 这些引用不保证在它们被使用时仍然保持“存活”,因此这些引用的调用结果需要在使用前进行检测。 此方法可用于避免创建会导致垃圾回收器将保留键超出实际需要时长的引用。

WeakKeyDictionary.keyrefs()

返回包含对键的弱引用的可迭代对象。

class weakref.WeakValueDictionary([dict])

弱引用值的映射类。 当不再存在对该值的强引用时,字典中的条目将被丢弃。

在 3.9 版更改: 增加了对 ||= 运算符的支持,相关说明见 PEP 584

WeakValueDictionary 对象具有一个额外方法,此方法存在与 WeakKeyDictionary 对象的 keyrefs() 方法相同的问题。

WeakValueDictionary.valuerefs()

返回包含对值的弱引用的可迭代对象。

class weakref.WeakSet([elements])

保持对其元素弱引用的集合类。 当不再有对某个元素的强引用时元素将被丢弃。

class weakref.WeakMethod(method)

一个模拟对绑定方法(即在类中定义并在实例中查找的方法)进行弱引用的自定义 ref 子类。 由于绑定方法是临时性的,标准弱引用无法保持它。 WeakMethod 包含特别代码用来重新创建绑定方法,直到对象或初始函数被销毁:

>>> class C:
...     def method(self):
...         print("method called!")
...
>>> c = C()
>>> r = weakref.ref(c.method)
>>> r()
>>> r = weakref.WeakMethod(c.method)
>>> r()
<bound method C.method of <__main__.C object at 0x7fc859830220>>
>>> r()()
method called!
>>> del c
>>> gc.collect()
0
>>> r()
>>>

3.4 新版功能.

class weakref.finalize(obj, func, /, \args, *kwargs)

返回一个可调用的终结器对象,该对象将在 obj 作为垃圾回收时被调用。 与普通的弱引用不同,终结器将总是存活,直到引用对象被回收,这极大地简化了生存期管理。

终结器总是被视为 存活 直到它被调用(显式调用或在垃圾回收时隐式调用),调用之后它将 死亡。 调用存活的终结器将返回 func(*arg, **kwargs) 的求值结果,而调用死亡的终结器将返回 None

在垃圾收集期间由终结器回调所引发异常将显示于标准错误输出,但无法被传播。 它们会按与对象的 __del__() 方法或弱引用的回调所引发异常相同的方式被处理。

当程序退出时,剩余的存活终结器会被调用,除非它们的 atexit 属性已被设为假值。 它们会按与创建时相反的顺序被调用。

终结器在 interpreter shutdown 的后期绝不会发起调用其回调函数,此时模块全局变量很可能已被替换为 None

  • __call__()

    如果 self 为存活状态则将其标记为已死亡,并返回调用 func(*args, **kwargs) 的结果。 如果 self 已死亡则返回 None

  • detach()

    如果 self 为存活状态则将其标记为已死亡,并返回元组 (obj, func, args, kwargs)。 如果 self 已死亡则返 None

  • peek()

    如果 self 为存活状态则返回元组 (obj, func, args, kwargs)。 如果 self 已死亡则返回 None

  • alive

    如果终结器为存活状态则该特征属性为真值,否则为假值。

  • atexit

    一个可写的布尔型特征属性,默认为真值。 当程序退出时,它会调用所有 atexit 为真值的剩余存活终结器。 它们会按与创建时相反的顺序被调用。

注解

很重要的一点是确保 func, argskwargs 不拥有任何对 obj 的引用,无论是直接的或是间接的,否则的话 obj 将永远不会被作为垃圾回收。 特别地,func 不应当是 obj 的一个绑定方法。

3.4 新版功能.

weakref.ReferenceType

弱引用对象的类型对象。

weakref.ProxyType

不可调用对象的代理的类型对象。

weakref.CallableProxyType

可调用对象的代理的类型对象。

weakref.ProxyTypes

包含所有代理的类型对象的序列。 这可以用于更方便地检测一个对象是否是代理,而不必依赖于两种代理对象的名称。

参见

PEP 205 - 弱引用

此特性的提议和理由,包括早期实现的链接和其他语言中类似特性的相关信息。

弱引用对象

弱引用对象没有 ref.__callback__ 以外的方法和属性。 一个弱引用对象如果存在,就允许通过调用它来获取引用:

>>> import weakref
>>> class Object:
...     pass
...
>>> o = Object()
>>> r = weakref.ref(o)
>>> o2 = r()
>>> o is o2
True

如果引用已不存在,则调用引用对象将返回 None:

>>> del o, o2
>>> print(r())
None

检测一个弱引用对象是否仍然存在应该使用表达式 ref() is not None。 通常,需要使用引用对象的应用代码应当遵循这样的模式:

# r is a weak reference object
o = r()
if o is None:
    # referent has been garbage collected
    print("Object has been deallocated; can't frobnicate.")
else:
    print("Object is still live!")
    o.do_something_useful()

使用单独的“存活”测试会在多线程应用中制造竞争条件;其他线程可能导致某个弱引用在该弱引用被调用前就失效;上述的写法在多线程应用和单线程应用中都是安全的。

特别版本的 ref 对象可以通过子类化来创建。 在 WeakValueDictionary 的实现中就使用了这种方式来减少映射中每个条目的内存开销。 这对于将附加信息关联到引用的情况最为适用,但也可以被用于在调用中插入额外处理来提取引用。

这个例子演示了如何将 ref 的一个子类用于存储有关对象的附加信息并在引用被访问时影响其所返回的值:

import weakref
class ExtendedRef(weakref.ref):
    def __init__(self, ob, callback=None, /, **annotations):
        super().__init__(ob, callback)
        self.__counter = 0
        for k, v in annotations.items():
            setattr(self, k, v)
    def __call__(self):
        """Return a pair containing the referent and the number of
        times the reference has been called.
        """
        ob = super().__call__()
        if ob is not None:
            self.__counter += 1
            ob = (ob, self.__counter)
        return ob

示例

这个简单的例子演示了一个应用如何使用对象 ID 来提取之前出现过的对象。 然后对象的 ID 可以在其它数据结构中使用,而无须强制对象保持存活,但处于存活状态的对象也仍然可以通过 ID 来提取。

import weakref
_id2obj_dict = weakref.WeakValueDictionary()
def remember(obj):
    oid = id(obj)
    _id2obj_dict[oid] = obj
    return oid
def id2obj(oid):
    return _id2obj_dict[oid]

终结器对象

使用 finalize 的主要好处在于它能更简便地注册回调函数,而无须保留所返回的终结器对象。 例如

>>> import weakref
>>> class Object:
...     pass
...
>>> kenny = Object()
>>> weakref.finalize(kenny, print, "You killed Kenny!")  
<finalize object at ...; for 'Object' at ...>
>>> del kenny
You killed Kenny!

终结器也可以被直接调用。 但是终结器最多只能对回调函数发起一次调用。

>>> def callback(x, y, z):
...     print("CALLBACK")
...     return x + y + z
...
>>> obj = Object()
>>> f = weakref.finalize(obj, callback, 1, 2, z=3)
>>> assert f.alive
>>> assert f() == 6
CALLBACK
>>> assert not f.alive
>>> f()                     # callback not called because finalizer dead
>>> del obj                 # callback not called because finalizer dead

你可以使用 detach() 方法来注销一个终结器。 该方法将销毁终结器并返回其被创建时传给构造器的参数。

>>> obj = Object()
>>> f = weakref.finalize(obj, callback, 1, 2, z=3)
>>> f.detach()                                           
(<...Object object ...>, <function callback ...>, (1, 2), {'z': 3})
>>> newobj, func, args, kwargs = _
>>> assert not f.alive
>>> assert newobj is obj
>>> assert func(*args, **kwargs) == 6
CALLBACK

除非你将 atexit 属性设为 False,否则终结器在程序退出时如果仍然存活就将被调用。 例如

>>> obj = Object()
>>> weakref.finalize(obj, print, "obj dead or exiting")
<finalize object at ...; for 'Object' at ...>
>>> exit()
obj dead or exiting

比较终结器与 __del__() 方法

假设我们想创建一个类,用它的实例来代表临时目录。 当以下事件中的某一个发生时,这个目录应当与其内容一起被删除:

  • 对象被作为垃圾回收,
  • 对象的 remove() 方法被调用,或
  • 程序退出。

我们可以尝试使用 __del__() 方法来实现这个类,如下所示:

class TempDir:
    def __init__(self):
        self.name = tempfile.mkdtemp()
    def remove(self):
        if self.name is not None:
            shutil.rmtree(self.name)
            self.name = None
    @property
    def removed(self):
        return self.name is None
    def __del__(self):
        self.remove()

从 Python 3.4 开始,__del__() 方法不会再阻止循环引用被作为垃圾回收,并且模块全局变量在 interpreter shutdown 期间不会被强制设为 None。 因此这段代码在 CPython 上应该会正常运行而不会出现任何问题。

然而,__del__() 方法的处理会严重地受到具体实现的影响,因为它依赖于解释器垃圾回收实现方式的内部细节。

更健壮的替代方式可以是定义一个终结器,只引用它所需要的特定函数和对象,而不是获取对整个对象状态的访问权:

class TempDir:
    def __init__(self):
        self.name = tempfile.mkdtemp()
        self._finalizer = weakref.finalize(self, shutil.rmtree, self.name)
    def remove(self):
        self._finalizer()
    @property
    def removed(self):
        return not self._finalizer.alive

像这样定义后,我们的终结器将只接受一个对其完成正确清理目录任务所需细节的引用。 如果对象一直未被作为垃圾回收,终结器仍会在退出时被调用。

基于弱引用的终结器还具有另一项优势,就是它们可被用来为定义由第三方控制的类注册终结器,例如当一个模块被卸载时运行特定代码:

import weakref, sys
def unloading_module():
    # implicit reference to the module globals from the function body
weakref.finalize(sys.modules[__name__], unloading_module)

注解

如果当程序退出时你恰好在守护线程中创建终结器对象,则有可能该终结器不会在退出时被调用。 但是,在一个守护线程中 atexit.register(), try: ... finally: ...with: ... 同样不能保证执行清理。

types —- 动态类型创建和内置类型名称

源代码: Lib/types.py


此模块定义了一些工具函数,用于协助动态创建新的类型。

它还为某些对象类型定义了名称,这些名称由标准 Python 解释器所使用,但并不像内置的 intstr 那样对外公开。

最后,它还额外提供了一些类型相关但重要程度不足以作为内置对象的工具类和函数。

动态类型创建

types.new_class(name, bases=(), kwds=None, exec_body=None)

使用适当的元类动态地创建一个类对象。

前三个参数是组成类定义头的部件:类名称,基类 (有序排列),关键字参数 (例如 metaclass)。

exec_body 参数是一个回调函数,用于填充新创建类的命名空间。 它应当接受类命名空间作为其唯一的参数并使用类内容直接更新命名空间。 如果未提供回调函数,则它就等效于传入 lambda ns: None

3.3 新版功能.

types.prepare_class(name, bases=(), kwds=None)

计算适当的元类并创建类命名空间。

参数是组成类定义头的部件:类名称,基类 (有序排列) 以及关键字参数 (例如 metaclass)。

返回值是一个 3 元组: metaclass, namespace, kwds

metaclass 是适当的元类,namespace 是预备好的类命名空间而 kwds 是所传入 kwds 参数移除每个 'metaclass' 条目后的已更新副本。 如果未传入 kwds 参数,这将为一个空字典。

3.3 新版功能.

在 3.6 版更改: 所返回元组中 namespace 元素的默认值已被改变。 现在当元类没有 __prepare__ 方法时将会使用一个保留插入顺序的映射。

PEP 3115 - Python 3000 中的元类

引入 __prepare__ 命名空间钩子

types.resolve_bases(bases)

动态地解析 MRO 条目,具体描述见 PEP 560

此函数会在 bases 中查找不是 type 的实例的项,并返回一个元组,其中每个具有 __mro_entries__ 方法的此种对象对象将被替换为调用该方法解包后的结果。 如果一个 bases 项是 type 的实例,或它不具有 __mro_entries__ 方法,则它将不加改变地被包含在返回的元组中。

3.7 新版功能.

PEP 560 - 对 typing 模块和泛型类型的核心支持

标准解释器类型

此模块为许多类型提供了实现 Python 解释器所要求的名称。 它刻意地避免了包含某些仅在处理过程中偶然出现的类型,例如 listiterator 类型。

此种名称的典型应用如 isinstance()issubclass() 检测。

如果你要实例化这些类型中的任何一种,请注意其签名在不同 Python 版本之间可能出现变化。

以下类型有相应的标准名称定义:

types.NoneType

None 的类型。

3.10 新版功能.

types.FunctionType
types.LambdaType

用户自定义函数以及由 lambda 表达式所创建函数的类型。

引发一个 审计事件 function.__new__,附带参数 code

此审计事件只会被函数对象的直接实例化引发,而不会被普通编译所引发。

types.GeneratorType

generator 迭代器对象的类型,由生成器函数创建。

types.CoroutineType

coroutine 对象的类型,由 async def 函数创建。

3.5 新版功能.

types.AsyncGeneratorType

asynchronous generator 迭代器对象的类型,由异步生成器函数创建。

3.6 新版功能.

class types.CodeType(**kwargs)

代码对象的类型,例如 compile() 的返回值。

引发 审计事件 code.__new__ 附带参数 code, filename, name, argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize, flags

请注意被审计的参数可能与初始化代码所要求的名称或位置不相匹配。 审计事件只会被代码对象的直接实例化引发,而不会被普通编译所引发。

  • replace(**kwargs)

    返回代码对象的一个副本,使用指定的新字段值。

    3.8 新版功能.

types.CellType

单元对象的类型:这种对象被用作函数中自由变量的容器。

3.8 新版功能.

types.MethodType

用户自定义类实例方法的类型。

types.BuiltinFunctionType
types.BuiltinMethodType

内置函数例如 len()sys.exit() 以及内置类方法的类型。 (这里所说的“内置”是指“以 C 语言编写”。)

types.WrapperDescriptorType

某些内置数据类型和基类的方法的类型,例如 object.__init__()object.__lt__()

3.7 新版功能.

types.MethodWrapperType

某些内置数据类型和基类的 绑定 方法的类型。 例如 object().__str__ 所属的类型。

3.7 新版功能.

types.NotImplementedType

NotImplemented 的类型。

3.10 新版功能.

types.MethodDescriptorType

某些内置数据类型方法例如 str.join() 的类型。

3.7 新版功能.

types.ClassMethodDescriptorType

某些内置数据类型 非绑定 类方法例如 dict.__dict__['fromkeys'] 的类型。

3.7 新版功能.

class types.ModuleType(name, doc=None)

模块 的类型。 构造器接受待创建模块的名称并以其 docstring 作为可选参数。

注解

如果你希望设置各种由导入控制的属性,请使用 importlib.util.module_from_spec() 来创建一个新模块。

  • __doc__

    模块的 docstring。 默认为 None

  • __loader__

    用于加载模块的 loader。 默认为 None

    此属性会匹配保存在 attr:spec 对象中的 importlib.machinery.ModuleSpec.loader

    注解

    未来的 Python 版本可能停止默认设置此属性。 为了避免这个潜在变化的影响,如果你明确地需要使用此属性则推荐改从 __spec__ 属性读取或使用 getattr(module, "__loader__", None)

    在 3.4 版更改: 默认为 None。 之前该属性为可选项。

  • __name__

    萨芬内容名称。 应当能匹配 importlib.machinery.ModuleSpec.name

  • __package__

    一个模块所属的 package。 如果模块为最高层级的(即不是任何特定包的组成部分)则该属性应设为 '',否则它应设为特定包的名称 (如果模块本身也是一个包则名称可以为 __name__)。 默认为 None

    此属性会匹配保存在 attr:spec 对象中的 importlib.machinery.ModuleSpec.parent

    注解

    未来的 Python 版本可能停止默认设置此属性。 为了避免这个潜在变化的影响,如果你明确地需要使用此属性则推荐改从 __spec__ 属性读取或使用 getattr(module, "__package__", None)

    在 3.4 版更改: 默认为 None。 之前该属性为可选项。

  • __spec__

    模块的导入系统相关状态的记录。 应当是一个 importlib.machinery.ModuleSpec 的实例。

    3.4 新版功能.

types.EllipsisType

Ellipsis 的类型。

3.10 新版功能.

class types.GenericAlias(t_origin, t_args)

形参化泛型 的类型,例如 list[int]

t_origin 应当是一个非形参化的泛型类,例如 list, tupledictt_args 应当是一个形参化 t_origintuple (长度可以为 1):

>>> from types import GenericAlias
>>> list[int] == GenericAlias(list, (int,))
True
>>> dict[str, int] == GenericAlias(dict, (str, int))
True

3.9 新版功能.

在 3.9.2 版更改: 此类型现在可以被子类化。

types.UnionType

合并类型表达式 的类型。

3.10 新版功能.

class types.TracebackType(tb_next, tb_frame, tb_lasti, tb_lineno)

回溯对象的类型,例如 sys.exc_info()[2] 中的对象。

types.FrameType

帧对象的类型,例如 tb.tb_frame 中的对象,其中 tb 是一个回溯对象。

types.GetSetDescriptorType

使用 PyGetSetDef 在扩展模块中定义的对象的类型,例如 FrameType.f_localsarray.array.typecode。 此类型被用作对象属性的描述器;它的目的与 property 类型相同,但专门针对在扩展模块中定义的类。

types.MemberDescriptorType

使用 PyMemberDef 在扩展模块中定义的对象的类型,例如 datetime.timedelta.days。 此类型被用作使用标准转换函数的简单 C 数据成员的描述器;它的目的与 property 类型相同,但专门针对在扩展模块中定义的类。

CPython implementation detail: 在 Python 的其它实现中,此类型可能与 GetSetDescriptorType 完全相同。

class types.MappingProxyType(mapping)

一个映射的只读代理。 它提供了对映射条目的动态视图,这意味着当映射发生改变时,视图会反映这些改变。

3.3 新版功能.

在 3.9 版更改: 更新为支持 PEP 584 所新增的合并 (|) 运算符,它会简单地委托给下层的映射。

  • key in proxy

    如果下层的映射中存在键 key 则返回 True,否则返回 False

  • proxy[key]

    返回下层的映射中以 key 为键的项。 如果下层的映射中不存在键 key 则引发 KeyError

  • iter(proxy)

    返回由下层映射的键为元素的迭代器。 这是 iter(proxy.keys()) 的快捷方式。

  • len(proxy)

    返回下层映射中的项数。

  • copy()

    返回下层映射的浅拷贝。

  • get(key[, default])

    如果 key 存在于下层映射中则返回 key 的值,否则返回 default*。 如果 *default 未给出则默认为 None,因而此方法绝不会引发 KeyError

  • items()

    返回由下层映射的项 ((键, 值) 对) 组成的一个新视图。

  • keys()

    返回由下层映射的键组成的一个新视图。

  • values()

    返回由下层映射的值组成的一个新视图。

  • reversed(proxy)

    返回一个包含下层映射的键的反向迭代器。

    3.9 新版功能.

附加工具类和函数

class types.SimpleNamespace

一个简单的 object 子类,提供了访问其命名空间的属性,以及一个有意义的 repr。

不同于 object,对于 SimpleNamespace 你可以添加和移除属性。 如果一个 SimpleNamespace 对象使用关键字参数进行初始化,这些参数会被直接加入下层命名空间。

此类型大致等价于以下代码:

class SimpleNamespace:
    def __init__(self, /, **kwargs):
        self.__dict__.update(kwargs)
    def __repr__(self):
        items = (f"{k}={v!r}" for k, v in self.__dict__.items())
        return "{}({})".format(type(self).__name__, ", ".join(items))
    def __eq__(self, other):
        if isinstance(self, SimpleNamespace) and isinstance(other, SimpleNamespace):
           return self.__dict__ == other.__dict__
        return NotImplemented

SimpleNamespace 可被用于替代 class NS: pass。 但是,对于结构化记录类型则应改用 namedtuple()

3.3 新版功能.

在 3.9 版更改: repr 中的属性顺序由字母顺序改为插入顺序 (类似 dict)。

types.DynamicClassAttribute(fget=None, fset=None, fdel=None, doc=None)

在类上访问 getattr 的路由属性。

这是一个描述器,用于定义通过实例与通过类访问时具有不同行为的属性。 当实例访问时保持正常行为,但当类访问属性时将被路由至类的 getattr 方法;这是通过引发 AttributeError 来完成的。

这允许有在实例上激活的特性属性,同时又有在类上的同名虚拟属性 。

3.4 新版功能.

协程工具函数

types.coroutine(gen_func)

此函数可将 generator 函数转换为返回基于生成器的协程的 coroutine function。 基于生成器的协程仍然属于 generator iterator,但同时又可被视为 coroutine 对象兼 awaitable。 不过,它没有必要实现 __await__() 方法。

如果 gen_func 是一个生成器函数,它将被原地修改。

如果 gen_func 不是一个生成器函数,则它会被包装。 如果它返回一个 collections.abc.Generator 的实例,该实例将被包装在一个 awaitable 代理对象中。 所有其他对象类型将被原样返回。

3.5 新版功能.

copy —- 浅层 (shallow) 和深层 (deep) 复制操作

源代码: Lib/copy.py


Python 的赋值语句不复制对象,而是创建目标和对象的绑定关系。对于自身可变,或包含可变项的集合,有时要生成副本用于改变操作,而不必改变原始对象。本模块提供了通用的浅层复制和深层复制操作,(如下所述)。

接口摘要:

copy.copy(x)

返回 x 的浅层复制。

copy.deepcopy(x[, memo])

返回 x 的深层复制。

exception copy.Error

针对模块特定错误引发。

浅层与深层复制的区别仅与复合对象(即包含列表或类的实例等其他对象的对象)相关:

  • 浅层复制 构造一个新的复合对象,然后(在尽可能的范围内)将原始对象中找到的对象的 引用 插入其中。
  • 深层复制 构造一个新的复合对象,然后,递归地将在原始对象里找到的对象的 副本 插入其中。

深度复制操作通常存在两个问题, 而浅层复制操作并不存在这些问题:

  • 递归对象 (直接或间接包含对自身引用的复合对象) 可能会导致递归循环。
  • 由于深层复制会复制所有内容,因此可能会过多复制(例如本应该在副本之间共享的数据)。

deepcopy() 函数用以下方式避免了这些问题:

  • 保留在当前复制过程中已复制的对象的 “备忘录” (memo) 字典;以及
  • 允许用户定义的类重载复制操作或复制的组件集合。

该模块不复制模块、方法、栈追踪(stack trace)、栈帧(stack frame)、文件、套接字、窗口、数组以及任何类似的类型。它通过不改变地返回原始对象来(浅层或深层地)“复制”函数和类;这与 pickle 模块处理这类问题的方式是相似的。

制作字典的浅层复制可以使用 dict.copy() 方法,而制作列表的浅层复制可以通过赋值整个列表的切片完成,例如,copied_list = original_list[:]

类可以使用与控制序列化(pickling)操作相同的接口来控制复制操作,关于这些方法的描述信息请参考 pickle 模块。实际上,copy 模块使用的正是从 copyreg 模块中注册的 pickle 函数。

想要为一个类定义它自己的拷贝操作实现,可以通过定义特殊方法 __copy__()__deepcopy__()。 调用前者以实现浅层拷贝操作;该方法不必传入额外参数。 调用后者以实现深层拷贝操作;它应转入一个参数,即 memo 字典。 如果 __deepcopy__() 实现需要创建一个组件的深层拷贝,它应当调用 deepcopy() 函数并以该组件作为第一个参数而以该 memo 字典作为第二个参数。。 memo 字典应当被当作不透明对象来处理。

pprint — 数据美化输出

源代码: Lib/pprint.py


pprint 模块提供了“美化打印”任意 Python 数据结构的功能,这种美化形式可用作对解释器的输入。 如果经格式化的结构包含非基本 Python 类型的对象,则其美化形式可能无法被加载。 包含文件、套接字或类对象,以及许多其他不能用 Python 字面值来表示的对象都有可能导致这样的结果。

格式化后的形式会在可能的情况下以单行来表示对象,并在无法在允许宽度内容纳对象的情况下将其分为多行。 如果你需要调整宽度限制则应显式地构造 PrettyPrinter 对象。

字典在计算其显示形式前会先根据键来排序。

在 3.9 版更改: 添加了对美化打印 types.SimpleNamespace 的支持。

在 3.10 版更改: 添加了对美化打印 dataclasses.dataclass 的支持。

pprint 模块定义了一个类:

class pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None, **, compact=False, sort_dicts=True, underscore_numbers=False*)

构造一个 PrettyPrinter 实例。 这个构造器支持一些关键字形参。

stream (默认为 sys.stdout) 是一个 file-like object,通过调用该对象的 write() 方法可以将输出写入其中。

其他值可用来配置复杂数据结构嵌套要以何种形式被展示。

indent (默认为 1) 指定要为每个缩进层级添加的缩进量。

depth 控制可被打印的缩进层级数量;如果要打印的数据结构层级过深,则其所包含的下一层级将用 ... 替换。 默认情况下,对于被格式化对象的层级深度没有任何限制。

width (默认为 80) 指定输出中每行所允许的最大字符数。 如果一个数据结构无法在宽度限制之内被格式化,将显示尽可能多的内容。

compact 影响长序列(列表、元组、集合等等)的格式化方式。 如果 compact 为假值(默认)则序列的每一项将格式化为单独的行。 如果 compact 为真值,则每个输出行格式化时将在 width 的限制之内尽可能地容纳多个条目。

如果 sort_dicts 为真值(默认),字典在格式化时将基于键进行排序,否则它们将按插入顺序显示。

如果 underscore_numbers 为真值,整数在格式化时将使用 _ 字符作为千位分隔符,否则不显示下划线(默认)。

在 3.4 版更改: 增加了 compact 形参。

在 3.8 版更改: 增加了 sort_dicts 形参。

在 3.10 版更改: 添加了 underscore_numbers 形参。

>>> import pprint
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
>>> stuff.insert(0, stuff[:])
>>> pp = pprint.PrettyPrinter(indent=4)
>>> pp.pprint(stuff)
[   ['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
    'spam',
    'eggs',
    'lumberjack',
    'knights',
    'ni']
>>> pp = pprint.PrettyPrinter(width=41, compact=True)
>>> pp.pprint(stuff)
[['spam', 'eggs', 'lumberjack',
  'knights', 'ni'],
 'spam', 'eggs', 'lumberjack', 'knights',
 'ni']
>>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
... ('parrot', ('fresh fruit',))))))))
>>> pp = pprint.PrettyPrinter(depth=6)
>>> pp.pprint(tup)
('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...)))))))

pprint 模块还提供了一些快捷函数:

pprint.pformat(object, indent=1, width=80, depth=None, **, compact=False, sort_dicts=True, underscore_numbers=False*)

object 的格式化表示作为字符串返回。 indent, width, depth, compact, sort_dictsunderscore_numbers 将作为格式化形参传递给 PrettyPrinter 构造器。

在 3.4 版更改: 增加了 compact 形参。

在 3.8 版更改: 增加了 sort_dicts 形参。

在 3.10 版更改: 添加了 underscore_numbers 形参。

pprint.pp(object, \args, sort_dicts=False, *kwargs)

打印 object 的格式化表示并附带一个换行符。 如果 sort_dicts 为假值(默认),字典将按键的插入顺序显示,否则将按字典键排序。 argskwargs 将作为格式化形参被传给 pprint()

3.8 新版功能.

pprint.pprint(object, stream=None, indent=1, width=80, depth=None, **, compact=False, sort_dicts=True, underscore_numbers=False*)

object 的格式化表示打印至 stream*,末尾带一个换行符。 如果 *streamNone,则使用 sys.stdout。 这可在交互式解释器而非 print() 函数中使用以便对值进行检查(你甚至可以在特定作用域内重赋值 print = pprint.pprint 以方便使用)。 indent, width, depth, compact, sort_dictsunderscore_numbers 将作为格式化形参传递给 PrettyPrinter 构造器。

在 3.4 版更改: 增加了 compact 形参。

在 3.8 版更改: 增加了 sort_dicts 形参。

在 3.10 版更改: 添加了 underscore_numbers 形参。

>>> import pprint
>>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
>>> stuff.insert(0, stuff)
>>> pprint.pprint(stuff)
[<Recursion on list with id=...>,
 'spam',
 'eggs',
 'lumberjack',
 'knights',
 'ni']

pprint.isreadable(object)

确定 object 的格式化表示是否“可读”,或是否可被用来通过 eval() 重新构建对象的值。 此函数对于递归对象总是返回 False

>>> pprint.isreadable(stuff)
False

pprint.isrecursive(object)

确定 object 是否需要递归表示。

此外还定义了一个支持函数:

pprint.saferepr(object)

返回 object 的字符串表示,并为递归数据结构提供保护。 如果 object 的表示形式公开了一个递归条目,该递归引用会被表示为 <Recursion on typename with id=number>。 该表示因而不会进行其它格式化。

>>> pprint.saferepr(stuff)
"[<Recursion on list with id=...>, 'spam', 'eggs', 'lumberjack', 'knights', 'ni']"

PrettyPrinter 对象

PrettyPrinter 的实例具有下列方法:

PrettyPrinter.pformat(object)

返回 object 格式化表示。 这会将传给 PrettyPrinter 构造器的选项纳入考虑。

PrettyPrinter.pprint(object)

在所配置的流上打印 object 的格式化表示,并附加一个换行符。

下列方法提供了与同名函数相对应的实现。 在实例上使用这些方法效率会更高一些,因为不需要创建新的 PrettyPrinter 对象。

PrettyPrinter.isreadable(object)

确定对象的格式化表示是否“可读”,或者是否可使用 eval() 重建对象值。 请注意此方法对于递归对象将返回 False。 如果设置了 PrettyPrinterdepth 形参并且对象深度超出允许范围,此方法将返回 False

PrettyPrinter.isrecursive(object)

确定对象是否需要递归表示。

此方法作为一个钩子提供,允许子类修改将对象转换为字符串的方式。 默认实现使用 saferepr() 实现的内部方式。

PrettyPrinter.format(object, context, maxlevels, level)

返回三个值:字符串形式的 object 已格式化版本,指明结果是否可读的旗标,以及指明是否检测到递归的旗标。 第一个参数是要表示的对象。 第二个是以对象 id() 为键的字典,这些对象是当前表示上下文的一部分(影响 object 表示的直接和间接容器);如果需要呈现一个已经在 context 中表示的对象,则第三个返回值应当为 True。 对 format() 方法的递归调用应当将容器的附加条目添加到此字典中。 第三个参数 maxlevels 给出了对递归的请求限制;如果没有请求限制则其值将为 0。 此参数应当不加修改地传给递归调用。 第四个参数 level 给出于当前层级;传给递归调用的参数值应当小于当前调用的值。

示例

为了演示 pprint() 函数及其形参的几种用法,让我们从 PyPI 获取关于某个项目的信息:

>>> import json
>>> import pprint
>>> from urllib.request import urlopen
>>> with urlopen('https://pypi.org/pypi/sampleproject/json') as resp:
...     project_info = json.load(resp)['info']

pprint() 以其基本形式显示了整个对象:

>>> pprint.pprint(project_info)
{'author': 'The Python Packaging Authority',
 'author_email': 'pypa-dev@googlegroups.com',
 'bugtrack_url': None,
 'classifiers': ['Development Status :: 3 - Alpha',
                 'Intended Audience :: Developers',
                 'License :: OSI Approved :: MIT License',
                 'Programming Language :: Python :: 2',
                 'Programming Language :: Python :: 2.6',
                 'Programming Language :: Python :: 2.7',
                 'Programming Language :: Python :: 3',
                 'Programming Language :: Python :: 3.2',
                 'Programming Language :: Python :: 3.3',
                 'Programming Language :: Python :: 3.4',
                 'Topic :: Software Development :: Build Tools'],
 'description': 'A sample Python project\n'
                '=======================\n'
                '\n'
                'This is the description file for the project.\n'
                '\n'
                'The file should use UTF-8 encoding and be written using '
                'ReStructured Text. It\n'
                'will be used to generate the project webpage on PyPI, and '
                'should be written for\n'
                'that purpose.\n'
                '\n'
                'Typical contents for this file would include an overview of '
                'the project, basic\n'
                'usage examples, etc. Generally, including the project '
                'changelog in here is not\n'
                'a good idea, although a simple "What\'s New" section for the '
                'most recent version\n'
                'may be appropriate.',
 'description_content_type': None,
 'docs_url': None,
 'download_url': 'UNKNOWN',
 'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1},
 'home_page': 'https://github.com/pypa/sampleproject',
 'keywords': 'sample setuptools development',
 'license': 'MIT',
 'maintainer': None,
 'maintainer_email': None,
 'name': 'sampleproject',
 'package_url': 'https://pypi.org/project/sampleproject/',
 'platform': 'UNKNOWN',
 'project_url': 'https://pypi.org/project/sampleproject/',
 'project_urls': {'Download': 'UNKNOWN',
                  'Homepage': 'https://github.com/pypa/sampleproject'},
 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
 'requires_dist': None,
 'requires_python': None,
 'summary': 'A sample Python project',
 'version': '1.2.0'}

结果可以被限制到特定的 depth (更深层的内容将使用省略号):

>>> pprint.pprint(project_info, depth=1)
{'author': 'The Python Packaging Authority',
 'author_email': 'pypa-dev@googlegroups.com',
 'bugtrack_url': None,
 'classifiers': [...],
 'description': 'A sample Python project\n'
                '=======================\n'
                '\n'
                'This is the description file for the project.\n'
                '\n'
                'The file should use UTF-8 encoding and be written using '
                'ReStructured Text. It\n'
                'will be used to generate the project webpage on PyPI, and '
                'should be written for\n'
                'that purpose.\n'
                '\n'
                'Typical contents for this file would include an overview of '
                'the project, basic\n'
                'usage examples, etc. Generally, including the project '
                'changelog in here is not\n'
                'a good idea, although a simple "What\'s New" section for the '
                'most recent version\n'
                'may be appropriate.',
 'description_content_type': None,
 'docs_url': None,
 'download_url': 'UNKNOWN',
 'downloads': {...},
 'home_page': 'https://github.com/pypa/sampleproject',
 'keywords': 'sample setuptools development',
 'license': 'MIT',
 'maintainer': None,
 'maintainer_email': None,
 'name': 'sampleproject',
 'package_url': 'https://pypi.org/project/sampleproject/',
 'platform': 'UNKNOWN',
 'project_url': 'https://pypi.org/project/sampleproject/',
 'project_urls': {...},
 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
 'requires_dist': None,
 'requires_python': None,
 'summary': 'A sample Python project',
 'version': '1.2.0'}

此外,还可以设置建议的最大字符 width。 如果一个对象无法被拆分,则将超出指定宽度:

>>> pprint.pprint(project_info, depth=1, width=60)
{'author': 'The Python Packaging Authority',
 'author_email': 'pypa-dev@googlegroups.com',
 'bugtrack_url': None,
 'classifiers': [...],
 'description': 'A sample Python project\n'
                '=======================\n'
                '\n'
                'This is the description file for the '
                'project.\n'
                '\n'
                'The file should use UTF-8 encoding and be '
                'written using ReStructured Text. It\n'
                'will be used to generate the project '
                'webpage on PyPI, and should be written '
                'for\n'
                'that purpose.\n'
                '\n'
                'Typical contents for this file would '
                'include an overview of the project, '
                'basic\n'
                'usage examples, etc. Generally, including '
                'the project changelog in here is not\n'
                'a good idea, although a simple "What\'s '
                'New" section for the most recent version\n'
                'may be appropriate.',
 'description_content_type': None,
 'docs_url': None,
 'download_url': 'UNKNOWN',
 'downloads': {...},
 'home_page': 'https://github.com/pypa/sampleproject',
 'keywords': 'sample setuptools development',
 'license': 'MIT',
 'maintainer': None,
 'maintainer_email': None,
 'name': 'sampleproject',
 'package_url': 'https://pypi.org/project/sampleproject/',
 'platform': 'UNKNOWN',
 'project_url': 'https://pypi.org/project/sampleproject/',
 'project_urls': {...},
 'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
 'requires_dist': None,
 'requires_python': None,
 'summary': 'A sample Python project',
 'version': '1.2.0'}

reprlib —- 另一种 repr() 实现

源代码: Lib/reprlib.py


reprlib 模块提供了一种对象表示的产生方式,它会对结果字符串的大小进行限制。 该方式被用于 Python 调试器,也适用于某些其他场景。

此模块提供了一个类、一个实例和一个函数:

class reprlib.Repr

该类提供了格式化服务 适用于实现与内置 repr() 相似的方法;其中附加了针对不同对象类型的大小限制,以避免生成超长的表示。

reprlib.aRepr

这是 Repr 的一个实例,用于提供如下所述的 repr() 函数。 改变此对象的属性将会影响 repr() 和 Python 调试器所使用的大小限制。

reprlib.repr(obj)

这是 aReprrepr() 方法。 它会返回与同名内置函数所返回字符串相似的字符串,区别在于附带了对多数类型的大小限制。

在大小限制工具以外,此模块还提供了一个装饰器,用于检测对 __repr__() 的递归调用并改用一个占位符来替换。

@``reprlib.recursive_repr(fillvalue=’…’)

用于为 __repr__() 方法检测同一线程内部递归调用的装饰器。 如果执行了递归调用,则会返回 fillvalue,否则执行正常的 __repr__() 调用。 例如:

>>> from reprlib import recursive_repr
>>> class MyList(list):
...     @recursive_repr()
...     def __repr__(self):
...         return '<' + '|'.join(map(repr, self)) + '>'
...
>>> m = MyList('abc')
>>> m.append(m)
>>> m.append('x')
>>> print(m)
<'a'|'b'|'c'|...|'x'>

3.2 新版功能.

Repr 对象

Repr 实例对象包含一些属性可以用于为不同对象类型的表示提供大小限制,还包含一些方法可以格式化特定的对象类型。

Repr.maxlevel

创建递归表示形式的深度限制。 默认为 6

Repr.maxdict
Repr.maxlist
Repr.maxtuple
Repr.maxset
Repr.maxfrozenset
Repr.maxdeque
Repr.maxarray

表示命名对象类型的条目数量限制。 对于 maxdict 的默认值为 4,对于 maxarray5,对于其他则为 6

Repr.maxlong

表示整数的最大字符数量。 数码会从中间被丢弃。 默认值为 40

Repr.maxstring

表示字符串的字符数量限制。 请注意字符源会使用字符串的“正常”表示形式:如果表示中需要用到转义序列,在缩短表示时它们可能会被破坏。 默认值为 30

Repr.maxother

此限制用于控制在 Repr 对象上没有特定的格式化方法可用的对象类型的大小。 它会以类似 maxstring 的方式被应用。 默认值为 20

Repr.repr(obj)

内置 repr() 的等价形式,它使用实例专属的格式化。

Repr.repr1(obj, level)

repr() 使用的递归实现。 此方法使用 obj 的类型来确定要调用哪个格式化方法,并传入 objlevel*。 类型专属的方法应当调用 repr1() 来执行递归格式化,在递归调用中使用 level - 1 作为 *level 的值。

Repr.repr_TYPE(obj, level)

特定类型的格式化方法会被实现为基于类型名称来命名的方法。 在方法名称中,TYPE 会被替换为 '_'.join(type(obj).__name__.split())。 对这些方法的分派会由 repr1() 来处理。 需要对值进行递归格式化的类型专属方法应当调用 self.repr1(subobj, level - 1)

子类化 Repr 对象

通过 Repr.repr1() 使用动态分派允许 Repr 的子类添加对额外内置对象类型的支持,或是修改对已支持类型的处理。 这个例子演示了如何添加对文件对象的特殊支持:

import reprlib
import sys
class MyRepr(reprlib.Repr):
    def repr_TextIOWrapper(self, obj, level):
        if obj.name in {'<stdin>', '<stdout>', '<stderr>'}:
            return obj.name
        return repr(obj)
aRepr = MyRepr()
print(aRepr.repr(sys.stdin))         # prints '<stdin>'

enum —- 对枚举的支持

3.4 新版功能.

源代码: Lib/enum.py


枚举是与多个唯一常量值绑定的一组符号名(即成员)。枚举中的成员可以进行身份比较,并且枚举自身也可迭代。

注解

枚举成员名称的大小写

枚举表示的是常量,因此,建议枚举成员名称使用大写字母,本篇的示例将用此种风格。

模块内容

本模块定义了四个枚举类,用来定义名称与值的唯一组合: EnumIntEnumFlagIntFlag。此外,还定义了一个装饰器,unique(), 和一个辅助类,auto

class enum.Enum

创建枚举常量的基类。

class enum.IntEnum

创建 int 子类枚举常量的基类。

class enum.IntFlag

创建可与位运算符搭配使用,又不失去 IntFlag 成员资格的枚举常量的基类。IntFlag 成员也是 int 的子类。

class enum.Flag

创建可与位运算符搭配使用,又不会失去 Flag 成员资格的枚举常量的基类。

enum.unique()

确保一个名称只绑定一个值的 Enum 类装饰器。

class enum.auto

以合适的值代替 Enum 成员的实例。 初始值默认从 1 开始。

3.6 新版功能: Flag, IntFlag, auto

创建 Enum

枚举是由 class 句法创建的,这种方式易读、易写。 Enum 以如下定义枚举:

>>> from enum import Enum
>>> class Color(Enum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3
...

注解

Enum 成员值

成员值可以是 intstr 等。若无需设定确切值,auto 实例可以自动为成员分配合适 的值。将 auto 与其他值混用时必须要慎重。

注解

命名法

  • Color枚举 (或称为 enum )。
  • Color.REDColor.GREEN 等属性是 枚举成员 (或 enum 成员),也是常量。
  • 枚举成员具有 名称 (例如 Color.RED 的名称为 REDColor.BLUE 的值为 3 等等)

注解

虽然 Enum 由 class 语法创建,但 Enum 并不是常规的 Python 类。

枚举成员的字符串表现形式更容易理解:

>>> print(Color.RED)
Color.RED

同时,它的 repr 包含更多信息:

>>> print(repr(Color.RED))
<Color.RED: 1>

枚举成员的 类型 就是它所属的枚举:

>>> type(Color.RED)
<enum 'Color'>
>>> isinstance(Color.GREEN, Color)
True
>>>

Enum 成员还包含 name 属性:

>>> print(Color.RED.name)
RED

枚举按定义的顺序进行迭代:

>>> class Shake(Enum):
...     VANILLA = 7
...     CHOCOLATE = 4
...     COOKIES = 9
...     MINT = 3
...
>>> for shake in Shake:
...     print(shake)
...
Shake.VANILLA
Shake.CHOCOLATE
Shake.COOKIES
Shake.MINT

枚举成员可哈希,可用于字典和集合:

>>> apples = {}
>>> apples[Color.RED] = 'red delicious'
>>> apples[Color.GREEN] = 'granny smith'
>>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}
True

枚举成员及其属性的编程访问

有时,要在程序中访问枚举成员(如,开发时不知道颜色的确切值,Color.RED 不适用的情况)。Enum 支持如下访问方式:

>>> Color(1)
<Color.RED: 1>
>>> Color(3)
<Color.BLUE: 3>

name 访问枚举成员时,可使用项目名称:

>>> Color['RED']
<Color.RED: 1>
>>> Color['GREEN']
<Color.GREEN: 2>

可访问枚举成员的 namevalue

>>> member = Color.RED
>>> member.name
'RED'
>>> member.value
1

重复的枚举成员和值

两个枚举成员的名称不能相同:

>>> class Shape(Enum):
...     SQUARE = 2
...     SQUARE = 3
...
Traceback (most recent call last):
...
TypeError: Attempted to reuse key: 'SQUARE'

但是,两个枚举成员可以有相同的值。假设,成员 A 和 B 的值相同(先定义的是 A),则 B 是 A 的别名。按值查找 A 和 B 的值返回的是 A。按名称查找 B,返回的也是 A:

>>> class Shape(Enum):
...     SQUARE = 2
...     DIAMOND = 1
...     CIRCLE = 3
...     ALIAS_FOR_SQUARE = 2
...
>>> Shape.SQUARE
<Shape.SQUARE: 2>
>>> Shape.ALIAS_FOR_SQUARE
<Shape.SQUARE: 2>
>>> Shape(2)
<Shape.SQUARE: 2>

注解

不支持创建与已定义属性(其他成员、方法等)同名的成员,也不支持创建与现有成员同名的属性。

确保唯一枚举值

默认情况下,枚举允许多个名称作为一个值的别名。如需禁用此行为,下述装饰器可以确保枚举中的值仅能只用一次:

@enum.unique

专用于枚举的 class 装饰器。 它会搜索一个枚举的 __members__ 并收集所找到的任何别名;只要找到任何别名就会引发 ValueError 并附带相关细节信息:

>>> from enum import Enum, unique
>>> @unique
... class Mistake(Enum):
...     ONE = 1
...     TWO = 2
...     THREE = 3
...     FOUR = 3
...
Traceback (most recent call last):
...
ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE

使用自动设定的值

如果确切的值不重要,你可以使用 auto:

>>> from enum import Enum, auto
>>> class Color(Enum):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> list(Color)
[<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

值将由 _generate_next_value_() 来选择,该函数可以被重载:

>>> class AutoName(Enum):
...     def _generate_next_value_(name, start, count, last_values):
...         return name
...
>>> class Ordinal(AutoName):
...     NORTH = auto()
...     SOUTH = auto()
...     EAST = auto()
...     WEST = auto()
...
>>> list(Ordinal)
[<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]

注解

默认 _generate_next_value_() 方法的目标是提供所给出的最后一个 int 所在序列的下一个 int,但这种行为方式属于实现细节并且可能发生改变。

注解

_generate_next_value_() 方法定义必须在任何其他成员之前。

迭代

对枚举成员的迭代不会给出别名:

>>> list(Shape)
[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]

特殊属性 __members__ 是一个从名称到成员的只读有序映射。 它包含枚举中定义的所有名称,包括别名:

>>> for name, member in Shape.__members__.items():
...     name, member
...
('SQUARE', <Shape.SQUARE: 2>)
('DIAMOND', <Shape.DIAMOND: 1>)
('CIRCLE', <Shape.CIRCLE: 3>)
('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)

__members__ 属性可被用于对枚举成员进行详细的程序化访问。 例如,找出所有别名:

>>> [name for name, member in Shape.__members__.items() if member.name != name]
['ALIAS_FOR_SQUARE']

比较运算

枚举成员是按标识号进行比较的:

>>> Color.RED is Color.RED
True
>>> Color.RED is Color.BLUE
False
>>> Color.RED is not Color.BLUE
True

枚举值之间的排序比较 不被 支持。 Enum 成员不属于整数 :

>>> Color.RED < Color.BLUE
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Color' and 'Color'

相等比较的定义如下:

>>> Color.BLUE == Color.RED
False
>>> Color.BLUE != Color.RED
True
>>> Color.BLUE == Color.BLUE
True

与非枚举值的比较将总是不相等(同样地,IntEnum 被显式设计成不同的行为,参见下文):

>>> Color.BLUE == 2
False

允许的枚举成员和属性

以上示例使用整数作为枚举值。 使用整数相当简洁方便(并由 Functional API 默认提供),但并不强制要求使用。 在大部分用例中,开发者都关心枚举的实际值是什么。 但如果值 确实 重要,则枚举可以使用任意的值。

枚举属于 Python 的类,并可具有普通方法和特殊方法。 如果我们有这样一个枚举:

>>> class Mood(Enum):
...     FUNKY = 1
...     HAPPY = 3
...
...     def describe(self):
...         # self is the member here
...         return self.name, self.value
...
...     def __str__(self):
...         return 'my custom str! {0}'.format(self.value)
...
...     @classmethod
...     def favorite_mood(cls):
...         # cls here is the enumeration
...         return cls.HAPPY
...

那么:

>>> Mood.favorite_mood()
<Mood.HAPPY: 3>
>>> Mood.HAPPY.describe()
('HAPPY', 3)
>>> str(Mood.FUNKY)
'my custom str! 1'

对于允许内容的规则如下:以单下划线开头和结尾的名称是由枚举保留而不可使用;在枚举中定义的所有其他属性将成为该枚举的成员,例外项则包括特殊方法成员 (__str__(), __add__() 等),描述符 (方法也属于描述符) 以及在 _ignore_ 中列出的变量名。

注意:如果你的枚举定义了 __new__() 和/或 __init__() 那么给予枚举成员的任何值都会被传入这些方法。

受限的 Enum 子类化

一个新的 Enum 类必须基于一个 Enum 类,至多一个实体数据类型以及出于实际需要的任意多个基于 object 的 mixin 类。 这些基类的顺序为:

class EnumName([mix-in, ...,] [data-type,] base-enum):    
    pass

另外,仅当一个枚举未定义任何成员时才允许子类化该枚举。 因此禁止这样的写法:

>>> class MoreColor(Color):
...     PINK = 17
...
Traceback (most recent call last):
...
TypeError: MoreColor: cannot extend enumeration 'Color'

但是允许这样的写法:

>>> class Foo(Enum):
...     def some_behavior(self):
...         pass
...
>>> class Bar(Foo):
...     HAPPY = 1
...     SAD = 2
...

允许子类化定义了成员的枚举将会导致违反类型与实例的某些重要的不可变规则。 在另一方面,允许在一组枚举之间共享某些通用行为也是有意义的。

封存

枚举可以被封存与解封:

>>> from test.test_enum import Fruit
>>> from pickle import dumps, loads
>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
True

封存的常规限制同样适用:可封存枚举必须在模块的最高层级中定义,因为解封操作要求它们可以从该模块导入。

注解

使用 pickle 协议版本 4 可以方便地封存嵌套在其他类中的枚举。

通过在枚举类中定义 __reduce_ex__() 可以对 Enum 成员的封存/解封方式进行修改。

功能性 API

Enum 类属于可调用对象,它提供了以下功能性 API:

>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
>>> Animal
<enum 'Animal'>
>>> Animal.ANT
<Animal.ANT: 1>
>>> Animal.ANT.value
1
>>> list(Animal)
[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]

该 API 的主义类似于 namedtuple。 调用 Enum 的第一个参数是枚举的名称。

第二个参数是枚举成员名称的 来源。 它可以是一个用空格分隔的名称字符串、名称序列、键/值对 2 元组的序列,或者名称到值的映射(例如字典)。 最后两种选项使得可以为枚举任意赋值;其他选项会自动以从 1 开始递增的整数赋值(使用 start 形参可指定不同的起始值)。 返回值是一个派生自 Enum 的新类。 换句话说,以上对 Animal 的赋值就等价于:

>>> class Animal(Enum):
...     ANT = 1
...     BEE = 2
...     CAT = 3
...     DOG = 4
...

默认以 1 而以 0 作为起始数值的原因在于 0 的布尔值为 False,但所有枚举成员都应被求值为 True

对使用功能性 API 创建的枚举执行封存可能会很麻烦,因为要使用帧堆栈的实现细节来尝试并找出枚举是在哪个模块中创建的(例如当你使用了另一个模块中的工具函数就可能失败,在 IronPython 或 Jython 上也可能无效)。 解决办法是显式地指定模块名称,如下所示:

>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)

警告

如果未提供 module,且 Enum 无法确定是哪个模块,新的 Enum 成员将不可被解封;为了让错误尽量靠近源头,封存将被禁用。

新的 pickle 协议版本 4 在某些情况下同样依赖于 __qualname__ 被设为特定位置以便 pickle 能够找到相应的类。 例如,类是否存在于全局作用域的 SomeData 类中:

>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')

完整的签名为:

Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)

将被新 Enum 类将记录为其名称的数据。

names

Enum 的成员。 这可以是一个空格或逗号分隔的字符串 (起始值将为 1,除非另行指定):

'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'

或是一个名称的迭代器:

['RED', 'GREEN', 'BLUE']

或是一个 (名称, 值) 对的迭代器:

[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]

或是一个映射:

{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}

module — 模块

新 Enum 类所在模块的名称。

qualname

新 Enum 类在模块中的具体位置。

type — 类型

要加入新 Enum 类的类型。

start

当只传入名称时要使用的起始数值。

在 3.5 版更改: 增加了 start 形参。

派生的枚举

IntEnum

所提供的第一个变种 Enum 同时也是 int 的一个子类。 IntEnum 的成员可与整数进行比较;通过扩展,不同类型的整数枚举也可以相互进行比较:

>>> from enum import IntEnum
>>> class Shape(IntEnum):
...     CIRCLE = 1
...     SQUARE = 2
...
>>> class Request(IntEnum):
...     POST = 1
...     GET = 2
...
>>> Shape == 1
False
>>> Shape.CIRCLE == 1
True
>>> Shape.CIRCLE == Request.POST
True

不过,它们仍然不可与标准 Enum 枚举进行比较:

>>> class Shape(IntEnum):
...     CIRCLE = 1
...     SQUARE = 2
...
>>> class Color(Enum):
...     RED = 1
...     GREEN = 2
...
>>> Shape.CIRCLE == Color.RED
False

IntEnum 值在其他方面的行为都如你预期的一样类似于整数:

>>> int(Shape.CIRCLE)
1
>>> ['a', 'b', 'c'][Shape.CIRCLE]
'b'
>>> [i for i in range(Shape.SQUARE)]
[0, 1]

IntFlag

所提供的下一个 Enum 的变种 IntFlag 同样是基于 int 的,不同之处在于 IntFlag 成员可使用按位运算符 (&, |, ^, ~) 进行组合且结果仍然为 IntFlag 成员。 如果,正如名称所表明的,IntFlag 成员同时也是 int 的子类,并能在任何使用 int 的场合被使用。 IntFlag 成员进行除按位运算以外的其他运算都将导致失去 IntFlag 成员资格。

3.6 新版功能.

示例 IntFlag 类:

>>> from enum import IntFlag
>>> class Perm(IntFlag):
...     R = 4
...     W = 2
...     X = 1
...
>>> Perm.R | Perm.W
<Perm.R|W: 6>
>>> Perm.R + Perm.W
6
>>> RW = Perm.R | Perm.W
>>> Perm.R in RW
True

对于组合同样可以进行命名:

>>> class Perm(IntFlag):
...     R = 4
...     W = 2
...     X = 1
...     RWX = 7
>>> Perm.RWX
<Perm.RWX: 7>
>>> ~Perm.RWX
<Perm.-8: -8>

IntFlagEnum 的另一个重要区别在于如果没有设置任何旗标(值为 0),则其布尔值为 False:

>>> Perm.R & Perm.X
<Perm.0: 0>
>>> bool(Perm.R & Perm.X)
False

由于 IntFlag 成员同时也是 int 的子类,因此它们可以相互组合:

>>> Perm.X | 8
<Perm.8|X: 9>

旗标

最后一个变种是 Flag。 与 IntFlag 类似,Flag 成员可使用按位运算符 (&, |, ^, ~) 进行组合,与 IntFlag 不同的是它们不可与任何其它 Flag 枚举或 int 进行组合或比较。 虽然可以直接指定值,但推荐使用 auto 作为值以便让 Flag 选择适当的值。

3.6 新版功能.

IntFlag 类似,如果 Flag 成员的某种组合导致没有设置任何旗标,则其布尔值为 False:

>>> from enum import Flag, auto
>>> class Color(Flag):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> Color.RED & Color.GREEN
<Color.0: 0>
>>> bool(Color.RED & Color.GREEN)
False

单个旗标的值应当为二的乘方 (1, 2, 4, 8, …),旗标的组合则无此限制:

>>> class Color(Flag):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...     WHITE = RED | BLUE | GREEN
...
>>> Color.WHITE
<Color.WHITE: 7>

对 “no flags set” 条件指定一个名称并不会改变其布尔值:

>>> class Color(Flag):
...     BLACK = 0
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> Color.BLACK
<Color.BLACK: 0>
>>> bool(Color.BLACK)
False

注解

对于大多数新代码,强烈推荐使用 EnumFlag,因为 IntEnumIntFlag 打破了枚举的某些语义约定(例如可以同整数进行比较,并因而导致此行为被传递给其他无关的枚举)。 IntEnumIntFlag 的使用应当仅限于 EnumFlag 无法使用的场合;例如,当使用枚举替代整数常量时,或是与其他系统进行交互操作时。

其他事项

虽然 IntEnumenum 模块的一部分,但要独立实现也应该相当容易:

class IntEnum(int, Enum):    
    pass

这里演示了如何定义类似的派生枚举;例如一个混合了 str 而不是 intStrEnum

几条规则:

  1. 当子类化 Enum 时,在基类序列中的混合类型必须出现于 Enum 本身之前,如以上 IntEnum 的例子所示。
  2. 虽然 Enum 可以拥有任意类型的成员,不过一旦你混合了附加类型,则所有成员必须为相应类型的值,如在上面的例子中即为 int。 此限制不适用于仅添加方法而未指定另一数据类型的混合类。
  3. 当混合了另一数据类型时,value 属性会 不同于 枚举成员自身,但它们仍保持等价且比较结果也相等。
  4. %-style formatting: %s 和 %r 会分别调用 Enum 类的 __str__()__repr__();其他代码 (例如表示 IntEnum 的 %i 或 %h) 会将枚举成员视为对应的混合类型。
  5. 格式化字符串字面值, str.format()format() 将使用混合类型的 __format__() 除非在子类中重载了 __str__()__format__(),在这种情况下将使用被重载的方法或 Enum 的方法。 请使用 !s 和 !r 格式代码来强制使用 Enum 类的 __str__()__repr__() 方法。

何时使用 __new__()__init__()

当你想要定制 Enum 成员的实际值时必须使用 __new__()。 任何其他修改可以用 __new__() 也可以用 __init__(),应优先使用 __init__()

举例来说,如果你要向构造器传入多个条目,但只希望将其中一个作为值:

>>> class Coordinate(bytes, Enum):
...     """
...     Coordinate with binary codes that can be indexed by the int code.
...     """
...     def __new__(cls, value, label, unit):
...         obj = bytes.__new__(cls, [value])
...         obj._value_ = value
...         obj.label = label
...         obj.unit = unit
...         return obj
...     PX = (0, 'P.X', 'km')
...     PY = (1, 'P.Y', 'km')
...     VX = (2, 'V.X', 'km/s')
...     VY = (3, 'V.Y', 'km/s')
...
>>> print(Coordinate['PY'])
Coordinate.PY
>>> print(Coordinate(3))
Coordinate.VY

有趣的示例

虽然 Enum, IntEnum, IntFlagFlag 预期可覆盖大多数应用场景,但它们无法覆盖全部。 这里有一些不同类型枚举的方案,它们可以被直接使用,或是作为自行创建的参考示例。

省略值

在许多应用场景中人们都不关心枚举的实际值是什么。 有几个方式可以定义此种类型的简单枚举:

  • 使用 auto 的实例作为值
  • 使用 object 的实例作为值
  • 使用描述性的字符串作为值
  • 使用元组作为值并用自定义的 __new__() 以一个 int 值来替代该元组

使用以上任何一种方法均可向用户指明值并不重要,并且使人能够添加、移除或重排序成员而不必改变其余成员的数值。

无论你选择何种方法,你都应当提供一个 repr() 并且它也需要隐藏(不重要的)值:

>>> class NoValue(Enum):
...     def __repr__(self):
...         return '<%s.%s>' % (self.__class__.__name__, self.name)
...
使用 auto

使用 auto 的形式如下:

>>> class Color(NoValue):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()
...
>>> Color.GREEN
<Color.GREEN>
使用 object

使用 object 的形式如下:

>>> class Color(NoValue):
...     RED = object()
...     GREEN = object()
...     BLUE = object()
...
>>> Color.GREEN
<Color.GREEN>
使用描述性字符串

使用字符串作为值的形式如下:

>>> class Color(NoValue):
...     RED = 'stop'
...     GREEN = 'go'
...     BLUE = 'too fast!'
...
>>> Color.GREEN
<Color.GREEN>
>>> Color.GREEN.value
'go'
使用自定义的 __new__()

使用自动编号 __new__() 的形式如下:

>>> class AutoNumber(NoValue):
...     def __new__(cls):
...         value = len(cls.__members__) + 1
...         obj = object.__new__(cls)
...         obj._value_ = value
...         return obj
...
>>> class Color(AutoNumber):
...     RED = ()
...     GREEN = ()
...     BLUE = ()
...
>>> Color.GREEN
<Color.GREEN>
>>> Color.GREEN.value
2

要实现更通用的 AutoNumber,请添加 *args 到签名中:

>>> class AutoNumber(NoValue):
...     def __new__(cls, *args):      # this is the only change from above
...         value = len(cls.__members__) + 1
...         obj = object.__new__(cls)
...         obj._value_ = value
...         return obj
...

这样当你从 AutoNumber 继承时你将可以编写你自己的 __init__ 来处理任何附加参数:

>>> class Swatch(AutoNumber):
...     def __init__(self, pantone='unknown'):
...         self.pantone = pantone
...     AUBURN = '3497'
...     SEA_GREEN = '1246'
...     BLEACHED_CORAL = () # New color, no Pantone code yet!
...
>>> Swatch.SEA_GREEN
<Swatch.SEA_GREEN>
>>> Swatch.SEA_GREEN.pantone
'1246'
>>> Swatch.BLEACHED_CORAL.pantone
'unknown'

注解

如果定义了 __new__() 则它会在创建 Enum 成员期间被使用;随后它将被 Enum 的 __new__() 所替换,该方法会在类创建后被用来查找现有成员。

OrderedEnum

一个有序枚举,它不是基于 IntEnum,因此保持了正常的 Enum 不变特性(例如不可与其他枚举进行比较):

>>> class OrderedEnum(Enum):
...     def __ge__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value >= other.value
...         return NotImplemented
...     def __gt__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value > other.value
...         return NotImplemented
...     def __le__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value <= other.value
...         return NotImplemented
...     def __lt__(self, other):
...         if self.__class__ is other.__class__:
...             return self.value < other.value
...         return NotImplemented
...
>>> class Grade(OrderedEnum):
...     A = 5
...     B = 4
...     C = 3
...     D = 2
...     F = 1
...
>>> Grade.C < Grade.A
True

DuplicateFreeEnum

如果发现重复的成员名称则将引发错误而不是创建别名:

>>> class DuplicateFreeEnum(Enum):
...     def __init__(self, *args):
...         cls = self.__class__
...         if any(self.value == e.value for e in cls):
...             a = self.name
...             e = cls(self.value).name
...             raise ValueError(
...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
...                 % (a, e))
...
>>> class Color(DuplicateFreeEnum):
...     RED = 1
...     GREEN = 2
...     BLUE = 3
...     GRENE = 2
...
Traceback (most recent call last):
...
ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'

注解

这个例子适用于子类化 Enum 来添加或改变禁用别名以及其他行为。 如果需要的改变只是禁用别名,也可以选择使用 unique() 装饰器。

Planet

如果定义了 __new__()__init__() 则枚举成员的值将被传给这些方法:

>>> class Planet(Enum):
...     MERCURY = (3.303e+23, 2.4397e6)
...     VENUS   = (4.869e+24, 6.0518e6)
...     EARTH   = (5.976e+24, 6.37814e6)
...     MARS    = (6.421e+23, 3.3972e6)
...     JUPITER = (1.9e+27,   7.1492e7)
...     SATURN  = (5.688e+26, 6.0268e7)
...     URANUS  = (8.686e+25, 2.5559e7)
...     NEPTUNE = (1.024e+26, 2.4746e7)
...     def __init__(self, mass, radius):
...         self.mass = mass       # in kilograms
...         self.radius = radius   # in meters
...     @property
...     def surface_gravity(self):
...         # universal gravitational constant  (m3 kg-1 s-2)
...         G = 6.67300E-11
...         return G * self.mass / (self.radius * self.radius)
...
>>> Planet.EARTH.value
(5.976e+24, 6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129

TimePeriod

一个演示如何使用 _ignore_ 属性的例子:

>>> from datetime import timedelta
>>> class Period(timedelta, Enum):
...     "different lengths of time"
...     _ignore_ = 'Period i'
...     Period = vars()
...     for i in range(367):
...         Period['day_%d' % i] = i
...
>>> list(Period)[:2]
[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
>>> list(Period)[-2:]
[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]

各种枚举有何区别?

枚举具有自定义的元类,它会影响所派生枚举类及其实例(成员)的各个方面。

枚举类

EnumMeta 元类负责提供 __contains__(), __dir__(), __iter__() 及其他方法以允许用户通过 Enum 类来完成一般类做不到的事情,例如 list(Color) 或 some_enum_var in Color。 EnumMeta 会负责确保最终 Enum 类中的各种其他方法是正确的 (例如 __new__(), __getnewargs__(), __str__()__repr__())。

枚举成员(即实例)

有关枚举成员最有趣的特点是它们都是单例对象。 EnumMeta 会在创建 Enum 类本身时将它们全部创建完成,然后准备好一个自定义的 __new__(),通过只返回现有的成员实例来确保不会再实例化新的对象。

细节要点

支持的 __dunder__ 名称

__members__ 是一个 member_name:member 条目的只读有序映射。 它只在类上可用。

如果指定了 __new__(),它必须创建并返回枚举成员;相应地设定成员的 _value_ 也是一个很好的主意。 一旦所有成员都创建完成它就不会再被使用。

支持的 _sunder_ 名称
  • _name_ — 成员的名称
  • _value_ — 成员的值;可以在 __new__ 中设置 / 修改
  • _missing_ — 当未发现某个值时所使用的查找函数;可被重载
  • _ignore_ — 一个名称列表,可以为 liststr,它不会被转化为成员,并将从最终类中被移除
  • _order_ — 用于 Python 2/3 代码以确保成员顺序一致(类属性,在类创建期间会被移除)
  • _generate_next_value_ — 用于 Functional API 并通过 auto 为枚举成员获取适当的值;可被重载

3.6 新版功能: _missing_, _order_, _generate_next_value_

3.7 新版功能: _ignore_

用来帮助 Python 2 / Python 3 代码保持同步提供 _order_ 属性。 它将与枚举的实际顺序进行对照检查,如果两者不匹配则会引发错误:

>>> class Color(Enum):
...     _order_ = 'RED GREEN BLUE'
...     RED = 1
...     BLUE = 3
...     GREEN = 2
...
Traceback (most recent call last):
...
TypeError: member order does not match _order_

注解

在 Python 2 代码中 _order_ 属性是必须的,因为定义顺序在被记录之前就会丢失。

_Private__names

私有名称在 Python 3.10 中将成为普通属性而不再是错误或成员(具体取决于该名称是否以一个下划线结束)。 在 3.9 中使用这种名称将引发 DeprecationWarning

Enum 成员类型

Enum 成员是其 Enum 类的实例,一般通过 EnumClass.member 的形式来访问。 在特定情况下它们也可通过 EnumClass.member.member 的形式来访问,但你绝对不应这样做,因为查找可能失败,或者更糟糕地返回你所查找的 Enum 成员以外的对象(这也是成员应使用全大写名称的另一个好理由):

>>> class FieldTypes(Enum):
...     name = 0
...     value = 1
...     size = 2
...
>>> FieldTypes.value.size
<FieldTypes.size: 2>
>>> FieldTypes.size.value
2

在 3.5 版更改.

Enum 类和成员的布尔值

混合了非 Enum 类型(例如 int, str 等)的 Enum 成员会按所混合类型的规则被求值;在其他情况下,所有成员都将被求值为 True。 要使你的自定义 Enum 的布尔值取决于成员的值,请在你的类中添加以下代码:

def __bool__(self):
    return bool(self.value)

Enum 类总是会被求值为 True

带有方法的 Enum

如果你为你的 Enum 子类添加了额外的方法,如同上述的 Planet 类一样,这些方法将在对成员执行 dir() 时显示出来,但对类执行时则不会显示:

>>> dir(Planet)
['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
>>> dir(Planet.EARTH)
['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
组合 Flag 的成员

如果 Flag 成员的某种组合未被命名,则 repr() 将包含所有已命名的旗标和值中所有已命名的旗标组合:

>>> class Color(Flag):
...     RED = auto()
...     GREEN = auto()
...     BLUE = auto()
...     MAGENTA = RED | BLUE
...     YELLOW = RED | GREEN
...     CYAN = GREEN | BLUE
...
>>> Color(3)  # named combination
<Color.YELLOW: 3>
>>> Color(7)      # not named combination
<Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>

graphlib —- 操作类似图的结构的功能

源代码: Lib/graphlib.py


class graphlib.TopologicalSorter(graph=None)

提供以拓扑方式对可哈希节点的图进行排序的功能。

拓扑排序是指图中顶点的线性排序,使得对于每条从顶点 u 到顶点 v 的有向边 u -> v,顶点 u 都排在顶点 v 之前。 例如,图的顶点可以代表要执行的任务,而边代表某一个任务必须在另一个任务之前执行的约束条件;在这个例子中,拓扑排序只是任务的有效序列。 完全拓扑排序 当且仅当图不包含有向环,也就是说为有向无环图时,完全拓扑排序才是可能的。

如果提供了可选的 graph 参数则它必须为一个表示有向无环图的字典,其中的键为节点而值为包含图中该节点的所有上级节点(即具有指向键中的值的边的节点)的可迭代对象。 额外的节点可以使用 add() 方法添加到图中。

在通常情况下,对给定的图执行排序所需的步骤如下:

  • 通过可选的初始图创建一个 TopologicalSorter 的实例。
  • 添加额外的节点到图中。
  • 在图上调用 prepare()
  • is_active()True 时,迭代 get_ready() 所返回的节点并加以处理。 完成处理后在每个节点上调用 done()

在只需要对图中的节点进行立即排序并且不涉及并行性的情况下,可以直接使用便捷方法 TopologicalSorter.static_order():

>>> graph = {"D": {"B", "C"}, "C": {"A"}, "B": {"A"}}
>>> ts = TopologicalSorter(graph)
>>> tuple(ts.static_order())
('A', 'C', 'B', 'D')

这个类被设计用来在节点就绪时方便地支持对其并行处理。 例如:

topological_sorter = TopologicalSorter()
# Add nodes to 'topological_sorter'...
topological_sorter.prepare()
while topological_sorter.is_active():
    for node in topological_sorter.get_ready():
        # Worker threads or processes take nodes to work on off the
        # 'task_queue' queue.
        task_queue.put(node)
    # When the work for a node is done, workers put the node in
    # 'finalized_tasks_queue' so we can get more nodes to work on.
    # The definition of 'is_active()' guarantees that, at this point, at
    # least one node has been placed on 'task_queue' that hasn't yet
    # been passed to 'done()', so this blocking 'get()' must (eventually)
    # succeed.  After calling 'done()', we loop back to call 'get_ready()'
    # again, so put newly freed nodes on 'task_queue' as soon as
    # logically possible.
    node = finalized_tasks_queue.get()
    topological_sorter.done(node)
  • add(node, \predecessors*)

    将一个新节点及其上级节点添加到图中。 node 以及 predecessors 中的所有元素都必须为可哈希对象。

    如果附带相同的节点参数多次调用,则依赖项的集合将为所有被传入依赖项的并集。

    可以添加不带依赖项的节点 (即不提供 predecessors) 或者重复提供依赖项。 如果有先前未提供的节点包含在 predecessors 中则它将被自动添加到图中并且不带自己的上级节点。

    如果在 prepare() 之后被调用则会引发 ValueError

  • prepare()

    将图标记为已完成并检查图中是否存在环。 如何检测到任何环,则将引发 CycleError,但 get_ready() 仍可被用来获取尽可能多的节点直到环阻塞了操作过程。 在调用此函数后,图将无法再修改,因此不能再使用 add() 添加更多的节点。

  • is_active()

    如果可以取得更多进展则返回 True,否则返回 False。 如果环没有阻塞操作,并且还存在尚未被 TopologicalSorter.get_ready() 返回的已就绪节点或者已标记为 TopologicalSorter.done() 的节点数量少于已被 TopologicalSorter.get_ready() 所返回的节点数量则还可以取得进展。

    该类的 __bool__() 方法要使用此函数,因此除了:

    if ts.is_active():
        ...

    可能会简单地执行:

    if ts:
        ...

    如果之前未调用 prepare() 就调用此函数则会引发 ValueError

  • done(\nodes*)

    TopologicalSorter.get_ready() 所返回的节点集合标记为已处理,解除对 nodes 中每个节点的后续节点的阻塞以便在将来通过对 TopologicalSorter.get_ready() 的调用来返回它们。

    如果 nodes 中的任何节点已经被之前对该方法的调用标记为已处理或者如果未通过使用 TopologicalSorter.add() 将一个节点添加到图中,如果未调用 prepare() 即调用此方法或者如果节点尚未被 get_ready() 所返回则将引发 ValueError

  • get_ready()

    返回由所有已就绪节点组成的 tuple。 初始状态下它将返回所有不带上级节点的节点,并且一旦通过调用 TopologicalSorter.done() 将它们标记为已处理,之后的调用将返回所有上级节点已被处理的新节点。 一旦无法再取得进展,则会返回空元组。

    如果之前未调用 prepare() 就调用此函数则会引发 ValueError

  • static_order()

    返回一个迭代器,它将按照拓扑顺序来迭代所有节点。 当使用此方法时,prepare()done() 不应被调用。 此方法等价于:

    def static_order(self):
        self.prepare()
        while self.is_active():
            node_group = self.get_ready()
            yield from node_group
            self.done(*node_group)

    所返回的特定顺序可能取决于条目被插入图中的顺序。 例如:

    >>> ts = TopologicalSorter()
    >>> ts.add(3, 2, 1)
    >>> ts.add(1, 0)
    >>> print([*ts.static_order()])
    [2, 0, 1, 3]
    >>> ts2 = TopologicalSorter()
    >>> ts2.add(1, 0)
    >>> ts2.add(3, 2, 1)
    >>> print([*ts2.static_order()])
    [0, 2, 1, 3]

    这是由于实际上 “0” 和 “2” 在图中的级别相同(它们将在对 get_ready() 的同一次调用中被返回) 并且它们之间的顺序是由插入顺序决定的。

    如果检测到任何环,则将引发 CycleError

3.9 新版功能.

异常

graphlib 模块定义了以下异常类:

exception graphlib.CycleError

ValueError 的子类,当特定的图中存在环时将由 TopologicalSorter.prepare() 引发。 如果存在多个环,则将只报告其中一个未定义的选项并将其包括在异常中。

检测到的环可以通过异常实例的 args 属性的第二个元素来访问,它由一个节点列表组成,其中的每个节点在图中都是列表中下一个节点的直接上级节点。 在报告的列表中,开头和末尾的节点将是同一对象,以表明它是一个环。

数字和数学模块

本章介绍的模块提供与数字和数学相关的函数和数据类型。 numbers 模块定义了数字类型的抽象层次结构。 mathcmath 模块包含浮点数和复数的各种数学函数。 decimal 模块支持使用任意精度算术的十进制数的精确表示。

本章包含以下模块的文档:

  • numbers —- 数字的抽象基类
    • 数字的层次
    • 类型接口注释。
      • 加入更多数字的ABC
      • 实现算术运算
  • math —- 数学函数
    • 数论与表示函数
    • 幂函数与对数函数
    • 三角函数
    • 角度转换
    • 双曲函数
    • 特殊函数
    • 常量
  • cmath —- 关于复数的数学函数
    • 到极坐标和从极坐标的转换
    • 幂函数与对数函数
    • 三角函数
    • 双曲函数
    • 分类函数
    • 常量
  • decimal —- 十进制定点和浮点运算
    • 快速入门教程
    • Decimal 对象
      • 逻辑操作数
    • 上下文对象
    • 常量
    • 舍入模式
    • 信号
    • 浮点数说明
      • 通过提升精度来解决舍入错误
      • 特殊的值
    • 使用线程
    • 例程
    • Decimal 常见问题
  • fractions —- 分数
  • random —- 生成伪随机数
    • 簿记功能
    • 用于字节数据的函数
    • 整数用函数
    • 序列用函数
    • 实值分布
    • 替代生成器
    • 关于再现性的说明
    • 例子
    • 例程
  • statistics —- 数学统计函数
    • 平均值以及对中心位置的评估
    • 对分散程度的评估
    • 对两个输入之间关系的统计
    • 函数细节
    • 异常
    • NormalDist 对象
      • NormalDist 示例和用法

numbers —- 数字的抽象基类

源代码: Lib/numbers.py


numbers 模块 (PEP 3141) 定义了数字 抽象基类 的层级结构,其中逐级定义了更多操作。 此模块中定义的类型都不可被实例化。

class numbers.Number

数字的层次结构的基础。 如果你只想确认参数 x 是不是数字而不关心其类型,则使用 isinstance(x, Number)

数字的层次

class numbers.Complex

这个类型的子类描述了复数并包括了适用于内置 complex 类型的操作。 这些操作有: 转换为 complexbool, real, imag, +, -, *, /, **, abs(), conjugate(), == 以及 !=。 除 -!= 之外所有操作都是抽象的。

  • real

    抽象的。得到该数字的实数部分。

  • imag

    抽象的。得到该数字的虚数部分。

  • abstractmethod conjugate()

    抽象的。返回共轭复数。例如 (1+3j).conjugate() == (1-3j)

class numbers.Real

相对于 ComplexReal 加入了只有实数才能进行的操作。

简单的说,它们是:转化至 floatmath.trunc()round()math.floor()math.ceil()divmod()//%<<=>、 和 >=

实数同样默认支持 complex()realimagconjugate()

class numbers.Rational

子类型 Real 并加入 numeratordenominator 两种属性,这两种属性应该属于最低的级别。加入后,这默认支持 float()

  • numerator

    抽象的。

  • denominator

    抽象的。

class numbers.Integral

子类型 Rational 还增加了到 int 的转换操作。 为 float(), numeratordenominator 提供了默认支持。 为 pow() 方法增加了求余和按位字符串运算的抽象方法: <<, >>, &, ^, |, ~

类型接口注释。

实现者需要注意使相等的数字相等并拥有同样的值。当这两个数使用不同的扩展模块时,这其中的差异是很微妙的。例如,用 fractions.Fraction 实现 hash() 如下:

def __hash__(self):
    if self.denominator == 1:
        # Get integers right.
        return hash(self.numerator)
    # Expensive check, but definitely correct.
    if self == float(self):
        return hash(float(self))
    else:
        # Use tuple's hash to avoid a high collision rate on
        # simple fractions.
        return hash((self.numerator, self.denominator))

加入更多数字的ABC

当然,这里有更多支持数字的ABC,如果不加入这些,就将缺少层次感。你可以用如下方法在 ComplexReal 中加入 MyFoo:

class MyFoo(Complex): ...
MyFoo.register(Real)

实现算术运算

我们希望实现计算,因此,混合模式操作要么调用一个作者知道参数类型的实现,要么转变成为最接近的内置类型并对这个执行操作。对于子类 Integral,这意味着 __add__()__radd__() 必须用如下方式定义:

class MyIntegral(Integral):
    def __add__(self, other):
        if isinstance(other, MyIntegral):
            return do_my_adding_stuff(self, other)
        elif isinstance(other, OtherTypeIKnowAbout):
            return do_my_other_adding_stuff(self, other)
        else:
            return NotImplemented
    def __radd__(self, other):
        if isinstance(other, MyIntegral):
            return do_my_adding_stuff(other, self)
        elif isinstance(other, OtherTypeIKnowAbout):
            return do_my_other_adding_stuff(other, self)
        elif isinstance(other, Integral):
            return int(other) + int(self)
        elif isinstance(other, Real):
            return float(other) + float(self)
        elif isinstance(other, Complex):
            return complex(other) + complex(self)
        else:
            return NotImplemented

Complex 有 5 种不同的混合类型的操作。 我将上面提到的所有代码作为“模板”称作 MyIntegralOtherTypeIKnowAboutaComplex 的子类型 A 的实例 (a : A <: Complex),同时 b : B <: Complex。 我将要计算 a + b:

  1. 如果 A 被定义成一个承认 b__add__(),一切都没有问题。
  2. 如果 A 转回成“模板”失败,它将返回一个属于 __add__() 的值,我们需要避免 B 定义了一个更加智能的 __radd__(),因此模板需要返回一个属于 __add__()NotImplemented 。(或者 A 可能完全不实现 __add__() 。)
  3. 接着看 B__radd__() 。如果它承认 a ,一切都没有问题。
  4. 如果没有成功回退到模板,就没有更多的方法可以去尝试,因此这里将使用默认的实现。
  5. 如果 B <: A , Python 在 A.__add__ 之前尝试 B.__radd__ 。 这是可行的,是通过对 A 的认识实现的,因此这可以在交给 Complex 处理之前处理这些实例。

如果 A <: ComplexB <: Real 没有共享任何资源,那么适当的共享操作涉及内置的 complex ,并且分别获得 __radd__() ,因此 a+b == b+a

由于对任何一直类型的大部分操作是十分相似的,可以定义一个帮助函数,即一个生成后续或相反的实例的生成器。例如,使用 fractions.Fraction 如下:

def _operator_fallbacks(monomorphic_operator, fallback_operator):
    def forward(a, b):
        if isinstance(b, (int, Fraction)):
            return monomorphic_operator(a, b)
        elif isinstance(b, float):
            return fallback_operator(float(a), b)
        elif isinstance(b, complex):
            return fallback_operator(complex(a), b)
        else:
            return NotImplemented
    forward.__name__ = '__' + fallback_operator.__name__ + '__'
    forward.__doc__ = monomorphic_operator.__doc__
    def reverse(b, a):
        if isinstance(a, Rational):
            # Includes ints.
            return monomorphic_operator(a, b)
        elif isinstance(a, numbers.Real):
            return fallback_operator(float(a), float(b))
        elif isinstance(a, numbers.Complex):
            return fallback_operator(complex(a), complex(b))
        else:
            return NotImplemented
    reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
    reverse.__doc__ = monomorphic_operator.__doc__
    return forward, reverse
def _add(a, b):
    """a + b"""
    return Fraction(a.numerator * b.denominator +
                    b.numerator * a.denominator,
                    a.denominator * b.denominator)
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
# ...

math —- 数学函数

该模块提供了对C标准定义的数学函数的访问。

这些函数不适用于复数;如果你需要计算复数,请使用 cmath 模块中的同名函数。将支持计算复数的函数区分开的目的,来自于大多数开发者并不愿意像数学家一样需要学习复数的概念。得到一个异常而不是一个复数结果使得开发者能够更早地监测到传递给这些函数的参数中包含复数,进而调查其产生的原因。

该模块提供了以下函数。除非另有明确说明,否则所有返回值均为浮点数。

数论与表示函数

math.ceil(x)

返回 x 的上限,即大于或者等于 x 的最小整数。如果 x 不是一个浮点数,则委托 x.__ceil__(), 返回一个 Integral 类的值。

math.comb(n, k)

返回不重复且无顺序地从 n 项中选择 k 项的方式总数。

k <= n 时取值为 n! / (k! * (n - k)!);当 k > n 时取值为零。

也称为二项式系数,因为它等价于表达式 (1 + x) ** n 的多项式展开中第 k 项的系数。

如果任一参数不为整数则会引发 TypeError。 如果任一参数为负数则会引发 ValueError

3.8 新版功能.

math.copysign(x, y)

返回一个基于 x 的绝对值和 y 的符号的浮点数。在支持带符号零的平台上,copysign(1.0, -0.0) 返回 -1.0.

math.fabs(x)

返回 x 的绝对值。

math.factorial(x)

以一个整数返回 x 的阶乘。 如果 x 不是整数或为负数时则将引发 ValueError

3.9 版后已移除: 接受具有整数值的浮点数 (例如 5.0) 的行为已被弃用。

math.floor(x)

返回 x 的向下取整,小于或等于 x 的最大整数。如果 x 不是浮点数,则委托 x.__floor__() ,它应返回 Integral 值。

math.fmod(x, y)

返回 fmod(x, y) ,由平台C库定义。请注意,Python表达式 x % y 可能不会返回相同的结果。C标准的目的是 fmod(x, y) 完全(数学上;到无限精度)等于 x - n*y 对于某个整数 n ,使得结果具有 与 x 相同的符号和小于 abs(y) 的幅度。Python的 x % y 返回带有 y 符号的结果,并且可能不能完全计算浮点参数。 例如, fmod(-1e-100, 1e100)-1e-100 ,但Python的 -1e-100 % 1e100 的结果是 1e100-1e-100 ,它不能完全表示为浮点数,并且取整为令人惊讶的 1e100 。 出于这个原因,函数 fmod() 在使用浮点数时通常是首选,而Python的 x % y 在使用整数时是首选。

math.frexp(x)

(m, e) 对的形式返回 x 的尾数和指数。 m 是一个浮点数, e 是一个整数,正好是 x == m * 2**e 。 如果 x 为零,则返回 (0.0, 0) ,否则返回 0.5 <= abs(m) < 1 。这用于以可移植方式“分离”浮点数的内部表示。

math.fsum(iterable)

返回迭代中的精确浮点值。通过跟踪多个中间部分和来避免精度损失:

>>> sum([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1])
0.9999999999999999
>>> fsum([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1])
1.0

该算法的准确性取决于IEEE-754算术保证和舍入模式为半偶的典型情况。在某些非Windows版本中,底层C库使用扩展精度添加,并且有时可能会使中间和加倍,导致它在最低有效位中关闭。

math.gcd(\integers*)

返回给定的整数参数的最大公约数。 如果有一个参数非零,则返回值将是能同时整除所有参数的最大正整数。 如果所有参数为零,则返回值为 0。 不带参数的 gcd() 返回 0

3.5 新版功能.

在 3.9 版更改: 添加了对任意数量的参数的支持。 之前的版本只支持两个参数。

math.isclose(a, b, **, rel_tol=1e-09, abs_tol=0.0*)

ab 的值比较接近则返回 True,否则返回 False

根据给定的绝对和相对容差确定两个值是否被认为是接近的。

rel_tol 是相对容差 —— 它是 ab 之间允许的最大差值,相对于 ab 的较大绝对值。例如,要设置5%的容差,请传递 rel_tol=0.05 。默认容差为 1e-09,确保两个值在大约9位十进制数字内相同。 rel_tol 必须大于零。

abs_tol 是最小绝对容差 —— 对于接近零的比较很有用。 abs_tol 必须至少为零。

如果没有错误发生,结果将是: abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

IEEE 754特殊值 NaNinf-inf 将根据IEEE规则处理。具体来说, NaN 不被认为接近任何其他值,包括 NaNinf-inf 只被认为接近自己。

3.5 新版功能.

参见

PEP 485 —— 用于测试近似相等的函数

math.isfinite(x)

如果 x 既不是无穷大也不是NaN,则返回 True ,否则返回 False 。 (注意 0.0 被认为 有限的。)

3.2 新版功能.

math.isinf(x)

如果 x 是正或负无穷大,则返回 True ,否则返回 False

math.isnan(x)

如果 x 是 NaN(不是数字),则返回 True ,否则返回 False

math.isqrt(n)

返回非负整数 n 的整数平方根。 这就是对 n 的实际平方根向下取整,或者相当于使得 a² ≤ n 的最大整数 a

对于某些应用来说,可以更适合取值为使得 na² 的最小整数 a ,或者换句话说就是 n 的实际平方根向上取整。 对于正数 n,这可以使用 a = 1 + isqrt(n - 1) 来计算。

3.8 新版功能.

math.lcm(\integers*)

返回给定的整数参数的最小公倍数。 如果所有参数均非零,则返回值将是为所有参数的整数倍的最小正整数。 如果参数之一为零,则返回值为 0。 不带参数的 lcm() 返回 1

3.9 新版功能.

math.ldexp(x, i)

返回 x * (2**i) 。 这基本上是函数 frexp() 的反函数。

math.modf(x)

返回 x 的小数和整数部分。两个结果都带有 x 的符号并且是浮点数。

math.nextafter(x, y)

返回 x 趋向于 y 的最接近的浮点数值。

如果 x 等于 y 则返回 y

示例:

  • math.nextafter(x, math.inf) 的方向朝上:趋向于正无穷。
  • math.nextafter(x, -math.inf) 的方向朝下:趋向于负无穷。
  • math.nextafter(x, 0.0) 趋向于零。
  • math.nextafter(x, math.copysign(math.inf, x)) 趋向于零的反方向。

3.9 新版功能.

math.perm(n, k=None)

返回不重复且有顺序地从 n 项中选择 k 项的方式总数。

k <= n 时取值为 n! / (n - k)!;当 k > n 时取值为零。

如果 k 未指定或为 None,则 k 默认值为 n 并且函数将返回 n!

如果任一参数不为整数则会引发 TypeError。 如果任一参数为负数则会引发 ValueError

3.8 新版功能.

math.prod(iterable, **, start=1*)

计算输入的 iterable 中所有元素的积。 积的默认 start 值为 1

当可迭代对象为空时,返回起始值。 此函数特别针对数字值使用,并会拒绝非数字类型。

3.8 新版功能.

math.remainder(x, y)

返回 IEEE 754 风格的 x 相对于 y 的余数。对于有限 x 和有限非零 y ,这是差异 x - n*y ,其中 n 是与商 x / y 的精确值最接近的整数。如果 x / y 恰好位于两个连续整数之间,则将最接近的 偶数 用作 n 。 余数 r = remainder(x, y) 因此总是满足 abs(r) <= 0.5 * abs(y)

特殊情况遵循IEEE 754:特别是 remainder(x, math.inf) 对于任何有限 x 都是 x ,而 remainder(x, 0)remainder(math.inf, x) 引发 ValueError 适用于任何非NaN的 x 。如果余数运算的结果为零,则该零将具有与 x 相同的符号。

在使用IEEE 754二进制浮点的平台上,此操作的结果始终可以完全表示:不会引入舍入错误。

3.7 新版功能.

math.trunc(x)

返回 Realx 截断为 Integral (通常是整数)。 委托给 x.__trunc__()

math.ulp(x)

返回浮点数 x 的最小有效比特位的值:

  • 如果 x 是 NaN (非数字),则返回 x
  • 如果 x 为负数,则返回 ulp(-x)
  • 如果 x 为正数,则返回 x
  • 如果 x 等于零,则返回 去正规化的 可表示最小正浮点数 (小于 正规化的 最小正浮点数 sys.float_info.min)。
  • 如果 x 等于可表示最大正浮点数,则返回 x 的最低有效比特位的值,使得小于 x 的第一个浮点数为 x - ulp(x)
  • 在其他情况下 (x 是一个有限的正数),则返回 x 的最低有效比特位的值,使得大于 x 的第一个浮点数为 x + ulp(x)

ULP 即 “Unit in the Last Place” 的缩写。

3.9 新版功能.

注意 frexp()modf() 具有与它们的C等价函数不同的调用/返回模式:它们采用单个参数并返回一对值,而不是通过 ‘输出形参’ 返回它们的第二个返回参数(Python中没有这样的东西)。

对于 ceil()floor()modf() 函数,请注意 所有 足够大的浮点数都是精确整数。Python浮点数通常不超过53位的精度(与平台C double类型相同),在这种情况下,任何浮点 xabs(x) >= 2**52 必然没有小数位。

幂函数与对数函数

math.exp(x)

返回 ex 幂,其中 e = 2.718281… 是自然对数的基数。这通常比 math.e ** xpow(math.e, x) 更精确。

math.expm1(x)

返回 ex 次幂,减1。这里 e 是自然对数的基数。对于小浮点数 xexp(x) - 1 中的减法可能导致 significant loss of precision; expm1() 函数提供了一种将此数量计算为全精度的方法:

>>> from math import exp, expm1
>>> exp(1e-5) - 1  # gives result accurate to 11 places
1.0000050000069649e-05
>>> expm1(1e-5)    # result accurate to full precision
1.0000050000166668e-05

3.2 新版功能.

math.log(x[, base])

使用一个参数,返回 x 的自然对数(底为 e )。

使用两个参数,返回给定的 base 的对数 x ,计算为 log(x)/log(base)

math.log1p(x)

返回 1+x 的自然对数(以 e 为底)。 以对于接近零的 x 精确的方式计算结果。

math.log2(x)

返回 x 以2为底的对数。这通常比 log(x, 2) 更准确。

3.3 新版功能.

参见

int.bit_length() 返回表示二进制整数所需的位数,不包括符号和前导零。

math.log10(x)

返回 x 底为10的对数。这通常比 log(x, 10) 更准确。

math.pow(x, y)

将返回 xy 次幂。特殊情况尽可能遵循C99标准的附录’F’。特别是, pow(1.0, x)pow(x, 0.0) 总是返回 1.0 ,即使 x 是零或NaN。 如果 xy 都是有限的, x 是负数, y 不是整数那么 pow(x, y) 是未定义的,并且引发 ValueError

与内置的 ** 运算符不同, math.pow() 将其参数转换为 float 类型。使用 ** 或内置的 pow() 函数来计算精确的整数幂。

math.sqrt(x)

返回 x 的平方根。

三角函数

math.acos(x)

返回以弧度为单位的 x 的反余弦值。 结果范围在 0pi 之间。

math.asin(x)

返回以弧度为单位的 x 的反正弦值。 结果范围在 -pi/2pi/2 之间。

math.atan(x)

返回以弧度为单位的 x 的反正切值。 结果范围在 -pi/2pi/2 之间。.

math.atan2(y, x)

以弧度为单位返回 atan(y / x) 。结果是在 -pipi 之间。从原点到点 (x, y) 的平面矢量使该角度与正X轴成正比。 atan2() 的点的两个输入的符号都是已知的,因此它可以计算角度的正确象限。 例如, atan(1)atan2(1, 1) 都是 pi/4 ,但 atan2(-1, -1)-3*pi/4

math.cos(x)

返回 x 弧度的余弦值。

math.dist(p, q)

返回 pq 两点之间的欧几里得距离,以一个坐标序列(或可迭代对象)的形式给出。 两个点必须具有相同的维度。

大致相当于:

sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))

3.8 新版功能.

math.hypot(\coordinates*)

返回欧几里得范数,sqrt(sum(x**2 for x in coordinates))。 这是从原点到坐标给定点的向量长度。

对于一个二维点 (x, y),这等价于使用毕达哥拉斯定义 sqrt(x*x + y*y) 计算一个直角三角形的斜边。

在 3.8 版更改: 添加了对 n 维点的支持。 之前的版本只支持二维点。

在 3.10 版更改: 改进了算法的精确性,使得最大误差在 1 ulp (最后一位的单位数值) 以下。 更为常见的情况是,结果几乎总是能正确地舍入到 1/2 ulp 范围之内。

math.sin(x)

返回 x 弧度的正弦值。

math.tan(x)

返回 x 弧度的正切值。

角度转换

math.degrees(x)

将角度 x 从弧度转换为度数。

math.radians(x)

将角度 x 从度数转换为弧度。

双曲函数

双曲函数 是基于双曲线而非圆来对三角函数进行模拟。

math.acosh(x)

返回 x 的反双曲余弦值。

math.asinh(x)

返回 x 的反双曲正弦值。

math.atanh(x)

返回 x 的反双曲正切值。

math.cosh(x)

返回 x 的双曲余弦值。

math.sinh(x)

返回 x 的双曲正弦值。

math.tanh(x)

返回 x 的双曲正切值。

特殊函数

math.erf(x)

返回 x 处的 error function 。

erf() 函数可用于计算传统的统计函数,如 累积标准正态分布

def phi(x):
    'Cumulative distribution function for the standard normal distribution'
    return (1.0 + erf(x / sqrt(2.0))) / 2.0

3.2 新版功能.

math.erfc(x)

返回 x 处的互补误差函数。 互补错误函数 定义为 1.0 - erf(x)。 它用于 x 的大值,从其中减去一个会导致 有效位数损失。

3.2 新版功能.

math.gamma(x)

返回 x 处的 伽马函数 值。

3.2 新版功能.

math.lgamma(x)

返回Gamma函数在 x 绝对值的自然对数。

3.2 新版功能.

常量

math.pi

数学常数 π = 3.141592…,精确到可用精度。

math.e

数学常数 e = 2.718281…,精确到可用精度。

math.tau

数学常数 τ = 6.283185…,精确到可用精度。Tau 是一个圆周常数,等于 2π,圆的周长与半径之比。更多关于 Tau 的信息可参考 Vi Hart 的视频 Pi is (still) Wrong。吃两倍多的派来庆祝 Tau 日 吧!

3.6 新版功能.

math.inf

浮点正无穷大。 (对于负无穷大,使用 -math.inf 。)相当于 float('inf') 的输出。

3.5 新版功能.

math.nan

浮点“非数字”(NaN)值。 相当于 float('nan') 的输出。

3.5 新版功能.

CPython implementation detail: math 模块主要包含围绕平台C数学库函数的简单包装器。特殊情况下的行为在适当情况下遵循C99标准的附录F。当前的实现将引发 ValueError 用于无效操作,如 sqrt(-1.0)log(0.0) (其中C99附件F建议发出无效操作信号或被零除), 和 OverflowError 用于溢出的结果(例如, exp(1000.0) )。除非一个或多个输入参数是NaN,否则不会从上述任何函数返回NaN;在这种情况下,大多数函数将返回一个NaN,但是(再次遵循C99附件F)这个规则有一些例外,例如 pow(float('nan'), 0.0)hypot(float('nan'), float('inf'))

请注意,Python不会将显式NaN与静默NaN区分开来,并且显式NaN的行为仍未明确。典型的行为是将所有NaN视为静默的。

cmath —- 关于复数的数学函数

这一模块提供了一些关于复数的数学函数。 该模块的函数的参数为整数、浮点数或复数。 这些函数的参数也可为一个拥有 __complex__()__float__() 方法的 Python 对象,这些方法分别用于将对象转换为复数和浮点数,这些函数作用于转换后的结果。

注解

在具有对于有符号零的硬件和系统级支持的平台上,涉及支割线的函数在支割线的 两侧 都是连续的:零的符号可用来区别支割线的一侧和另一侧。 在不支持有符号零的平台上,连续性的规则见下文。

到极坐标和从极坐标的转换

使用 矩形坐标笛卡尔坐标 在内部存储 Python 复数 z。 这完全取决于它的 实部 z.real虚部 z.imag。 换句话说:

z == z.real + z.imag*1j

极坐标 提供了另一种复数的表示方法。在极坐标中,一个复数 z 由模量 r 和相位角 phi 来定义。模量 r 是从 z 到坐标原点的距离,而相位角 phi 是以弧度为单位的,逆时针的,从正X轴到连接原点和 z 的线段间夹角的角度。

下面的函数可用于原生直角坐标与极坐标的相互转换。

cmath.phase(x)

x 的相位 (也称为 x参数) 返回为一个浮点数。phase(x) 相当于 math.atan2(x.imag, x.real)。 结果处于 [-π, π] 之间,以及这个操作的分支切断处于负实轴上,从上方连续。 在支持有符号零的系统上(这包涵大多数当前的常用系统),这意味着结果的符号与 x.imag 的符号相同,即使 x.imag 的值是 0:

>>> phase(complex(-1.0, 0.0))
3.141592653589793
>>> phase(complex(-1.0, -0.0))
-3.141592653589793

注解

一个复数 x 的模数(绝对值)可以通过内置函数 abs() 计算。没有单独的 cmath 模块函数用于这个操作。

cmath.polar(x)

在极坐标中返回 x 的表达方式。返回一个数对 (r, phi)rx 的模数,phix 的相位角。 polar(x) 相当于 (abs(x), phase(x))

cmath.rect(r, phi)

通过极坐标的 rphi 返回复数 x。相当于 r * (math.cos(phi) + math.sin(phi)*1j)

幂函数与对数函数

cmath.exp(x)

返回 ex 次方,e 是自然对数的底数。

cmath.log(x[, base])

返回给定 basex 的对数。如果没有给定 base*,返回 *x 的自然对数。 从 0 到 -∞ 存在一条支割线,沿负实轴之上连续。

cmath.log10(x)

返回底数为 10 的 x 的对数。它具有与 log() 相同的支割线。

cmath.sqrt(x)

返回 x 的平方根。 它具有与 log() 相同的支割线。

三角函数

cmath.acos(x)

返回 x 的反余弦。这里有两条支割线:一条沿着实轴从 1 向右延伸到 ∞,从下面连续延伸。另外一条沿着实轴从 -1 向左延伸到 -∞,从上面连续延伸。

cmath.asin(x)

返回 x 的反正弦。它与 acos() 有相同的支割线。

cmath.atan(x)

返回 x 的反正切。它具有两条支割线:一条沿着虚轴从 1j 延伸到 ∞j,向右持续延伸。另一条是沿着虚轴从 -1j 延伸到 -∞j ,向左持续延伸。

cmath.cos(x)

返回 x 的余弦。

cmath.sin(x)

返回 x 的正弦。

cmath.tan(x)

返回 x 的正切。

双曲函数

cmath.acosh(x)

返回 x 的反双曲余弦。它有一条支割线沿着实轴从 1 到 -∞ 向左延伸,从上方持续延伸。

cmath.asinh(x)

返回 x 的反双曲正弦。它有两条支割线:一条沿着虚轴从 1j 向右持续延伸到 ∞j。另一条是沿着虚轴从 -1j 向左持续延伸到 -∞j

cmath.atanh(x)

返回 x 的反双曲正切。它有两条支割线:一条是沿着实轴从 1 延展到 ,从下面持续延展。另一条是沿着实轴从 -1 延展到 -∞,从上面持续延展。

cmath.cosh(x)

返回 x 的双曲余弦值。

cmath.sinh(x)

返回 x 的双曲正弦值。

cmath.tanh(x)

返回 x 的双曲正切值。

分类函数

cmath.isfinite(x)

如果 x 的实部和虚部都是有限的,则返回 True,否则返回 False

3.2 新版功能.

cmath.isinf(x)

如果 x 的实部或者虚部是无穷大的,则返回 True,否则返回 False

cmath.isnan(x)

如果 x 的实部或者虚部是 NaN,则返回 True ,否则返回 False

cmath.isclose(a, b, **, rel_tol=1e-09, abs_tol=0.0*)

ab 的值比较接近则返回 True,否则返回 False

根据给定的绝对和相对容差确定两个值是否被认为是接近的。

rel_tol 是相对容差 —— 它是 ab 之间允许的最大差值,相对于 ab 的较大绝对值。例如,要设置5%的容差,请传递 rel_tol=0.05 。默认容差为 1e-09,确保两个值在大约9位十进制数字内相同。 rel_tol 必须大于零。

abs_tol 是最小绝对容差 —— 对于接近零的比较很有用。 abs_tol 必须至少为零。

如果没有错误发生,结果将是: abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

IEEE 754特殊值 NaNinf-inf 将根据IEEE规则处理。具体来说, NaN 不被认为接近任何其他值,包括 NaNinf-inf 只被认为接近自己。

3.5 新版功能.

参见

PEP 485 —— 用于测试近似相等的函数

常量

cmath.pi

数学常数 π ,作为一个浮点数。

cmath.e

数学常数 e ,作为一个浮点数。

cmath.tau

数学常数 τ ,作为一个浮点数。

3.6 新版功能.

cmath.inf

浮点正无穷大。相当于 float('inf')

3.6 新版功能.

cmath.infj

具有零实部和正无穷虚部的复数。相当于 complex(0.0, float('inf'))

3.6 新版功能.

cmath.nan

浮点“非数字”(NaN)值。相当于 float('nan')

3.6 新版功能.

cmath.nanj

具有零实部和 NaN 虚部的复数。相当于 complex(0.0, float('nan'))

3.6 新版功能.

请注意,函数的选择与模块 math 中的函数选择相似,但不完全相同。 拥有两个模块的原因是因为有些用户对复数不感兴趣,甚至根本不知道它们是什么。它们宁愿 math.sqrt(-1) 引发异常,也不想返回一个复数。 另请注意,被 cmath 定义的函数始终会返回一个复数,尽管答案可以表示为一个实数(在这种情况下,复数的虚数部分为零)。

关于支割线的注释:它们是沿着给定函数无法连续的曲线。它们是许多复变函数的必要特征。 假设您需要使用复变函数进行计算,您将会了解支割线的概念。 请参阅几乎所有关于复变函数的(不太基本)的书来获得启发。

decimal —- 十进制定点和浮点运算

源码: Lib/decimal.py


decimal 模块为快速正确舍入的十进制浮点运算提供支持。 与 float 数据类型相比,它具有以下几个优点:

  • Decimal 类型的“设计是基于考虑人类习惯的浮点数模型,并且因此具有以下最高指导原则 —— 计算机必须提供与人们在学校所学习的算术相一致的算术。” —— 摘自 decimal 算术规范描述。

  • Decimal 数字的表示是完全精确的。 相比之下,1.12.2 这样的数字在二进制浮点中没有精确的表示。 最终用户通常不希望 1.1 + 2.2 如二进制浮点数表示那样被显示为 3.3000000000000003

  • 精确性会延续到算术类操作中。 对于 decimal 浮点数,0.1 + 0.1 + 0.1 - 0.3 会精确地等于零。 而对于二进制浮点数,结果则为 5.5511151231257827e-017 。 虽然接近于零,但其中的误差将妨碍可靠的相等性检验,并且误差还会不断累积。 因此,decimal 更适合具有严格相等不变性要求的会计类应用。

  • 十进制模块包含有效位的概念,因此 1.30 + 1.20 的结果是 2.50 。 保留尾随零以表示有效位。 这是货币的惯用表示方法。乘法则沿用 “教科书“ 中:保留被乘数中的所有数字的方法。 例如, 1.3 * 1.2 结果是 1.561.30 * 1.20 结果是 1.5600

  • 与基于硬件的二进制浮点不同,十进制模块具有用户可更改的精度(默认为28位),可以与给定问题所需的一样大:

    >>> from decimal import *
    >>> getcontext().prec = 6
    >>> Decimal(1) / Decimal(7)
    Decimal('0.142857')
    >>> getcontext().prec = 28
    >>> Decimal(1) / Decimal(7)
    Decimal('0.1428571428571428571428571429')
  • 二进制和 decimal 浮点数都是根据已发布的标准实现的。 虽然内置浮点类型只公开其功能的一小部分,但 decimal 模块公开了标准的所有必需部分。 在需要时,程序员可以完全控制舍入和信号处理。 这包括通过使用异常来阻止任何不精确操作来强制执行精确算术的选项。

  • decimal 模块旨在支持“无偏差,精确无舍入的十进制算术(有时称为定点数算术)和有舍入的浮点数算术”。 —— 摘自 decimal 算术规范说明。

该模块的设计以三个概念为中心:decimal 数值,算术上下文和信号。

decimal 数值是不可变对象。 它由符号,系数和指数位组成。 为了保持有效位,系数位不会截去末尾零。 decimal 数值也包括特殊值例如 Infinity-InfinityNaN 。 该标准还区分 -0+0

算术的上下文是指定精度、舍入规则、指数限制、指示操作结果的标志以及确定符号是否被视为异常的陷阱启用器的环境。 舍入选项包括 ROUND_CEILINGROUND_DOWNROUND_FLOORROUND_HALF_DOWN, ROUND_HALF_EVENROUND_HALF_UPROUND_UP 以及 ROUND_05UP.

信号是在计算过程中出现的异常条件组。 根据应用程序的需要,信号可能会被忽略,被视为信息,或被视为异常。 十进制模块中的信号有:ClampedInvalidOperationDivisionByZeroInexactRoundedSubnormalOverflowUnderflow 以及 FloatOperation

对于每个信号,都有一个标志和一个陷阱启动器。 遇到信号时,其标志设置为 1 ,然后,如果陷阱启用器设置为 1 ,则引发异常。 标志是粘性的,因此用户需要在监控计算之前重置它们。

参见

快速入门教程

通常使用 decimal 的方式是先导入该模块,通过 getcontext() 查看当前上下文,并在必要时为精度、舍入或启用的陷阱设置新值:

>>> from decimal import *
>>> getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
        InvalidOperation])
>>> getcontext().prec = 7       # Set a new precision

可以基于整数、字符串、浮点数或元组构造 Decimal 实例。 基于整数或浮点数构造将执行该整数或浮点值的精确转换。 Decimal 数字包括特殊值例如 NaN 表示“非数字”,正的和负的 Infinity-0

>>> getcontext().prec = 28
>>> Decimal(10)
Decimal('10')
>>> Decimal('3.14')
Decimal('3.14')
>>> Decimal(3.14)
Decimal('3.140000000000000124344978758017532527446746826171875')
>>> Decimal((0, (3, 1, 4), -2))
Decimal('3.14')
>>> Decimal(str(2.0 ** 0.5))
Decimal('1.4142135623730951')
>>> Decimal(2) ** Decimal('0.5')
Decimal('1.414213562373095048801688724')
>>> Decimal('NaN')
Decimal('NaN')
>>> Decimal('-Infinity')
Decimal('-Infinity')

如果 FloatOperation 信号被捕获,构造函数中的小数和浮点数的意外混合或排序比较会引发异常

>>> c = getcontext()
>>> c.traps[FloatOperation] = True
>>> Decimal(3.14)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') < 3.7
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.FloatOperation: [<class 'decimal.FloatOperation'>]
>>> Decimal('3.5') == 3.5
True

3.3 新版功能.

新 Decimal 的重要性仅由输入的位数决定。 上下文精度和舍入仅在算术运算期间发挥作用。

>>> getcontext().prec = 6
>>> Decimal('3.0')
Decimal('3.0')
>>> Decimal('3.1415926535')
Decimal('3.1415926535')
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85987')
>>> getcontext().rounding = ROUND_UP
>>> Decimal('3.1415926535') + Decimal('2.7182818285')
Decimal('5.85988')

如果超出了 C 版本的内部限制,则构造一个 decimal 将引发 InvalidOperation

>>> Decimal("1e9999999999999999999")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]

在 3.3 版更改.

Decimal 数字能很好地与 Python 的其余部分交互。 以下是一个小小的 decimal 浮点数飞行马戏团:

>>> data = list(map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()))
>>> max(data)
Decimal('9.25')
>>> min(data)
Decimal('0.03')
>>> sorted(data)
[Decimal('0.03'), Decimal('1.00'), Decimal('1.34'), Decimal('1.87'),
 Decimal('2.35'), Decimal('3.45'), Decimal('9.25')]
>>> sum(data)
Decimal('19.29')
>>> a,b,c = data[:3]
>>> str(a)
'1.34'
>>> float(a)
1.34
>>> round(a, 1)
Decimal('1.3')
>>> int(a)
1
>>> a * 5
Decimal('6.70')
>>> a * b
Decimal('2.5058')
>>> c % a
Decimal('0.77')

Decimal 也可以使用一些数学函数:

>>> getcontext().prec = 28
>>> Decimal(2).sqrt()
Decimal('1.414213562373095048801688724')
>>> Decimal(1).exp()
Decimal('2.718281828459045235360287471')
>>> Decimal('10').ln()
Decimal('2.302585092994045684017991455')
>>> Decimal('10').log10()
Decimal('1')

quantize() 方法将数字舍入为固定指数。 此方法对于将结果舍入到固定的位置的货币应用程序非常有用:

>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN)
Decimal('7.32')
>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP)
Decimal('8')

如上所示,getcontext() 函数访问当前上下文并允许更改设置。 这种方法满足大多数应用程序的需求。

对于更高级的工作,使用 Context() 构造函数创建备用上下文可能很有用。 要使用备用活动,请使用 setcontext() 函数。

根据标准,decimal 模块提供了两个现成的标准上下文 BasicContextExtendedContext 。 前者对调试特别有用,因为许多陷阱都已启用:

>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN)
>>> setcontext(myothercontext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857142857142857142857142857')
>>> ExtendedContext
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[], traps=[])
>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(7)
Decimal('0.142857143')
>>> Decimal(42) / Decimal(0)
Decimal('Infinity')
>>> setcontext(BasicContext)
>>> Decimal(42) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#143>", line 1, in -toplevel-
    Decimal(42) / Decimal(0)
DivisionByZero: x / 0

上下文还具有用于监视计算期间遇到的异常情况的信号标志。 标志保持设置直到明确清除,因此最好通过使用 clear_flags() 方法清除每组受监控计算之前的标志。:

>>> setcontext(ExtendedContext)
>>> getcontext().clear_flags()
>>> Decimal(355) / Decimal(113)
Decimal('3.14159292')
>>> getcontext()
Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
        capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[])

flags 条目显示对 Pi 的有理逼近被舍入(超出上下文精度的数字被抛弃)并且结果是不精确的(一些丢弃的数字不为零)。

使用上下文的 traps 字段中的字典设置单个陷阱:

>>> setcontext(ExtendedContext)
>>> Decimal(1) / Decimal(0)
Decimal('Infinity')
>>> getcontext().traps[DivisionByZero] = 1
>>> Decimal(1) / Decimal(0)
Traceback (most recent call last):
  File "<pyshell#112>", line 1, in -toplevel-
    Decimal(1) / Decimal(0)
DivisionByZero: x / 0

大多数程序仅在程序开始时调整当前上下文一次。 并且,在许多应用程序中,数据在循环内单个强制转换为 Decimal 。 通过创建上下文集和小数,程序的大部分操作数据与其他 Python 数字类型没有区别。

Decimal 对象

class decimal.Decimal(value=’0’, context=None)

根据 value 构造一个新的 Decimal 对象。

value 可以是整数,字符串,元组,float ,或另一个 Decimal 对象。 如果没有给出 value*,则返回 Decimal('0')。 如果 *value 是一个字符串,它应该在前导和尾随空格字符以及下划线被删除之后符合十进制数字字符串语法:

sign           ::=  '+' | '-'
digit          ::=  '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator      ::=  'e' | 'E'
digits         ::=  digit [digit]...
decimal-part   ::=  digits '.' [digits] | ['.'] digits
exponent-part  ::=  indicator [sign] digits
infinity       ::=  'Infinity' | 'Inf'
nan            ::=  'NaN' [digits] | 'sNaN' [digits]
numeric-value  ::=  decimal-part [exponent-part] | infinity
numeric-string ::=  [sign] numeric-value | [sign] nan

当上面出现 digit 时也允许其他十进制数码。 其中包括来自各种其他语言系统的十进制数码(例如阿拉伯-印地语和天城文的数码)以及全宽数码 '\uff10''\uff19'

如果 value 是一个 tuple ,它应该有三个组件,一个符号( 0 表示正数或 1 表示负数),一个数字的 tuple 和整数指数。 例如, Decimal((0, (1, 4, 1, 4), -3)) 返回 Decimal('1.414')

如果 valuefloat ,则二进制浮点值无损地转换为其精确的十进制等效值。 此转换通常需要53位或更多位数的精度。 例如, Decimal(float('1.1')) 转换为Decimal(‘1.100000000000000088817841970012523233890533447265625’)

context 精度不会影响存储的位数。 这完全由 value 中的位数决定。 例如,Decimal('3.00000') 记录所有五个零,即使上下文精度只有三。

context 参数的目的是确定 value 是格式错误的字符串时该怎么做。 如果上下文陷阱 InvalidOperation,则引发异常;否则,构造函数返回一个新的 Decimal,其值为 NaN

构造完成后, Decimal 对象是不可变的。

在 3.2 版更改: 现在允许构造函数的参数为 float 实例。

在 3.3 版更改: float 参数在设置 FloatOperation 陷阱时引发异常。 默认情况下,陷阱已关闭。

在 3.6 版更改: 允许下划线进行分组,就像代码中的整数和浮点文字一样。

十进制浮点对象与其他内置数值类型共享许多属性,例如 floatint 。 所有常用的数学运算和特殊方法都适用。 同样,十进制对象可以复制、pickle、打印、用作字典键、用作集合元素、比较、排序和强制转换为另一种类型(例如 floatint )。

算术对十进制对象和算术对整数和浮点数有一些小的差别。 当余数运算符 % 应用于Decimal对象时,结果的符号是 被除数 的符号,而不是除数的符号:

>>> (-7) % 4
1
>>> Decimal(-7) % Decimal(4)
Decimal('-3')

整数除法运算符 // 的行为类似,返回真商的整数部分(截断为零)而不是它的向下取整,以便保留通常的标识 x == (x // y) * y + x % y:

>>> -7 // 4
-2
>>> Decimal(-7) // Decimal(4)
Decimal('-1')

%// 运算符实现了 remainderdivide-integer 操作(分别),如规范中所述。

十进制对象通常不能与浮点数或 fractions.Fraction 实例在算术运算中结合使用:例如,尝试将 Decimal 加到 float ,将引发 TypeError。 但是,可以使用 Python 的比较运算符来比较 Decimal 实例 x 和另一个数字 y 。 这样可以避免在对不同类型的数字进行相等比较时混淆结果。

在 3.2 版更改: 现在完全支持 Decimal 实例和其他数字类型之间的混合类型比较。

除了标准的数字属性,十进制浮点对象还有许多专门的方法:

  • adjusted()

    在移出系数最右边的数字之后返回调整后的指数,直到只剩下前导数字:Decimal('321e+5').adjusted() 返回 7 。 用于确定最高有效位相对于小数点的位置。

  • as_integer_ratio()

    返回一对 (n, d) 整数,表示给定的 Decimal 实例作为分数、最简形式项并带有正分母:

    >>> Decimal('-3.14').as_integer_ratio()
    (-157, 50)

    转换是精确的。 在 Infinity 上引发 OverflowError ,在 NaN 上引起 ValueError 。

3.6 新版功能.

  • as_tuple()

    返回一个 named tuple 表示的数字: DecimalTuple(sign, digits, exponent)

  • canonical()

    返回参数的规范编码。 目前,一个 Decimal 实例的编码始终是规范的,因此该操作返回其参数不变。

  • compare(other, context=None)

    比较两个 Decimal 实例的值。 compare() 返回一个 Decimal 实例,如果任一操作数是 NaN ,那么结果是 NaN

    a or b is a NaN  ==> Decimal('NaN')
    a < b            ==> Decimal('-1')
    a == b           ==> Decimal('0')
    a > b            ==> Decimal('1')
  • compare_signal(other, context=None)

    除了所有 NaN 信号之外,此操作与 compare() 方法相同。 也就是说,如果两个操作数都不是信令NaN,那么任何静默的 NaN 操作数都被视为信令NaN。

  • compare_total(other, context=None)

    使用它们的抽象表示而不是它们的数值来比较两个操作数。 类似于 compare() 方法,但结果给出了一个总排序 Decimal 实例。 两个 Decimal 实例具有相同的数值但不同的表示形式在此排序中比较不相等:

    >>> Decimal('12.0').compare_total(Decimal('12'))
    Decimal('-1')

    静默和发出信号的 NaN 也包括在总排序中。 这个函数的结果是 Decimal('0') 如果两个操作数具有相同的表示,或是 Decimal('-1') 如果第一个操作数的总顺序低于第二个操作数,或是 Decimal('1') 如果第一个操作数在总顺序中高于第二个操作数。 有关总排序的详细信息,请参阅规范。

    此操作不受上下文影响且静默:不更改任何标志且不执行舍入。 作为例外,如果无法准确转换第二个操作数,则C版本可能会引发InvalidOperation。

  • compare_total_mag(other, context=None)

    比较两个操作数使用它们的抽象表示而不是它们的值,如 compare_total(),但忽略每个操作数的符号。 x.compare_total_mag(y) 相当于 x.copy_abs().compare_total(y.copy_abs())

    此操作不受上下文影响且静默:不更改任何标志且不执行舍入。 作为例外,如果无法准确转换第二个操作数,则C版本可能会引发InvalidOperation。

  • conjugate()

    只返回self,这种方法只符合 Decimal 规范。

  • copy_abs()

    返回参数的绝对值。 此操作不受上下文影响并且是静默的:没有更改标志且不执行舍入。

  • copy_negate()

    回到参数的否定。 此操作不受上下文影响并且是静默的:没有标志更改且不执行舍入。

  • copy_sign(other, context=None)

    返回第一个操作数的副本,其符号设置为与第二个操作数的符号相同。 例如:

    >>> Decimal('2.3').copy_sign(Decimal('-1.5'))
    Decimal('-2.3')

    此操作不受上下文影响且静默:不更改任何标志且不执行舍入。 作为例外,如果无法准确转换第二个操作数,则C版本可能会引发InvalidOperation。

  • exp(context=None)

    返回给定数字的(自然)指数函数e**x的值。结果使用 ROUND_HALF_EVEN 舍入模式正确舍入。

    >>> Decimal(1).exp()
    Decimal('2.718281828459045235360287471')
    >>> Decimal(321).exp()
    Decimal('2.561702493119680037517373933E+139')
  • from_float(f)

    将浮点数转换为十进制数的类方法。

    注意, Decimal.from_float(0.1) 与 Decimal(‘0.1’) 不同。 由于 0.1 在二进制浮点中不能精确表示,因此该值存储为最接近的可表示值,即 0x1.999999999999ap-4 。 十进制的等效值是0.1000000000000000055511151231257827021181583404541015625

    注解

    从 Python 3.2 开始,Decimal 实例也可以直接从 float 构造。

    >>> Decimal.from_float(0.1)
    Decimal('0.1000000000000000055511151231257827021181583404541015625')
    >>> Decimal.from_float(float('nan'))
    Decimal('NaN')
    >>> Decimal.from_float(float('inf'))
    Decimal('Infinity')
    >>> Decimal.from_float(float('-inf'))
    Decimal('-Infinity')

    3.1 新版功能.

  • fma(other, third, context=None)

    混合乘法加法。 返回 selfother+third ,中间乘积 selfother 没有舍入。

    >>> Decimal(2).fma(3, 5)
    Decimal('11')
  • is_canonical()

    如果参数是规范的,则为返回 True,否则为 False 。 目前,Decimal 实例总是规范的,所以这个操作总是返回 True

  • is_finite()

    如果参数是一个有限的数,则返回为 True ;如果参数为无穷大或 NaN ,则返回为 False

  • is_infinite()

    如果参数为正负无穷大,则返回为 True ,否则为 False

  • is_nan()

    如果参数为 NaN (无论是否静默),则返回为 True ,否则为 False

  • is_normal(context=None)

    如果参数是一个 标准的 有限数则返回 True。 如果参数为零、次标准数、无穷大或 NaN 则返回 False

  • is_qnan()

    如果参数为静默 NaN,返回 True,否则返回 False

  • is_signed()

    如果参数带有负号,则返回为 True,否则返回 False。注意,0 和 NaN 都可带有符号。

  • is_snan()

    如果参数为显式 NaN,则返回 True,否则返回 False

  • is_subnormal(context=None)

    如果参数为次标准数,则返回 True,否则返回 False

  • is_zero()

    如果参数是0(正负皆可),则返回 True,否则返回 False

  • ln(context=None)

    返回操作数的自然对数(以 e 为底)。结果是使用 ROUND_HALF_EVEN 舍入模式正确舍入的。

  • log10(context=None)

    返回操作数的以十为底的对数。结果是使用 ROUND_HALF_EVEN 舍入模式正确舍入的。

  • logb(context=None)

    对于一个非零数,返回其运算数的调整后指数作为一个 Decimal 实例。 如果运算数为零将返回 Decimal('-Infinity') 并且产生 the DivisionByZero 标志。如果运算数是无限大则返回 Decimal('Infinity')

  • logical_and(other, context=None)

    logical_and() 是需要两个 逻辑运算数 的逻辑运算。按位输出两运算数的 and 运算的结果。

  • logical_invert(context=None)

    logical_invert() 是一个逻辑运算。结果是操作数的按位求反。

  • logical_or(other, context=None)

    logical_or() 是需要两个 logical operands 的逻辑运算。结果是两个运算数的按位的 or 运算。

  • logical_xor(other, context=None)

    logical_xor() 是需要两个 逻辑运算数 的逻辑运算。结果是按位输出的两运算数的异或运算。

  • max(other, context=None)

    max(self, other) 一样,除了在返回之前应用上下文舍入规则并且用信号通知或忽略 NaN 值(取决于上下文以及它们是发信号还是安静)。

  • max_mag(other, context=None)

    max() 方法相似,但是操作数使用绝对值完成比较。

  • min(other, context=None)

    min(self, other) 一样,除了在返回之前应用上下文舍入规则并且用信号通知或忽略 NaN 值(取决于上下文以及它们是发信号还是安静)。

  • min_mag(other, context=None)

    min() 方法相似,但是操作数使用绝对值完成比较。

  • next_minus(context=None)

    返回小于给定操作数的上下文中可表示的最大数字(或者当前线程的上下文中的可表示的最大数字如果没有给定上下文)。

  • next_plus(context=None)

    返回大于给定操作数的上下文中可表示的最小数字(或者当前线程的上下文中的可表示的最小数字如果没有给定上下文)。

  • next_toward(other, context=None)

    如果两运算数不相等,返回在第二个操作数的方向上最接近第一个操作数的数。如果两操作数数值上相等,返回将符号设置为与第二个运算数相同的第一个运算数的拷贝。

  • normalize(context=None)

    通过去除尾随的零并将所有结果等于 Decimal('0') 的转化为 Decimal('0e0') 来标准化数字。用于为等效类的属性生成规范值。比如, Decimal('32.100')Decimal('0.321000e+2') 都被标准化为相同的值 Decimal('32.1')

  • number_class(context=None)

    返回一个字符串描述运算数的 class 。返回值是以下十个字符串中的一个。

    • "-Infinity" ,指示运算数为负无穷大。
    • "-Normal" ,指示该运算数是负正常数字。
    • "-Subnormal" ,指示该运算数是负的次标准数。
    • "-Zero" ,指示该运算数是负零。
    • "-Zero" ,指示该运算数是正零。
    • "+Subnormal" ,指示该运算数是正的次标准数。
    • "+Normal" ,指示该运算数是正的标准数。
    • "+Infinity" ,指示该运算数是正无穷。
    • "NaN" ,指示该运算数是肃静 NaN (非数字)。
    • "sNaN" ,指示该运算数是信号 NaN 。
  • quantize(exp, rounding=None, context=None)

    返回的值等于舍入后的第一个运算数并且具有第二个操作数的指数。

    >>> Decimal('1.41421356').quantize(Decimal('1.000'))
    Decimal('1.414')

    与其他运算不同,如果量化运算后的系数长度大于精度,那么会发出一个 InvalidOperation 信号。这保证了除非有一个错误情况,量化指数恒等于右手运算数的指数。

    与其他运算不同,量化永不信号下溢,即使结果不正常且不精确。

    如果第二个运算数的指数大于第一个运算数的指数那或许需要舍入。在这种情况下,舍入模式由给定 rounding 参数决定,其余的由给定 context 参数决定;如果参数都未给定,使用当前线程上下文的舍入模式。

    每当结果的指数大于 Emax 或小于 Etiny 就会返回错误。

  • radix()

    返回 Decimal(10),即 Decimal 类进行所有算术运算所用的数制(基数)。 这是为保持与规范描述的兼容性而加入的。

  • remainder_near(other, context=None)

    返回 self 除以 other 的余数。 这与 self % other 的区别在于所选择的余数要使其绝对值最小化。 更准确地说,返回值为 self - n * other 其中 n 是最接近 self / other 的实际值的整数,并且如果两个整数与实际值的差相等则会选择其中的偶数。

    如果结果为零则其符号将为 self 的符号。

    >>> Decimal(18).remainder_near(Decimal(10))
    Decimal('-2')
    >>> Decimal(25).remainder_near(Decimal(10))
    Decimal('5')
    >>> Decimal(35).remainder_near(Decimal(10))
    Decimal('-5')
  • rotate(other, context=None)

    返回对第一个操作数的数码按第二个操作数所指定的数量进行轮转的结果。 第二个操作数必须为 -precision 至 precision 精度范围内的整数。 第二个操作数的绝对值给出要轮转的位数。 如果第二个操作数为正值则向左轮转;否则向右轮转。 如有必要第一个操作数的系数会在左侧填充零以达到 precision 所指定的长度。 第一个操作数的符号和指数保持不变。

  • same_quantum(other, context=None)

    检测自身与 other 是否具有相同的指数或是否均为 NaN

    此操作不受上下文影响且静默:不更改任何标志且不执行舍入。 作为例外,如果无法准确转换第二个操作数,则C版本可能会引发InvalidOperation。

  • scaleb(other, context=None)

    返回第一个操作数使用第二个操作数对指数进行调整的结果。 等价于返回第一个操作数乘以 10**other 的结果。 第二个操作数必须为整数。

  • shift(other, context=None)

    返回第一个操作数的数码按第二个操作数所指定的数量进行移位的结果。 第二个操作数必须为 -precision 至 precision 范围内的整数。 第二个操作数的绝对值给出要移动的位数。 如果第二个操作数为正值则向左移位;否则向右移位。 移入系数的数码为零。 第一个操作数的符号和指数保持不变。

  • sqrt(context=None)

    返回参数的平方根精确到完整精度。

  • to_eng_string(context=None)

    转换为字符串,如果需要指数则会使用工程标注法。

    工程标注法的指数是 3 的倍数。 这会在十进制位的左边保留至多 3 个数码,并可能要求添加一至两个末尾零。

    例如,此方法会将 Decimal('123E+1') 转换为 Decimal('1.23E+3')

  • to_integral(rounding=None, context=None)

    to_integral_value() 方法相同。 保留 to_integral 名称是为了与旧版本兼容。

  • to_integral_exact(rounding=None, context=None)

    舍入到最接近的整数,发出信号 Inexact 或者如果发生舍入则相应地发出信号 Rounded。 如果给出 rounding 形参则由其确定舍入模式,否则由给定的 context 来确定。 如果没有给定任何形参则会使用当前上下文的舍入模式。

  • to_integral_value(rounding=None, context=None)

    舍入到最接近的整数而不发出 InexactRounded 信号。 如果给出 rounding 则会应用其所指定的舍入模式;否则使用所提供的 context 或当前上下文的舍入方法。

逻辑操作数

logical_and(), logical_invert(), logical_or()logical_xor() 方法期望其参数为 逻辑操作数*。 *逻辑操作数 是指数位与符号位均为零的 Decimal 实例,并且其数字位均为 01

上下文对象

上下文是算术运算所在的环境。 它们管理精度、设置舍入规则、确定将哪些信号视为异常,并限制指数的范围。

每个线程都有自己的当前上下文,可使用 getcontext()setcontext() 函数来读取或修改:

decimal.getcontext()

返回活动线程的当前上下文。

decimal.setcontext(c)

将活动线程的当前上下文设为 c

你也可以使用 with 语句和 localcontext() 函数来临时改变活动上下文。

decimal.localcontext(ctx=None)

返回一个上下文管理器,它将在进入 with 语句时将活动线程的当前上下文设为 ctx 的一个副本并在退出 with 语句时恢复之前的上下文。 如果未指定上下文,则会使用当前上下文的一个副本。

例如,以下代码会将当前 decimal 精度设为 42 位,执行一个运算,然后自动恢复之前的上下文:

from decimal import localcontext
with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

新的上下文也可使用下述的 Context 构造器来创建。 此外,模块还提供了三种预设的上下文:

class decimal.BasicContext

这是由通用十进制算术规范描述所定义的标准上下文。 精度设为九。 舍入设为 ROUND_HALF_UP。 清除所有旗标。 启用所有陷阱(视为异常),但 Inexact, RoundedSubnormal 除外。

由于启用了许多陷阱,此上下文适用于进行调试。

class decimal.ExtendedContext

这是由通用十进制算术规范描述所定义的标准上下文。 精度设为九。 舍入设为 ROUND_HALF_EVEN。 清除所有旗标。 不启用任何陷阱(因此在计算期间不会引发异常)。

由于禁用了陷阱,此上下文适用于希望结果值为 NaNInfinity 而不是引发异常的应用。 这允许应用在出现当其他情况下会中止程序的条件时仍能完成运行。

class decimal.DefaultContext

此上下文被 Context 构造器用作新上下文的原型。 改变一个字段(例如精度)的效果将是改变 Context 构造器所创建的新上下文的默认值。

此上下文最适用于多线程环境。 在线程开始前改变一个字段具有设置全系统默认值的效果。 不推荐在线程开始后改变字段,因为这会要求线程同步避免竞争条件。

在单线程环境中,最好完全不使用此上下文。 而是简单地电显式创建上下文,具体如下所述。

默认值为 prec=28, rounding=ROUND_HALF_EVEN,并为 Overflow, InvalidOperationDivisionByZero 启用陷阱。

在已提供的三种上下文之外,还可以使用 Context 构造器创建新的上下文。

class decimal.Context(prec=None, rounding=None, Emin=None, Emax=None, capitals=None, clamp=None, flags=None, traps=None)

创建一个新上下文。 如果某个字段未指定或为 None,则从 DefaultContext 拷贝默认值。 如果 flags 字段未指定或为 None,则清空所有旗标。

prec 为一个 [1, MAX_PREC] 范围内的整数,用于设置该上下文中算术运算的精度。

rounding 选项应为 Rounding Modes 小节中列出的常量之一。

trapsflags 字段列出要设置的任何信号。 通常,新上下文应当只设置 traps 而让 flags 为空。

EminEmax 字段给定指数所允许的外部上限。 Emin 必须在 [MIN_EMIN, 0] 范围内,Emax 在 [0, MAX_EMAX] 范围内。

capitals 字段为 01 (默认值)。 如果设为 1,指数将附带打印大写的 E;其他情况则将使用小写的 e: Decimal('6.02e+23')

clamp 字段为 0 (默认值) 或 1。 如果设为 1,则 Decimal 实例的指数 e 的表示范围在此上下文中将严格限制为 Emin - prec + 1 <= e <= Emax - prec + 1。 如果 clamp0 则将适用较弱的条件: Decimal 实例调整后的指数最大值为 Emax。 当 clamp1 时,一个较大的普通数值将在可能的情况下减小其指数并为其系统添加相应数量的零,以便符合指数值限制;这可以保持数字值但会丢失有效末尾零的信息。 例如:

>>> Context(prec=6, Emax=999, clamp=1).create_decimal('1.23e999')
Decimal('1.23000E+999')

clamp 值为 1 时即允许与在 IEEE 754 中描述的固定宽度十进制交换格式保持兼容性。

Context 类定义了几种通用方法以及大量直接在给定上下文中进行算术运算的方法。 此外,对于上述的每种 Decimal 方法(不包括 adjusted()as_tuple() 方法)都有一个相应的 Context 方法。 例如,对于一个 Context 的实例 CDecimal 的实例 xC.exp(x) 就等价于 x.exp(context=C)。 每个 Context 方法都接受一个 Python 整数(即 int 的实例)在任何接受 Decimal 的实例的地方使用。

  • clear_flags()

    将所有旗标重置为 0

  • clear_traps()

    将所有陷阱重置为零 0

    3.3 新版功能.

  • copy()

    返回上下文的一个副本。

  • copy_decimal(num)

    返回 Decimal 实例 num 的一个副本。

  • create_decimal(num)

    基于 num 创建一个新 Decimal 实例但使用 self 作为上下文。 与 Decimal 构造器不同,该上下文的精度、舍入方法、旗标和陷阱会被应用于转换过程。

    此方法很有用处,因为常量往往被给予高于应用所需的精度。 另一个好处在于立即执行舍入可以消除超出当前精度的数位所导致的意外效果。 在下面的示例中,使用未舍入的输入意味着在总和中添加零会改变结果:

    >>> getcontext().prec = 3
    >>> Decimal('3.4445') + Decimal('1.0023')
    Decimal('4.45')
    >>> Decimal('3.4445') + Decimal(0) + Decimal('1.0023')
    Decimal('4.44')

    此方法实现了 IBM 规格描述中的转换为数字操作。 如果参数为字符串,则不允许有开头或末尾的空格或下划线。

  • create_decimal_from_float(f)

    基于浮点数 f 创建一个新的 Decimal 实例,但会使用 self 作为上下文来执行舍入。 与 Decimal.from_float() 类方法不同,上下文的精度、舍入方法、旗标和陷阱会应用到转换中。

    >>> context = Context(prec=5, rounding=ROUND_DOWN)
    >>> context.create_decimal_from_float(math.pi)
    Decimal('3.1415')
    >>> context = Context(prec=5, traps=[Inexact])
    >>> context.create_decimal_from_float(math.pi)
    Traceback (most recent call last):
        ...
    decimal.Inexact: None

    3.1 新版功能.

  • Etiny()

    返回一个等于 Emin - prec + 1 的值即次标准化结果中的最小指数值。 当发生向下溢出时,指数会设为 Etiny

  • Etop()

    返回一个等于 Emax - prec + 1 的值。

使用 decimal 的通常方式是创建 Decimal 实例然后对其应用算术运算,这些运算发生在活动线程的当前上下文中。 一种替代方式则是使用上下文的方法在特定上下文中进行计算。 这些方法类似于 Decimal 类的方法,在此仅简单地重新列出。

  • abs(x)

    返回 x 的绝对值。

  • add(x, y)

    返回 xy 的和。

  • canonical(x)

    返回相同的 Decimal 对象 x

  • compare(x, y)

    xy 进行数值比较。

  • compare_signal(x, y)

    对两个操作数进行数值比较。

  • compare_total(x, y)

    对两个操作数使用其抽象表示进行比较。

  • compare_total_mag(x, y)

    对两个操作数使用其抽象表示进行比较,忽略符号。

  • copy_abs(x)

    返回 x 的副本,符号设为 0。

  • copy_negate(x)

    返回 x 的副本,符号取反。

  • copy_sign(x, y)

    y 拷贝符号至 x

  • divide(x, y)

    返回 x 除以 y 的结果。

  • divide_int(x, y)

    返回 x 除以 y 的结果,截短为整数。

  • divmod(x, y)

    两个数字相除并返回结果的整数部分。

  • exp(x)

    返回 e ** x。

  • fma(x, y, z)

    返回 x 乘以 y 再加 z 的结果。

  • is_canonical(x)

    如果 x 是规范的则返回 True;否则返回 False

  • is_finite(x)

    如果 x 为有限的则返回True;否则返回 False

  • is_infinite(x)

    如果 x 是无限的则返回 True;否则返回 False

  • is_nan(x)

    如果 x 是 qNaN 或 sNaN 则返回 True;否则返回 False

  • is_normal(x)

    如果 x 是标准数则返回 True;否则返回 False

  • is_qnan(x)

    如果 x 是静默 NaN 则返回 True;否则返回 False

  • is_signed(x)

    x 是负数则返回 True;否则返回 False

  • is_snan(x)

    如果 x 是显式 NaN 则返回 True;否则返回 False

  • is_subnormal(x)

    如果 x 是次标准数则返回 True;否则返回 False

  • is_zero(x)

    如果 x 为零则返回 True;否则返回 False

  • ln(x)

    返回 x 的自然对数(以 e 为底)。

  • log10(x)

    返回 x 的以 10 为底的对数。

  • logb(x)

    返回操作数的 MSD 等级的指数。

  • logical_and(x, y)

    在操作数的每个数位间应用逻辑运算 and

  • logical_invert(x)

    反转 x 中的所有数位。

  • logical_or(x, y)

    在操作数的每个数位间应用逻辑运算 or

  • logical_xor(x, y)

    在操作数的每个数位间应用逻辑运算 xor

  • max(x, y)

    对两个值执行数字比较并返回其中的最大值。

  • max_mag(x, y)

    对两个值执行忽略正负号的数字比较。

  • min(x, y)

    对两个值执行数字比较并返回其中的最小值。

  • min_mag(x, y)

    对两个值执行忽略正负号的数字比较。

  • minus(x)

    对应于 Python 中的单目前缀取负运算符执行取负操作。

  • multiply(x, y)

    返回 xy 的积。

  • next_minus(x)

    返回小于 x 的最大数字表示形式。

  • next_plus(x)

    返回大于 x 的最小数字表示形式。

  • next_toward(x, y)

    返回 x 趋向于 y 的最接近的数字。

  • normalize(x)

    x 改写为最简形式。

  • number_class(x)

    返回 x 的类的表示。

  • plus(x)

    对应于 Python 中的单目前缀取正运算符执行取正操作。 此操作将应用上下文精度和舍入,因此它 不是 标识运算。

  • power(x, y, modulo=None)

    返回 xy 次方,如果给出了模数 modulo 则取其余数。

    如为两个参数则计算 x**y。 如果 x 为负值则 y 必须为整数。 除非 y 为整数且结果为有限值并可在 ‘precision’ 位内精确表示否则结果将是不精确的。 上下文的舍入模式将被使用。 结果在 Python 版中总是会被正确地舍入。

    Decimal(0) ** Decimal(0) 结果为 InvalidOperation,而如果 InvalidOperation 未被捕获,则结果为 Decimal('NaN')

    在 3.3 版更改: C 模块计算 power() 时会使用已正确舍入的 exp()ln() 函数。 结果是经过良好定义的,但仅限于“几乎总是正确地舍入”。

    带有三个参数时,计算 (x**y) % modulo。 对于三个参数的形式,参数将会应用以下限制:

    • 三个参数必须都是整数
    • y 必须是非负数
    • xy 至少有一个不为零
    • modulo 必须不为零且至多有 ‘precision’ 位

    来自 Context.power(x, y, modulo) 的结果值等于使用无限精度计算 (x**y) % modulo 所得到的值,但其计算过程更高效。 结果的指数为零,无论 x, ymodulo 的指数是多少。 结果值总是完全精确的。

  • quantize(x, y)

    返回的值等于 x (舍入后),并且指数为 y

  • radix()

    恰好返回 10,因为这是 Decimal 对象 :)

  • remainder(x, y)

    返回整除所得到的余数。

    结果的符号,如果不为零,则与原始除数的符号相同。

  • remainder_near(x, y)

    返回 x - y * n,其中 n 为最接近 x / y 实际值的整数(如结果为 0 则其符号将与 x 的符号相同)。

  • rotate(x, y)

    返回 x 翻转 y 次的副本。

  • same_quantum(x, y)

    如果两个操作数具有相同的指数则返回 True

  • scaleb(x, y)

    返回第一个操作数添加第二个值的指数后的结果。

  • shift(x, y)

    返回 x 变换 y 次的副本。

  • sqrt(x)

    非负数基于上下文精度的平方根。

  • subtract(x, y)

    返回 xy 的差。

  • to_eng_string(x)

    转换为字符串,如果需要指数则会使用工程标注法。

    工程标注法的指数是 3 的倍数。 这会在十进制位的左边保留至多 3 个数码,并可能要求添加一至两个末尾零。

  • to_integral_exact(x)

    舍入到一个整数。

  • to_sci_string(x)

    使用科学计数法将一个数字转换为字符串。

常量

本节中的常量仅与 C 模块相关。 它们也被包含在纯 Python 版本以保持兼容性。

32位 64位
decimal.``MAX_PREC 425000000 999999999999999999
decimal.``MAX_EMAX 425000000 999999999999999999
decimal.``MIN_EMIN -425000000 -999999999999999999
decimal.``MIN_ETINY -849999999 -1999999999999999997
decimal.HAVE_THREADS

该值为 True。 已弃用,因为 Python 现在总是启用线程。

3.9 版后已移除.

decimal.HAVE_CONTEXTVAR

默认值为 True。 如果 Python 编译版本 使用了 --without-decimal-contextvar 选项来配置,则 C 版本会使用线程局部而非协程局部上下文并且该值为 False。 这在某些嵌套上下文场景中将会稍快一些。

3.9 新版功能: 向下移植到 3.7 和 3.8。

舍入模式

decimal.ROUND_CEILING

舍入方向为 Infinity

decimal.ROUND_DOWN

舍入方向为零。

decimal.ROUND_FLOOR

舍入方向为 -Infinity

decimal.ROUND_HALF_DOWN

舍入到最接近的数,同样接近则舍入方向为零。

decimal.ROUND_HALF_EVEN

舍入到最接近的数,同样接近则舍入到最接近的偶数。

decimal.ROUND_HALF_UP

舍入到最接近的数,同样接近则舍入到零的反方向。

decimal.ROUND_UP

舍入到零的反方向。

decimal.ROUND_05UP

如果最后一位朝零的方向舍入后为 0 或 5 则舍入到零的反方向;否则舍入方向为零。

信号

信号代表在计算期间引发的条件。 每个信号对应于一个上下文旗标和一个上下文陷阱启用器。

上下文旗标将在遇到特定条件时被设定。 在完成计算之后,将为了获得信息而检测旗标(例如确定计算是否精确)。 在检测旗标后,请确保在开始下一次计算之前清除所有旗标。

如果为信号设定了上下文的陷阱启用器,则条件会导致特定的 Python 异常被引发。 举例来说,如果设定了 DivisionByZero 陷阱,则当遇到此条件时就将引发 DivisionByZero 异常。

class decimal.Clamped

修改一个指数以符合表示限制。

通常,限位将在一个指数超出上下文的 EminEmax 限制时发生。 在可能的情况下,会通过给系数添加零来将指数缩减至符合限制。

class decimal.DecimalException

其他信号的基类,并且也是 ArithmeticError 的一个子类。

class decimal.DivisionByZero

非无限数被零除的信号。

可在除法、取余队法或对一个数求负数次幂时发生。 如果此信号未被陷阱捕获,则返回 Infinity-Infinity 并且由对计算的输入来确定正负符号。

class decimal.Inexact

表明发生了舍入且结果是不精确的。

有非零数位在舍入期间被丢弃的信号。 舍入结果将被返回。 此信号旗标或陷阱被用于检测结果不精确的情况。

class decimal.InvalidOperation

执行了一个无效的操作。

表明请求了一个无意义的操作。 如未被陷阱捕获则返回 NaN。 可能的原因包括:

Infinity - Infinity
0 * Infinity
Infinity / Infinity
x % 0
Infinity % x
sqrt(-x) and x > 0
0 ** 0
x ** (non-integer)
x ** Infinity

class decimal.Overflow

数值的溢出。

表明在发生舍入之后的指数大于 Emax。 如果未被陷阱捕获,则结果将取决于舍入模式,或者向下舍入为最大的可表示有限数,或者向上舍入为 Infinity。 无论哪种情况,都将引发 InexactRounded 信号。

class decimal.Rounded

发生了舍入,但或许并没有信息丢失。

一旦舍入丢弃了数位就会发出此信号;即使被丢弃的数位是零 (例如将 5.00 舍入为 5.0)。 如果未被陷阱捕获,则不经修改地返回结果。 此信号用于检测有效位数的丢弃。

class decimal.Subnormal

在舍入之前指数低于 Emin

当操作结果是次标准数(即指数过小)时就会发出此信号。 如果未被陷阱捕获,则不经修改过返回结果。

class decimal.Underflow

数字向下溢出导致结果舍入到零。

当一个次标准数结果通过舍入转为零时就会发出此信号。 同时还将引发 InexactSubnormal 信号。

class decimal.FloatOperation

为 float 和 Decimal 的混合启用更严格的语义。

如果信号未被捕获(默认),则在 Decimal 构造器、create_decimal() 和所有比较运算中允许 float 和 Decimal 的混合。 转换和比较都是完全精确的。 发生的任何混合运算都将通过在上下文旗标中设置 FloatOperation 来静默地记录。 通过 from_float()create_decimal_from_float() 进行显式转换则不会设置旗标。

在其他情况下(即信号被捕获),则只静默执行相等性比较和显式转换。 所有其他混合运算都将引发 FloatOperation

以下表格总结了信号的层级结构:

exceptions.ArithmeticError(exceptions.Exception)
    DecimalException
        Clamped
        DivisionByZero(DecimalException, exceptions.ZeroDivisionError)
        Inexact
            Overflow(Inexact, Rounded)
            Underflow(Inexact, Rounded, Subnormal)
        InvalidOperation
        Rounded
        Subnormal
        FloatOperation(DecimalException, exceptions.TypeError)

浮点数说明

通过提升精度来解决舍入错误

使用十进制浮点数可以消除十进制表示错误(即能够完全精确地表示 0.1 这样的数);然而,某些运算在非零数位超出给定的精度时仍然可能导致舍入错误。

舍入错误的影响可能因接近相互抵销的加减运算被放大从而导致丢失有效位。 Knuth 提供了两个指导性示例,其中出现了精度不足的浮点算术舍入,导致加法的交换律和分配律被打破:

# Examples from Seminumerical Algorithms, Section 4.2.2.
>>> from decimal import Decimal, getcontext
>>> getcontext().prec = 8
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.5111111')
>>> u + (v + w)
Decimal('10')
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.01')
>>> u * (v+w)
Decimal('0.0060000')

decimal 模块则可以通过充分地扩展精度来避免有效位的丢失:

>>> getcontext().prec = 20
>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111')
>>> (u + v) + w
Decimal('9.51111111')
>>> u + (v + w)
Decimal('9.51111111')
>>>
>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003')
>>> (u*v) + (u*w)
Decimal('0.0060000')
>>> u * (v+w)
Decimal('0.0060000')

特殊的值

decimal 模块的数字系统提供了一些特殊的值,包括 NaN, sNaN, -Infinity, Infinity 以及两种零值 +0-0

无穷大可以使用 Decimal('Infinity') 来构建。 它们也可以在不捕获 DivisionByZero 信号捕获时通过除以零来产生。 类似地,当不捕获 Overflow 信号时,也可以通过舍入到超出最大可表示数字限制的方式产生无穷大的结果。

无穷大是有符号的(仿射)并可用于算术运算,它们会被当作极其巨大的不确定数字来处理。 例如,无穷大加一个常量结果也将为无穷大。

某些不存在有效结果的运算将会返回 NaN,或者如果捕获了 InvalidOperation 信号则会引发一个异常。 例如,0/0 会返回 NaN 表示结果“不是一个数字”。 这样的 NaN 是静默产生的,并且在产生之后参与其它计算时总是会得到 NaN 的结果。 这种行为对于偶而缺少输入的各类计算都很有用处 —- 它允许在将特定结果标记为无效的同时让计算继续运行。

另一种变体形式是 sNaN,它在每次运算后会发出信号而不是保持静默。 当对于无效结果需要中断计算进行特别处理时,这是一个很有用的返回值。

Python 中比较运算符的行为在涉及 NaN 时可能会令人有点惊讶。 相等性检测在操作数中有静默型或信号型 NaN 时总是会返回 False (即使是执行 Decimal('NaN')==Decimal('NaN')),而不等性检测总是会返回 True。 当尝试使用 <, <=, >>= 运算符中的任何一个来比较两个 Decimal 值时,如果运算数中有 NaN 则将引发 InvalidOperation 信号,如果此信号未被捕获则将返回 False。 请注意通用十进制算术规范并未规定直接比较行为;这些涉及 NaN 的比较规则来自于 IEEE 854 标准 (见第 5.7 节表 3)。 要确保严格符合标准,请改用 compare()compare-signal() 方法。

有符号零值可以由向下溢出的运算产生。 它们保留符号是为了让运算结果能以更高的精度传递。 由于它们的大小为零,正零和负零会被视为相等,且它们的符号具有信息。

在这两个不相同但却相等的有符号零之外,还存在几种零的不同表示形式,它们的精度不同但值也都相等。 这需要一些时间来逐渐适应。 对于习惯了标准浮点表示形式的眼睛来说,以下运算返回等于零的值并不是显而易见的:

>>> 1 / Decimal('Infinity')
Decimal('0E-1000026')

使用线程

getcontext() 函数会为每个线程访问不同的 Context 对象。 具有单独线程上下文意味着线程可以修改上下文 (例如 getcontext().prec=10) 而不影响其他线程。

类似的 setcontext() 会为当前上下文的目标自动赋值。

如果在调用 setcontext() 之前调用了 getcontext(),则 getcontext() 将自动创建一个新的上下文在当前线程中使用。

新的上下文拷贝自一个名为 DefaultContext 的原型上下文。 要控制默认值以便每个线程在应用运行期间都使用相同的值,可以直接修改 DefaultContext 对象。 这应当在任何线程启动 之前 完成以使得调用 getcontext() 的线程之间不会产生竞争条件。 例如:

# Set applicationwide defaults for all threads about to be launched
DefaultContext.prec = 12
DefaultContext.rounding = ROUND_DOWN
DefaultContext.traps = ExtendedContext.traps.copy()
DefaultContext.traps[InvalidOperation] = 1
setcontext(DefaultContext)
# Afterwards, the threads can be started
t1.start()
t2.start()
t3.start()
 . . .

例程

以下是一些用作工具函数的例程,它们演示了使用 Decimal 类的各种方式:

def moneyfmt(value, places=2, curr='', sep=',', dp='.',
             pos='', neg='-', trailneg=''):
    """Convert Decimal to a money formatted string.
    places:  required number of places after the decimal point
    curr:    optional currency symbol before the sign (may be blank)
    sep:     optional grouping separator (comma, period, space, or blank)
    dp:      decimal point indicator (comma or period)
             only specify as blank when places is zero
    pos:     optional sign for positive numbers: '+', space or blank
    neg:     optional sign for negative numbers: '-', '(', space or blank
    trailneg:optional trailing minus indicator:  '-', ')', space or blank
    >>> d = Decimal('-1234567.8901')
    >>> moneyfmt(d, curr='$')
    '-$1,234,567.89'
    >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-')
    '1.234.568-'
    >>> moneyfmt(d, curr='$', neg='(', trailneg=')')
    '($1,234,567.89)'
    >>> moneyfmt(Decimal(123456789), sep=' ')
    '123 456 789.00'
    >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>')
    '<0.02>'
    """
    q = Decimal(10) ** -places      # 2 places --> '0.01'
    sign, digits, exp = value.quantize(q).as_tuple()
    result = []
    digits = list(map(str, digits))
    build, next = result.append, digits.pop
    if sign:
        build(trailneg)
    for i in range(places):
        build(next() if digits else '0')
    if places:
        build(dp)
    if not digits:
        build('0')
    i = 0
    while digits:
        build(next())
        i += 1
        if i == 3 and digits:
            i = 0
            build(sep)
    build(curr)
    build(neg if sign else pos)
    return ''.join(reversed(result))
def pi():
    """Compute Pi to the current precision.
    >>> print(pi())
    3.141592653589793238462643383
    """
    getcontext().prec += 2  # extra digits for intermediate steps
    three = Decimal(3)      # substitute "three=3.0" for regular floats
    lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24
    while s != lasts:
        lasts = s
        n, na = n+na, na+8
        d, da = d+da, da+32
        t = (t * n) / d
        s += t
    getcontext().prec -= 2
    return +s               # unary plus applies the new precision
def exp(x):
    """Return e raised to the power of x.  Result type matches input type.
    >>> print(exp(Decimal(1)))
    2.718281828459045235360287471
    >>> print(exp(Decimal(2)))
    7.389056098930650227230427461
    >>> print(exp(2.0))
    7.38905609893
    >>> print(exp(2+0j))
    (7.38905609893+0j)
    """
    getcontext().prec += 2
    i, lasts, s, fact, num = 0, 0, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 1
        fact *= i
        num *= x
        s += num / fact
    getcontext().prec -= 2
    return +s
def cos(x):
    """Return the cosine of x as measured in radians.
    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).
    >>> print(cos(Decimal('0.5')))
    0.8775825618903727161162815826
    >>> print(cos(0.5))
    0.87758256189
    >>> print(cos(0.5+0j))
    (0.87758256189+0j)
    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s
def sin(x):
    """Return the sine of x as measured in radians.
    The Taylor series approximation works best for a small value of x.
    For larger values, first compute x = x % (2 * pi).
    >>> print(sin(Decimal('0.5')))
    0.4794255386042030002732879352
    >>> print(sin(0.5))
    0.479425538604
    >>> print(sin(0.5+0j))
    (0.479425538604+0j)
    """
    getcontext().prec += 2
    i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i * (i-1)
        num *= x * x
        sign *= -1
        s += num / fact * sign
    getcontext().prec -= 2
    return +s

Decimal 常见问题

Q. 总是输入 decimal.Decimal('1234.5') 是否过于笨拙。 在使用交互解释器时有没有最小化输入量的方式?

A. 有些用户会将构造器简写为一个字母:

>>> D = decimal.Decimal
>>> D('1.23') + D('3.45')
Decimal('4.68')

Q. 在带有两个十进制位的定点数应用中,有些输入值具有许多位,需要被舍入。 另一些数则不应具有多余位,需要验证有效性。 这种情况应该用什么方法?

A. 用 quantize() 方法舍入到固定数量的十进制位。 如果设置了 Inexact 陷阱,它也适用于验证有效性:

>>> TWOPLACES = Decimal(10) ** -2       # same as Decimal('0.01')

>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')

>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')

>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
   ...
Inexact: None

Q. 当我使用两个有效位的输入时,我要如何在一个应用中保持有效位不变?

A. 某些运算例如与整数相加、相减和相乘将会自动保留固定的小数位数。 其他运算,例如相除和非整数相乘则将会改变小数位数,需要再加上 quantize() 处理步骤:

>>> a = Decimal('102.72')           # Initial fixed-point values
>>> b = Decimal('3.17')
>>> a + b                           # Addition preserves fixed-point
Decimal('105.89')
>>> a - b
Decimal('99.55')
>>> a * 42                          # So does integer multiplication
Decimal('4314.24')
>>> (a * b).quantize(TWOPLACES)     # Must quantize non-integer multiplication
Decimal('325.62')
>>> (b / a).quantize(TWOPLACES)     # And quantize division
Decimal('0.03')

在开发定点数应用时,更方便的做法是定义处理 quantize() 步骤的函数:

>>> def mul(x, y, fp=TWOPLACES):
...     return (x * y).quantize(fp)
>>> def div(x, y, fp=TWOPLACES):
...     return (x / y).quantize(fp)

>>> mul(a, b)                       # Automatically preserve fixed-point
Decimal('325.62')
>>> div(b, a)
Decimal('0.03')

Q. 表示同一个值有许多方式。 数字 200, 200.000, 2E202E+4 的值都相同但有精度不同。 是否有办法将它们转换为一个可识别的规范值?

A. normalize() 方法可将所有相同的值映射为统一表示形式:

>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
>>> [v.normalize() for v in values]
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]

Q. 有些十进制值总是被打印为指数表示形式。 是否有办法得到一个非指数表示形式?

A. 对于某些值来说,指数表示形式是表示系数中有效位的唯一办法。 例如,将 5.0E+3 表示为 5000 可以让值保持恒定,但是无法显示原本的两位有效数字。

如果一个应用不必关心追踪有效位,则可以很容易地移除指数和末尾的零,丢弃有效位但让值保持不变:

>>> def remove_exponent(d):
...     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()

>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

Q. 是否有办法将一个普通浮点数转换为 Decimal

A. 是的,任何二进制浮点数都可以精确地表示为 Decimal 值,但完全精确的转换可能需要比平常感觉更高的精度:

>>> Decimal(math.pi)
Decimal('3.141592653589793115997963468544185161590576171875')

Q. 在一个复杂的计算中,我怎样才能保证不会得到由精度不足和舍入异常所导致的虚假结果。

A. 使用 decimal 模块可以很容易地检测结果。 最好的做法是使用更高的精度和不同的舍入模式重新进行计算。 明显不同的结果表明存在精度不足、舍入模式问题、不符合条件的输入或是结果不稳定的算法。

Q. 我发现上下文精度的应用只针对运算结果而不针对输入。在混合使用不同精度的值时有什么需要注意的吗?

A. 是的。 原则上所有值都会被视为精确值,在这些值上进行的算术运算也是如此。 只有结果会被舍入。 对于输入来说其好处是“所输入即所得”。 而其缺点则是如果你忘记了输入没有被舍入,结果看起来可能会很奇怪:

>>> getcontext().prec = 3
>>> Decimal('3.104') + Decimal('2.104')
Decimal('5.21')
>>> Decimal('3.104') + Decimal('0.000') + Decimal('2.104')
Decimal('5.20')

解决办法是提高精度或使用单目加法运算对输入执行强制舍入:

>>> getcontext().prec = 3
>>> +Decimal('1.23456789')      # unary plus triggers rounding
Decimal('1.23')

此外,还可以使用 Context.create_decimal() 方法在创建输入时执行舍入:

>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
Decimal('1.2345')

Q. CPython 实现对于巨大数字是否足够快速?

A. 是的。 在 CPython 和 PyPy3 实现中,decimal 模块的 C/CFFI 版本集成了高速 libmpdec 库用于实现任意精度正确舍入的十进制浮点算术 1libmpdec 会对中等大小的数字使用 Karatsuba 乘法 而对非常巨大的数字使用 数字原理变换。

必须要对任意精度算术适配上下文。 EminEmax 应当总是设为最大值,clamp 应当总是设为 0 (默认值)。 设置 prec 需要十分谨慎。

进行大数字算术的最便捷方式也是使用 prec 的最大值:

>>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN))
>>> x = Decimal(2) ** 256
>>> x / 128
Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312')

对于不精确的结果,在 64 位平台上 MAX_PREC 的值太大了,可用的内存将会不足:

>>> Decimal(1) / 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

在具有超量分配的系统上 (即 Linux),一种更复杂的方式根据可用的 RAM 大小来调整 prec。 假设你有 8GB 的 RAM 并期望同时有 10 个操作数,每个最多使用 500MB:

>>> import sys
>>>
>>> # Maximum number of digits for a single operand using 500MB in 8-byte words
>>> # with 19 digits per word (4-byte and 9 digits for the 32-bit build):
>>> maxdigits = 19 * ((500 * 1024**2) // 8)
>>>
>>> # Check that this works:
>>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN)
>>> c.traps[Inexact] = True
>>> setcontext(c)
>>>
>>> # Fill the available precision with nines:
>>> x = Decimal(0).logical_invert() * 9
>>> sys.getsizeof(x)
524288112
>>> x + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  decimal.Inexact: [<class 'decimal.Inexact'>]

总体而言(特别是在没有超量分配的系统上),如果期望所有计算都是精确的则推荐预估更严格的边界并设置 Inexact 陷阱。

fractions —- 分数

源代码 Lib/fractions.py


fractions 模块支持分数运算。

分数实例可以由一对整数,一个分数,或者一个字符串构建而成。

class fractions.Fraction(numerator=0, denominator=1)

class fractions.Fraction(other_fraction)

class fractions.Fraction(float)

class fractions.Fraction(decimal)

class fractions.Fraction(string)

第一个版本要求 numeratordenominatornumbers.Rational 的实例,并返回一个新的 Fraction 实例,其值为 numerator/denominator。 如果 denominator0 将会引发 ZeroDivisionError。 第二个版本要求 other_fractionnumbers.Rational 的实例,并返回一个 Fraction 实例且与传入值相等。 下两个版本接受 floatdecimal.Decimal 的实例,并返回一个 Fraction 实例且与传入值完全相等。 请注意由于二进制浮点数通常存在的问题,Fraction(1.1) 的参数并不会精确等于 11/10,因此 Fraction(1.1)不会 返回用户所期望的 Fraction(11, 10)。 (请参阅下文中 limit_denominator() 方法的文档。) 构造器的最后一个版本接受一个字符串或 unicode 实例。 此实例的通常形式为:

[sign] numerator ['/' denominator]

其中的可选项 sign 可以为 ‘+’ 或 ‘-‘ 并且 numeratordenominator (如果存在) 是十进制数码的字符串。 此外,float 构造器所接受的任何表示一个有限值的字符串也都为 Fraction 构造器所接受。 不论哪种形式的输入字符串也都可以带有前缀和/或后缀的空格符。 这里是一些示例:

>>> from fractions import Fraction
>>> Fraction(16, -10)
Fraction(-8, 5)
>>> Fraction(123)
Fraction(123, 1)
>>> Fraction()
Fraction(0, 1)
>>> Fraction('3/7')
Fraction(3, 7)
>>> Fraction(' -3/7 ')
Fraction(-3, 7)
>>> Fraction('1.414213 \t\n')
Fraction(1414213, 1000000)
>>> Fraction('-.125')
Fraction(-1, 8)
>>> Fraction('7e-6')
Fraction(7, 1000000)
>>> Fraction(2.25)
Fraction(9, 4)
>>> Fraction(1.1)
Fraction(2476979795053773, 2251799813685248)
>>> from decimal import Decimal
>>> Fraction(Decimal('1.1'))
Fraction(11, 10)

Fraction 类继承自抽象基类 numbers.Rational,并实现了该类的所有方法和操作。 Fraction 实例是可哈希的,并应当被视为不可变对象。 此外,Fraction 还具有以下属性和方法:

在 3.2 版更改: Fraction 构造器现在接受 floatdecimal.Decimal 实例。

在 3.9 版更改: 现在会使用 math.gcd() 函数来正规化 numeratordenominator*。 math.gcd() 总是返回 int 类型。 在之前版本中,GCD 的类型取决于 *numeratordenominator 的类型。

  • numerator

    最简分数形式的分子。

  • denominator

    最简分数形式的分母。

  • as_integer_ratio()

    返回由两个整数组成的元组,两数之比等于该分数的值且其分母为正数。

    3.8 新版功能.

  • from_float(flt)

    此类方法可构造一个 Fraction 来表示 flt 的精确值,该参数必须是一个 float。 请注意 Fraction.from_float(0.3) 的值并不等于 Fraction(3, 10)

    注解

    从 Python 3.2 开始,在构造 Fraction 实例时可以直接使用 float

  • from_decimal(dec)

    此类方法可构造一个 Fraction 来表示 dec 的精确值,该参数必须是一个 decimal.Decimal 实例。

    注解

    从 Python 3.2 开始,在构造 Fraction 实例时可以直接使用 decimal.Decimal 实例。

  • limit_denominator(max_denominator=1000000)

    找到并返回一个 Fraction 使得其值最接近 self 并且分母不大于 max_denominator。 此方法适用于找出给定浮点数的有理数近似值:

    >>> from fractions import Fraction
    >>> Fraction('3.1415926535897932').limit_denominator(1000)
    Fraction(355, 113)

    或是用来恢复被表示为一个浮点数的有理数:

    >>> from math import pi, cos
    >>> Fraction(cos(pi/3))
    Fraction(4503599627370497, 9007199254740992)
    >>> Fraction(cos(pi/3)).limit_denominator()
    Fraction(1, 2)
    >>> Fraction(1.1).limit_denominator()
    Fraction(11, 10)
  • __floor__()

    返回最大的 int <= self。 此方法也可通过 math.floor() 函数来使用:

    >>> from math import floor
    >>> floor(Fraction(355, 113))
    3
  • __ceil__()

    返回最小的 int >= self。 此方法也可通过 math.ceil() 函数来使用。

  • __round__()

    __round__(ndigits)

    第一个版本返回一个 int 使得其值最接近 self,位值为二分之一时只对偶数舍入。第二个版本会将 self 舍入到最接近 Fraction(1, 10**ndigits) 的倍数(如果 ndigits 为负值则为逻辑运算),位值为二分之一时同样只对偶数舍入。 此方法也可通过 round() 函数来使用。

random —- 生成伪随机数

源码: Lib/random.py


该模块实现了各种分布的伪随机数生成器。

对于整数,从范围中有统一的选择。 对于序列,存在随机元素的统一选择、用于生成列表的随机排列的函数、以及用于随机抽样而无需替换的函数。

在实数轴上,有计算均匀、正态(高斯)、对数正态、负指数、伽马和贝塔分布的函数。 为了生成角度分布,可以使用 von Mises 分布。

几乎所有模块函数都依赖于基本函数 random() ,它在半开放区间 [0.0,1.0) 内均匀生成随机浮点数。 Python 使用 Mersenne Twister 作为核心生成器。 它产生 53 位精度浮点数,周期为 2**19937-1 ,其在 C 中的底层实现既快又线程安全。 Mersenne Twister 是现存最广泛测试的随机数发生器之一。 但是,因为完全确定性,它不适用于所有目的,并且完全不适合加密目的。

这个模块提供的函数实际上是 random.Random 类的隐藏实例的绑定方法。 你可以实例化自己的 Random 类实例以获取不共享状态的生成器。

如果你想使用自己设计的不同基础生成器,类 Random 也可以作为子类:在这种情况下,重载 random()seed()getstate() 以及 setstate() 方法。可选地,新生成器可以提供 getrandbits() 方法——这允许 randrange() 在任意大的范围内产生选择。

random 模块还提供 SystemRandom 类,它使用系统函数 os.urandom() 从操作系统提供的源生成随机数。

参见

M. Matsumoto and T. Nishimura, “Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator”, ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, January pp.3—30 1998.

Complementary-Multiply-with-Carry recipe 用于兼容的替代随机数发生器,具有长周期和相对简单的更新操作。

簿记功能

random.seed(a=None, version=2)

初始化随机数生成器。

如果 a 被省略或为 None ,则使用当前系统时间。 如果操作系统提供随机源,则使用它们而不是系统时间(有关可用性的详细信息,请参阅 os.urandom() 函数)。

如果 a 是 int 类型,则直接使用。

对于版本2(默认的),strbytesbytearray 对象转换为 int 并使用它的所有位。

对于版本1(用于从旧版本的Python再现随机序列),用于 strbytes 的算法生成更窄的种子范围。

在 3.2 版更改: 已移至版本2方案,该方案使用字符串种子中的所有位。

3.9 版后已移除: 在将来,seed 必须是下列类型之一: NoneType, int, float, str, bytesbytearray

random.getstate()

返回捕获生成器当前内部状态的对象。 这个对象可以传递给 setstate() 来恢复状态。

random.setstate(state)

state 应该是从之前调用 getstate() 获得的,并且 setstate() 将生成器的内部状态恢复到 getstate() 被调用时的状态。

用于字节数据的函数

random.randbytes(n)

生成 n 个随机字节。

此方法不可用于生成安全凭据。 那应当使用 secrets.token_bytes()

3.9 新版功能.

整数用函数

random.randrange(stop)

random.randrange(start, stop[, step])

range(start, stop, step) 返回一个随机选择的元素。 这相当于 choice(range(start, stop, step)) ,但实际上并没有构建一个 range 对象。

位置参数模式匹配 range() 。不应使用关键字参数,因为该函数可能以意外的方式使用它们。

在 3.2 版更改: randrange() 在生成均匀分布的值方面更为复杂。 以前它使用了像int(random()*n)这样的形式,它可以产生稍微不均匀的分布。

3.10 版后已移除: 非整数类型到相等整数的自动转换已被弃用。 目前 randrange(10.0) 会无损地转换为 randrange(10)。 在未来,这将引发 TypeError

3.10 版后已移除: 针对非整数值例如 randrange(10.5)randrange('10') 引发的异常将从 ValueError 修改为 TypeError

random.randint(a, b)

返回随机整数 N 满足 a <= N <= b。相当于 randrange(a, b+1)

random.getrandbits(k)

返回具有 k 个随机比特位的非负 Python 整数。 此方法随 MersenneTwister 生成器一起提供,其他一些生成器也可能将其作为 API 的可选部分提供。 在可能的情况下,getrandbits() 会启用 randrange() 来处理任意大的区间。

在 3.9 版更改: 此方法现在接受零作为 k 的值。

序列用函数

random.choice(seq)

从非空序列 seq 返回一个随机元素。 如果 seq 为空,则引发 IndexError

random.choices(population, weights=None, **, cum_weights=None, k=1*)

population*中选择替换,返回大小为 *k 的元素列表。 如果 population 为空,则引发 IndexError

如果指定了 weight 序列,则根据相对权重进行选择。 或者,如果给出 cum_weights 序列,则根据累积权重(可能使用 itertools.accumulate() 计算)进行选择。 例如,相对权重[10, 5, 30, 5]相当于累积权重[10, 15, 45, 50]。 在内部,相对权重在进行选择之前会转换为累积权重,因此提供累积权重可以节省工作量。

如果既未指定 weight 也未指定 cum_weights ,则以相等的概率进行选择。 如果提供了权重序列,则它必须与 population 序列的长度相同。 一个 TypeError 指定了 weightscum_weights

weightscum_weights 可使用 random() 所返回的能与can use any numeric type that interoperates with the float 值进行相互运算的任何数字类型(包括整数、浮点数、分数但不包括 decimal)。 权重值应当非负且为有限的数值。 如果所有的权重值均为零则会引发 ValueError

对于给定的种子,具有相等加权的 choices() 函数通常产生与重复调用 choice() 不同的序列。 choices() 使用的算法使用浮点运算来实现内部一致性和速度。 choice() 使用的算法默认为重复选择的整数运算,以避免因舍入误差引起的小偏差。

3.6 新版功能.

在 3.9 版更改: 如果所有权重均为负值则将引发 ValueError

random.shuffle(x[, random])

将序列 x 随机打乱位置。

可选参数 random 是一个0参数函数,在 [0.0, 1.0) 中返回随机浮点数;默认情况下,这是函数 random()

要改变一个不可变的序列并返回一个新的打乱列表,请使用sample(x, k=len(x))

请注意,即使对于小的 len(x)x 的排列总数也可以快速增长,大于大多数随机数生成器的周期。 这意味着长序列的大多数排列永远不会产生。 例如,长度为2080的序列是可以在 Mersenne Twister 随机数生成器的周期内拟合的最大序列。

Deprecated since version 3.9, will be removed in version 3.11: 可选形参 random

random.sample(population, k, **, counts=None*)

返回从总体序列或集合中选择的唯一元素的 k 长度列表。 用于无重复的随机抽样。

返回包含来自总体的元素的新列表,同时保持原始总体不变。 结果列表按选择顺序排列,因此所有子切片也将是有效的随机样本。 这允许抽奖获奖者(样本)被划分为大奖和第二名获胜者(子切片)。

总体成员不必是 hashable 或 unique 。 如果总体包含重复,则每次出现都是样本中可能的选择。

重复的元素可以一个个地直接列出,或使用可选的仅限关键字形参 counts 来指定。 例如,sample(['red', 'blue'], counts=[4, 2], k=5) 等价于 sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)

要从一系列整数中选择样本,请使用 range() 对象作为参数。 对于从大量人群中采样,这种方法特别快速且节省空间:sample(range(10000000), k=60)

如果样本大小大于总体大小,则引发 ValueError

在 3.9 版更改: 增加了 counts 形参。

3.9 版后已移除: 在将来,population 必须是一个序列。 set 的实例将不再被支持。 集合必须先转换为 listtuple,最好是固定顺序以使抽样是可重现的。

实值分布

以下函数生成特定的实值分布。如常用数学实践中所使用的那样, 函数参数以分布方程中的相应变量命名;大多数这些方程都可以在任何统计学教材中找到。

random.random()

返回 [0.0, 1.0) 范围内的下一个随机浮点数。

random.uniform(a, b)

返回一个随机浮点数 N ,当 a <= ba <= N <= b ,当 b < ab <= N <= a

取决于等式 a + (b-a) * random() 中的浮点舍入,终点 b 可以包括或不包括在该范围内。

random.triangular(low, high, mode)

返回一个随机浮点数 N ,使得 low <= N <= high 并在这些边界之间使用指定的 modelowhigh 边界默认为零和一。 mode 参数默认为边界之间的中点,给出对称分布。

random.betavariate(alpha, beta)

Beta 分布。 参数的条件是 alpha > 0beta > 0。 返回值的范围介于 0 和 1 之间。

random.expovariate(lambd)

指数分布。 lambd 是 1.0 除以所需的平均值,它应该是非零的。 (该参数本应命名为 “lambda” ,但这是 Python 中的保留字。)如果 lambd 为正,则返回值的范围为 0 到正无穷大;如果 lambd 为负,则返回值从负无穷大到 0。

random.gammavariate(alpha, beta)

Gamma 分布。 ( 不是 gamma 函数! ) 参数的条件是 alpha > 0beta > 0

概率分布函数是:

          x ** (alpha - 1) * math.exp(-x / beta)
pdf(x) =  --------------------------------------
            math.gamma(alpha) * beta ** alpha

random.gauss(mu, sigma)

正态分布,也称高斯分布。 mu 为平均值,而 sigma 为标准差。 此函数要稍快于下面所定义的 normalvariate() 函数。

多线程注意事项:当两个线程同时调用此方法时,它们有可能将获得相同的返回值。 这可以通过三种办法来避免。 1) 让每个线程使用不同的随机数生成器实例。 2) 在所有调用外面加锁。 3) 改用速度较慢但是线程安全的 normalvariate() 函数。

random.lognormvariate(mu, sigma)

对数正态分布。 如果你采用这个分布的自然对数,你将得到一个正态分布,平均值为 mu 和标准差为 sigmamu 可以是任何值,sigma 必须大于零。

random.normalvariate(mu, sigma)

正态分布。 mu 是平均值,sigma 是标准差。

random.vonmisesvariate(mu, kappa)

冯·米塞斯分布。 mu 是平均角度,以弧度表示,介于0和 2*pi 之间,kappa 是浓度参数,必须大于或等于零。 如果 kappa 等于零,则该分布在 0 到 2*pi 的范围内减小到均匀的随机角度。

random.paretovariate(alpha)

帕累托分布。 alpha 是形状参数。

random.weibullvariate(alpha, beta)

威布尔分布。 alpha 是比例参数,beta 是形状参数。

替代生成器

class random.Random([seed])

该类实现了 random 模块所用的默认伪随机数生成器。

3.9 版后已移除: 在将来,seed 必须是下列类型之一: NoneType, int, float, str, bytesbytearray

class random.SystemRandom([seed])

使用 os.urandom() 函数的类,用从操作系统提供的源生成随机数。 这并非适用于所有系统。 也不依赖于软件状态,序列不可重现。 因此,seed() 方法没有效果而被忽略。 getstate()setstate() 方法如果被调用则引发 NotImplementedError

关于再现性的说明

有时能够重现伪随机数生成器给出的序列是很有用处的。 通过重用一个种子值,只要没有运行多线程,相同的序列就应当可在多次运行中重现。

大多数随机模块的算法和种子函数都会在 Python 版本中发生变化,但保证两个方面不会改变:

  • 如果添加了新的播种方法,则将提供向后兼容的播种机。
  • 当兼容的播种机被赋予相同的种子时,生成器的 random() 方法将继续产生相同的序列。

例子

基本示例:

>>> random()                             # Random float:  0.0 <= x < 1.0
0.37444887175646646
>>> uniform(2.5, 10.0)                   # Random float:  2.5 <= x <= 10.0
3.1800146073117523
>>> expovariate(1 / 5)                   # Interval between arrivals averaging 5 seconds
5.148957571865031
>>> randrange(10)                        # Integer from 0 to 9 inclusive
7
>>> randrange(0, 101, 2)                 # Even integer from 0 to 100 inclusive
26
>>> choice(['win', 'lose', 'draw'])      # Single random element from a sequence
'draw'
>>> deck = 'ace two three four'.split()
>>> shuffle(deck)                        # Shuffle a list
>>> deck
['four', 'two', 'ace', 'three']
>>> sample([10, 20, 30, 40, 50], k=4)    # Four samples without replacement
[40, 10, 50, 30]

模拟:

>>> # Six roulette wheel spins (weighted sampling with replacement)
>>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
['red', 'green', 'black', 'black', 'red', 'black']
>>> # Deal 20 cards without replacement from a deck
>>> # of 52 playing cards, and determine the proportion of cards
>>> # with a ten-value:  ten, jack, queen, or king.
>>> dealt = sample(['tens', 'low cards'], counts=[16, 36], k=20)
>>> dealt.count('tens') / 20
0.15
>>> # Estimate the probability of getting 5 or more heads from 7 spins
>>> # of a biased coin that settles on heads 60% of the time.
>>> def trial():
...     return choices('HT', cum_weights=(0.60, 1.00), k=7).count('H') >= 5
...
>>> sum(trial() for i in range(10_000)) / 10_000
0.4169
>>> # Probability of the median of 5 samples being in middle two quartiles
>>> def trial():
...     return 2_500 <= sorted(choices(range(10_000), k=5))[2] < 7_500
...
>>> sum(trial() for i in range(10_000)) / 10_000
0.7958

statistical bootstrapping 的示例,使用重新采样和替换来估计一个样本的均值的置信区间:

# http://statistics.about.com/od/Applications/a/Example-Of-Bootstrapping.htm
from statistics import fmean as mean
from random import choices
data = [41, 50, 29, 37, 81, 30, 73, 63, 20, 35, 68, 22, 60, 31, 95]
means = sorted(mean(choices(data, k=len(data))) for i in range(100))
print(f'The sample mean of {mean(data):.1f} has a 90% confidence '
      f'interval from {means[5]:.1f} to {means[94]:.1f}')

使用 重新采样排列测试 来确定统计学显著性或者使用 p-值 来观察药物与安慰剂的作用之间差异的示例:

# Example from "Statistics is Easy" by Dennis Shasha and Manda Wilson
from statistics import fmean as mean
from random import shuffle
drug = [54, 73, 53, 70, 73, 68, 52, 65, 65]
placebo = [54, 51, 58, 44, 55, 52, 42, 47, 58, 46]
observed_diff = mean(drug) - mean(placebo)
n = 10_000
count = 0
combined = drug + placebo
for i in range(n):
    shuffle(combined)
    new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):])
    count += (new_diff >= observed_diff)
print(f'{n} label reshufflings produced only {count} instances with a difference')
print(f'at least as extreme as the observed difference of {observed_diff:.1f}.')
print(f'The one-sided p-value of {count / n:.4f} leads us to reject the null')
print(f'hypothesis that there is no difference between the drug and the placebo.')

多服务器队列的到达时间和服务交付模拟:

from heapq import heappush, heappop
from random import expovariate, gauss
from statistics import mean, quantiles
average_arrival_interval = 5.6
average_service_time = 15.0
stdev_service_time = 3.5
num_servers = 3
waits = []
arrival_time = 0.0
servers = [0.0] * num_servers  # time when each server becomes available
for i in range(100_000):
    arrival_time += expovariate(1.0 / average_arrival_interval)
    next_server_available = heappop(servers)
    wait = max(0.0, next_server_available - arrival_time)
    waits.append(wait)
    service_duration = gauss(average_service_time, stdev_service_time)
    service_completed = arrival_time + wait + service_duration
    heappush(servers, service_completed)
print(f'Mean wait: {mean(waits):.1f}   Max wait: {max(waits):.1f}')
print('Quartiles:', [round(q, 1) for q in quantiles(waits)])

参见

Statistics for Hackers Jake Vanderplas 撰写的视频教程,使用一些基本概念进行统计分析,包括模拟、抽样、改组和交叉验证。

Economics Simulation Peter Norvig 编写的市场模拟,显示了该模块提供的许多工具和分布的有效使用(高斯、均匀、样本、beta变量、选择、三角和随机范围等)。

A Concrete Introduction to Probability (using Python) Peter Norvig 撰写的教程,涵盖了概率论基础知识,如何编写模拟,以及如何使用 Python 进行数据分析。

例程

默认的 random() 返回在 0.0 ≤ x < 1.0 范围内 2⁻⁵³ 的倍数。 所有这些数值间隔相等并能精确表示为 Python 浮点数。 但是在此间隔上有许多其他可表示浮点数是不可能的选择。 例如,0.05954861408025609 就不是 2⁻⁵³ 的整数倍。

以下规范程序采取了一种不同的方式。 在间隔上的所有浮点数都是可能的选择。 它们的尾数取值来自 2⁵² ≤ 尾数 < 2⁵³ 范围内整数的均匀分布。 指数取值则来自几何分布,其中小于 -53 的指数的出现频率为下一个较大指数的一半。

from random import Random
from math import ldexp
class FullRandom(Random):
    def random(self):
        mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
        exponent = -53
        x = 0
        while not x:
            x = self.getrandbits(32)
            exponent += x.bit_length() - 32
        return ldexp(mantissa, exponent)

该类中所有的 实值分布 都将使用新的方法:

>>> fr = FullRandom()
>>> fr.random()
0.05954861408025609
>>> fr.expovariate(0.25)
8.87925541791544

该规范程序在概念上等效于在 0.0 ≤ x < 1.0 范围内对所有 2⁻¹⁰⁷⁴ 的倍数进行选择的算法。 所有这样的数字间隔都相等,但大多必须向下舍入为最接近的 Python 浮点数表示形式。 (2⁻¹⁰⁷⁴ 这个数值是等于 math.ulp(0.0) 的未经正规化的最小正浮点数。)

statistics —- 数学统计函数

3.4 新版功能.

源代码: Lib/statistics.py


该模块提供了用于计算数字 (Real-valued) 数据的数理统计量的函数。

此模块并不是诸如 NumPy , SciPy 等第三方库或者诸如 Minitab , SAS , Matlab 等针对专业统计学家的专有全功能统计软件包的竞品。此模块针对图形和科学计算器的水平。

除非明确注释,这些函数支持 intfloatDecimalFraction 。当前不支持同其他类型(是否在数字塔中)的行为。混合类型的集合也是未定义的,并且依赖于实现。如果你输入的数据由混合类型组成,你应该能够使用 map() 来确保一个一致的结果,比如: map(float, input_data)

平均值以及对中心位置的评估

这些函数用于计算一个总体或样本的平均值或者典型值。

mean() 数据的算术平均数(“平均数”)。
fmean() 快速的,浮点算数平均数。
geometric_mean() 数据的几何平均数
harmonic_mean() 数据的调和均值
median() 数据的中位数(中间值)
median_low() 数据的低中位数
median_high() 数据的高中位数
median_grouped() 分组数据的中位数,即第50个百分点。
mode() 离散的或标称的数据的单个众数(出现最多的值)。
multimode() 离散的或标称的数据的众数(出现最多的值)列表。
quantiles() 将数据以相等的概率分为多个间隔。

对分散程度的评估

这些函数用于计算总体或样本与典型值或平均值的偏离程度。

pstdev() 数据的总体标准差
pvariance() 数据的总体方差
stdev() 数据的样本标准差
variance() 数据的样本方差

对两个输入之间关系的统计

这些函数计算两个输入之间关系的统计值。

covariance() 两个变量的样本协方差。
correlation() 两个变量的皮尔逊相关系数。
linear_regression() 简单线性回归的斜率和截距。

函数细节

注释:这些函数不需要对提供给它们的数据进行排序。但是,为了方便阅读,大多数例子展示的是已排序的序列。

statistics.mean(data)

返回 data 的样本算术平均数,形式为序列或迭代器。

算术平均数是数据之和与数据点个数的商。通常称作“平均数”,尽管它指示诸多数学平均数之一。它是数据的中心位置的度量。

data 为空,将会引发 StatisticsError

一些用法示例:

>>> mean([1, 2, 3, 4, 4])
2.8
>>> mean([-1.0, 2.5, 3.25, 5.75])
2.625
>>> from fractions import Fraction as F
>>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
Fraction(13, 21)
>>> from decimal import Decimal as D
>>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
Decimal('0.5625')

注解

均值非常受异常值的影响并且这不是中心位置的可靠估计:均值不一定是数据点的典型示例。

样本均值给出了一个无偏向的真实总体均值的估计,因此当平均抽取所有可能的样本, mean(sample) 收敛于整个总体的真实均值。如果 data 代表整个总体而不是样本,那么 mean(data) 等同于计算真实整体均值 μ 。

statistics.fmean(data)

data 转换成浮点数并且计算算术平均数。

此函数的运行速度比 mean() 函数快并且它总是返回一个 floatdata 可以为序列或可迭代对象。 如果输入数据集为空,则会引发 StatisticsError

>>> fmean([3.5, 4.0, 5.25])
4.25

3.8 新版功能.

statistics.geometric_mean(data)

data 转换成浮点数并且计算几何平均数。

几何平均值使用值的乘积表示 数据 的中心趋势或典型值(与使用它们的总和的算术平均值相反)。

如果输入数据集为空、包含零或包含负值则将引发 StatisticsErrordata 可以是序列或可迭代对象。

无需做出特殊努力即可获得准确的结果。(但是,将来或许会修改。)

>>> round(geometric_mean([54, 24, 36]), 1)
36.0

3.8 新版功能.

statistics.harmonic_mean(data, weights=None)

返回包含实数值的序列或可迭代对象 data 的调和平均数。 如果 weights 被省略或为 None,则会假定权重相等。

调和平均数是数据的倒数的算术平均值 mean() 的倒数。 例如,三个数值 a, bc 的调和平均数将等于 3/(1/a + 1/b + 1/c)。 如果其中一个值为零,则结果也将为零。

调和平均数是均值的一种,是对数据的中心位置的度量。 它通常适用于求比率和比例(如速度)的均值。

假设一辆车在 40 km/hr 的速度下行驶了 10 km ,然后又以 60 km/hr 的速度行驶了 10 km 。车辆的平均速率是多少?

>>> harmonic_mean([40, 60])
48.0

假设一辆汽车以速度 40 公里/小时行驶了 5 公里,当道路变得畅通后,提速到 60 公里/小时行驶了行程中剩余的 30 km。 请问其平均速度是多少?

>>> harmonic_mean([40, 60], weights=[5, 30])
56.0

如果 data 为空、任意元素小于零,或者加权汇总值不为正数则会引发 StatisticsError

当前算法在输入中遇到零时会提前退出。这意味着不会测试后续输入的有效性。(此行为将来可能会更改。)

3.6 新版功能.

在 3.10 版更改: 添加了对 weights 的支持。

statistics.median(data)

使用普通的“取中间两数平均值”方法返回数值数据的中位数(中间值)。 如果 data 为空,则将引发 StatisticsErrordata 可以是序列或可迭代对象。

中位数是衡量中间位置的可靠方式,并且较少受到极端值的影响。 当数据点的总数为奇数时,将返回中间数据点:

>>> median([1, 3, 5])
3

当数据点的总数为偶数时,中位数将通过对两个中间值求平均进行插值得出:

>>> median([1, 3, 5, 7])
4.0

这适用于当你的数据是离散的,并且你不介意中位数不是实际数据点的情况。

如果数据是有序的(支持排序操作)但不是数字(不支持加法),请考虑改用 median_low()median_high()

statistics.median_low(data)

返回数值数据的低中位数。 如果 data 为空则将引发 StatisticsErrordata 可以是序列或可迭代对象。

低中位数一定是数据集的成员。 当数据点总数为奇数时,将返回中间值。 当其为偶数时,将返回两个中间值中较小的那个。

>>> median_low([1, 3, 5])
3
>>> median_low([1, 3, 5, 7])
3

当你的数据是离散的,并且你希望中位数是一个实际数据点而非插值结果时可以使用低中位数。

statistics.median_high(data)

返回数据的高中位数。 如果 data 为空则将引发 StatisticsErrordata 可以是序列或可迭代对象。

高中位数一定是数据集的成员。 当数据点总数为奇数时,将返回中间值。 当其为偶数时,将返回两个中间值中较大的那个。

>>> median_high([1, 3, 5])
3
>>> median_high([1, 3, 5, 7])
5

当你的数据是离散的,并且你希望中位数是一个实际数据点而非插值结果时可以使用高中位数。

statistics.median_grouped(data, interval=1)

返回分组的连续数据的中位数,根据第 50 个百分点的位置使用插值来计算。 如果 data 为空则将引发 StatisticsErrordata 可以是序列或可迭代对象。

>>> median_grouped([52, 52, 53, 54])
52.5

在下面的示例中,数据已经过舍入,这样每个值都代表数据分类的中间点,例如 1 是 0.5—1.5 分类的中间点,2 是 1.5—2.5 分类的中间点,3 是 2.5—3.5 的中间点等待。 根据给定的数据,中间值应落在 3.5—4.5 分类之内,并可使用插值法来进行估算:

>>> median_grouped([1, 2, 2, 3, 4, 4, 4, 4, 4, 5])
3.7

可选参数 interval 表示分类间隔,默认值为 1。 改变分类间隔自然会改变插件结果:

>>> median_grouped([1, 3, 3, 5, 7], interval=1)
3.25
>>> median_grouped([1, 3, 3, 5, 7], interval=2)
3.5

此函数不会检查数据点之间是否至少相隔 interval 的距离。

CPython implementation detail: 在某些情况下,median_grouped() 可以会将数据点强制转换为浮点数。 此行为在未来有可能会发生改变。

参见

  • “Statistics for the Behavioral Sciences”, Frederick J Gravetter and Larry B Wallnau (8th Edition).
  • Gnome Gnumeric 电子表格中的 SSMEDIAN 函数。

statistics.mode(data)

从离散或标称的 data 返回单个出现最多的数据点。 此众数(如果存在)是最典型的值,并可用来度量中心的位置。

如果存在具有相同频率的多个众数,则返回在 data 中遇到的第一个。 如果想要其中最小或最大的一个,请使用 min(multimode(data))max(multimode(data))。 如果输入的 data 为空,则会引发 StatisticsError

mode 将假定是离散数据并返回一个单一的值。 这是通常的学校教学中标准的处理方式:

>>> mode([1, 1, 2, 3, 3, 3, 3, 4])
3

此众数的独特之处在于它是这个包中唯一还可应用于标称(非数字)数据的统计信息:

>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
'red'

在 3.8 版更改: 现在会通过返回所遇到的第一个众数来处理多模数据集。 之前它会在遇到超过一个的众数时引发 StatisticsError

statistics.multimode(data)

返回最频繁出现的值的列表,并按它们在 data 中首次出现的位置排序。 如果存在多个众数则将返回一个以上的众数,或者如果 data 为空则将返回空列表:

>>> multimode('aabbbbccddddeeffffgg')
['b', 'd', 'f']
>>> multimode('')
[]

3.8 新版功能.

statistics.pstdev(data, mu=None)

返回总体标准差(总体方差的平方根)。

>>> pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
0.986893273527251

statistics.pvariance(data, mu=None)

返回非空序列或包含实数值的可迭代对象 data 的总体方差。 方差或称相对于均值的二阶距,是对数据变化幅度(延展度或分散度)的度量。 方差值较大表明数据的散布范围较大;方差值较小表明它紧密聚集于均值附近。

如果给出了可选的第二个参数 mu*,它通常是 *data 的均值。 它也可以被用来计算相对于一个非均值点的二阶距。 如果该参数省略或为 None (默认值),则会自动进行算术均值的计算。

使用此函数可根据所有数值来计算方差。 要根据一个样本来估算方差,通常 variance() 函数是更好的选择。

如果 data 为空则会引发 StatisticsError

示例:

>>> data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]
>>> pvariance(data)
1.25

如果你已经计算过数据的平均值,你可以将其作为可选的第二个参数 mu 传入以避免重复计算:

>>> mu = mean(data)
>>> pvariance(data, mu)
1.25

同样也支持使用 Decimal 和 Fraction 值:

>>> from decimal import Decimal as D
>>> pvariance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
Decimal('24.815')
>>> from fractions import Fraction as F
>>> pvariance([F(1, 4), F(5, 4), F(1, 2)])
Fraction(13, 72)

注解

当调用时附带完整的总体数据时,这将给出总体方差 σ²。 而当调用时只附带一个样本时,这将给出偏置样本方差 s²,也被称为带有 N 个自由度的方差。

如果你通过某种方式知道了真实的总体平均值 μ,则可以使用此函数来计算一个样本的方差,并将已知的总体平均值作为第二个参数。 假设数据点是总体的一个随机样本,则结果将为总体方差的无偏估计值。

statistics.stdev(data, xbar=None)

返回样本标准差(样本方差的平方根)。

>>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
1.0810874155219827

statistics.variance(data, xbar=None)

返回包含至少两个实数值的可迭代对象 data 的样本方差。 方差或称相对于均值的二阶矩,是对数据变化幅度(延展度或分散度)的度量。 方差值较大表明数据的散布范围较大;方差值较小表明它紧密聚集于均值附近。

如果给出了可选的第二个参数 xbar*,它应当是 *data 的均值。 如果该参数省略或为 None (默认值),则会自动进行均值的计算。

当你的数据是总体数据的样本时请使用此函数。

如果 data 包含的值少于两个则会引发 StatisticsError

示例:

>>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
>>> variance(data)
1.3720238095238095

如果你已经计算过数据的平均值,你可以将其作为可选的第二个参数 xbar 传入以避免重复计算:

>>> m = mean(data)
>>> variance(data, m)
1.3720238095238095

此函数不会试图检查你所传入的 xbar 是否为真实的平均值。 使用任意值作为 xbar 可能导致无效或不可能的结果。

同样也支持使用 Decimal 和 Fraction 值:

>>> from decimal import Decimal as D
>>> variance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
Decimal('31.01875')
>>> from fractions import Fraction as F
>>> variance([F(1, 6), F(1, 2), F(5, 3)])
Fraction(67, 108)

注解

这是附带贝塞尔校正的样本方差 s²,也称为具有 N-1 自由度的方差。 假设数据点具有代表性(即为独立且均匀的分布),则结果应当是对总体方差的无偏估计。

如果你通过某种方式知道了真实的总体平均值 μ 则应当调用 pvariance() 函数并将该值作为 mu 形参传入以得到一个样本的方差。

statistics.quantiles(data, **, n=4, method=’exclusive’*)

data 分隔为具有相等概率的 n 个连续区间。 返回分隔这些区间的 n - 1 个分隔点的列表。

n 设为 4 以使用四分位(默认值)。 将 n 设为 10 以使用十分位。 将 n 设为 100 以使用百分位,即给出 99 个分隔点来将 data 分隔为 100 个大小相等的组。 如果 n 小于 1 则将引发 StatisticsError

data 可以是包含样本数据的任意可迭代对象。 为了获得有意义的结果,data 中数据点的数量应当大于 n。 如果数据点的数量小于两个则将引发 StatisticsError

分隔点是通过对两个最接近的数据点进行线性插值得到的。 例如,如果一个分隔点落在两个样本值 100112 之间距离三分之一的位置,则分隔点的取值将为 104

method 用于计算分位值,它会由于 data 是包含还是排除总体的最低和最高可能值而有所不同。

默认 method 是 “唯一的” 并且被用于在总体中数据采样这样可以有比样本中找到的更多的极端值。落在 m 个排序数据点的第 i-th 个以下的总体部分被计算为 i / (m + 1) 。给定九个样本值,方法排序它们并且分配一下的百分位: 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90% 。

method 设为 “inclusive” 可用于描述总体数据或已明确知道包含有总体数据中最极端值的样本。 data 中的最小值会被作为第 0 个百分位而最大值会被作为第 100 个百分位。 总体数据里处于 m 个已排序数据点中 第 i 个 以下的部分会以 (i - 1) / (m - 1) 来计算。 给定 11 个样本值,该方法会对它们进行排序并赋予以下百分位: 0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%, 100%。

# Decile cut points for empirically sampled data
>>> data = [105, 129, 87, 86, 111, 111, 89, 81, 108, 92, 110,
...         100, 75, 105, 103, 109, 76, 119, 99, 91, 103, 129,
...         106, 101, 84, 111, 74, 87, 86, 103, 103, 106, 86,
...         111, 75, 87, 102, 121, 111, 88, 89, 101, 106, 95,
...         103, 107, 101, 81, 109, 104]
>>> [round(q, 1) for q in quantiles(data, n=10)]
[81.0, 86.2, 89.0, 99.4, 102.5, 103.6, 106.0, 109.8, 111.0]

3.8 新版功能.

statistics.covariance(x, y, /)

返回两个输入 xy 的样本协方差。 样本协方差是对两个输入的同步变化性的度量。

两个输入必须具有相同的长度(不少于两个元素),否则会引发 StatisticsError

示例:

>>> x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> y = [1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> covariance(x, y)
0.75
>>> z = [9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> covariance(x, z)
-7.5
>>> covariance(z, x)
-7.5

3.10 新版功能.

statistics.correlation(x, y, /)

返回两个输入的 皮尔逊相关系数。 皮尔逊相关系数 r 的取值在 -1 到 +1 之间。 它衡量线性相关的强度和方向,其中 +1 表示非常强的正线性相关,-1 表示非常强的负线性相关,0 表示无线性相关。

两个输入必须具有相同的长度(不少于两个元素),并且不必为常量,否则会引发 StatisticsError

示例:

>>> x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> y = [9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> correlation(x, x)
1.0
>>> correlation(x, y)
-1.0

3.10 新版功能.

statistics.linear_regression(x, y, /)

返回使用普通最小二乘法估计得到的 简单线性回归 参数的斜率和截距。 简单纯属回归通过此线性函数来描述自变量 x 和因变量 y 之间的关系。

y = slope \ x + intercept + noise*

其中 slopeintercept 是估计得到的回归参数,而 noise 代表不可由线性回归解释的数据变异性(它等于因变量的预测值和实际值之间的差异)。

两个输入必须具有相同的长度(不少于两个元素),并且自变量 x 不可为常量;否则会引发 StatisticsError

例如,我们可以使用 Monty Python 系列电影的发布日期 在假定出品方保持现有步调的情况下预测到 2019 年时产出的 Monty Python 电影的累计数量。

>>> year = [1971, 1975, 1979, 1982, 1983]
>>> films_total = [1, 2, 3, 4, 5]
>>> slope, intercept = linear_regression(year, films_total)
>>> round(slope * 2019 + intercept)
16

3.10 新版功能.

异常

只定义了一个异常:

exception statistics.StatisticsError

ValueError 的子类,表示统计相关的异常。

NormalDist 对象

NormalDist 工具可用于创建和操纵 随机变量 的正态分布。 这个类将数据度量值的平均值和标准差作为单一实体来处理。

正态分布的概念来自于 中央极限定理 并且在统计学中有广泛的应用。

class statistics.NormalDist(mu=0.0, sigma=1.0)

返回一个新的 NormalDist 对象,其中 mu 代表 算术平均值sigma 代表 标准差

sigma 为负数,将会引发 StatisticsError

  • mean

    一个只读特征属性,表示特定正态分布的 算术平均值

  • median

    一个只读特征属性,表示特定正态分布的 中位数

  • mode

    一个只读特征属性,表示特定正态分布的 众数

  • stdev

    一个只读特征属性,表示特定正态分布的 标准差

  • variance

    一个只读特征属性,表示特定正态分布的 方差。 等于标准差的平方。

  • classmethod from_samples(data)

    传入使用 fmean()stdev() 基于 data 估算出的 musigma 形参创建一个正态分布实例。

    data 可以是任何 iterable 并且应当包含能被转换为 float 类型的值。 如果 data 不包含至少两个元素,则会引发 StatisticsError,因为估算中心值至少需要一个点而估算分散度至少需要两个点。

  • samples(n, **, seed=None*)

    对于给定的平均值和标准差生成 n 个随机样本。 返回一个由 float 值组成的 list

    当给定 seed 时,创建一个新的底层随机数生成器实例。 这适用于创建可重现的结果,即使对于多线程上下文也有效。

  • pdf(x)

    使用 概率密度函数 (pdf),计算一个随机变量 X 趋向于给定值 x 的相对可能性。 在数学意义上,它是当 dx 趋向于零时比率 P(x <= X < x+dx) / dx 的极限。

    相对可能性的计算方法是用一个狭窄区间内某个样本出现的概率除以区间的宽度(因此使用“密度”一词)。 由于可能性是相对于其他点的,它的值可以大于 1.0。

  • cdf(x)

    使用 累积分布函数 (cdf),计算一个随机变量 X 小于等于 x 的概率。 在数学上,它表示为 P(X <= x)

  • inv_cdf(p)

    计算反向累积分布函数,也称为 分位数函数百分点 函数。 在数学上,它表示为 x : P(X <= x) = p

    找出随机变量 X 的值 x 使得该变量小于等于该值的概率等于给定的概率 p

  • overlap(other)

    测量两个正态概率分布之间的一致性。 返回介于 0.0 和 1.0 之间的值,给出 两个概率密度函数的重叠区域

  • quantiles(n=4)

    将指定正态分布划分为 n 个相等概率的连续分隔区。 返回这些分隔区对应的 (n - 1) 个分隔点的列表。

    n 设为 4 以使用四分位(默认值)。 将 n 设为 10 以使用十分位。将 n 设为 100 以使用百分位,即给出 99 个分隔点来将正态分布分隔为 100 个大小相等的组。

  • zscore(x)

    计算 标准分 即以高于或低于正态分布的平均值的标准差数值的形式来描述 x: (x - mean) / stdev.

    3.9 新版功能.

NormalDist 的实例支持加上、减去、乘以或除以一个常量。 这些运算被用于转换和缩放。 例如:

>>> temperature_february = NormalDist(5, 2.5)             # Celsius
>>> temperature_february * (9/5) + 32                     # Fahrenheit
NormalDist(mu=41.0, sigma=4.5)

不允许一个常量除以 NormalDist 的实例,因为结果将不是正态分布。

由于正态分布是由独立变量的累加效应产生的,因此允许表示为 NormalDist 实例的 两组独立正态分布的随机变量相加和相减。 例如:

>>> birth_weights = NormalDist.from_samples([2.5, 3.1, 2.1, 2.4, 2.7, 3.5])
>>> drug_effects = NormalDist(0.4, 0.15)
>>> combined = birth_weights + drug_effects
>>> round(combined.mean, 1)
3.1
>>> round(combined.stdev, 1)
0.5

3.8 新版功能.

NormalDist 示例和用法

NormalDist 适合用来解决经典概率问题。

举例来说,如果 SAT 考试的历史数据 显示分数呈平均值为 1060 且标准差为 195 的正态分布,则可以确定考试分数处于 1100 和 1200 之间的学生的百分比舍入到最接近的整数应为:

>>> sat = NormalDist(1060, 195)
>>> fraction = sat.cdf(1200 + 0.5) - sat.cdf(1100 - 0.5)
>>> round(fraction * 100.0, 1)
18.4

求 SAT 分数的 四分位十分位

>>> list(map(round, sat.quantiles()))
[928, 1060, 1192]
>>> list(map(round, sat.quantiles(n=10)))
[810, 896, 958, 1011, 1060, 1109, 1162, 1224, 1310]

为了估算一个不易解析的模型分布,NormalDist 可以生成用于 蒙特卡洛模拟 的输入样本:

>>> def model(x, y, z):
...     return (3*x + 7*x*y - 5*y) / (11 * z)
...
>>> n = 100_000
>>> X = NormalDist(10, 2.5).samples(n, seed=3652260728)
>>> Y = NormalDist(15, 1.75).samples(n, seed=4582495471)
>>> Z = NormalDist(50, 1.25).samples(n, seed=6582483453)
>>> quantiles(map(model, X, Y, Z))       
[1.4591308524824727, 1.8035946855390597, 2.175091447274739]

当样本量较大并且成功试验的可能性接近 50% 时,正态分布可以被用来模拟 二项分布

例如,一次开源会议有 750 名与会者和两个可分别容纳 500 人的会议厅。 会上有一场关于 Python 的演讲和一场关于 Ruby 的演讲。 在往届会议中,65% 的与会者更愿意去听关于 Python 的演讲。 假定人群的偏好没有发生改变,那么 Python 演讲的会议厅不超出其容量上限的可能性是多少?

>>> n = 750             # Sample size
>>> p = 0.65            # Preference for Python
>>> q = 1.0 - p         # Preference for Ruby
>>> k = 500             # Room capacity
>>> # Approximation using the cumulative normal distribution
>>> from math import sqrt
>>> round(NormalDist(mu=n*p, sigma=sqrt(n*p*q)).cdf(k + 0.5), 4)
0.8402
>>> # Solution using the cumulative binomial distribution
>>> from math import comb, fsum
>>> round(fsum(comb(n, r) * p**r * q**(n-r) for r in range(k+1)), 4)
0.8402
>>> # Approximation using a simulation
>>> from random import seed, choices
>>> seed(8675309)
>>> def trial():
...     return choices(('Python', 'Ruby'), (p, q), k=n).count('Python')
>>> mean(trial() <= k for i in range(10_000))
0.8398

在机器学习问题中也经常会出现正态分布。

Wikipedia 上有一个 朴素贝叶斯分类器的好例子。 挑战的问题是根据对多个正态分布的特征测量值包括身高、体重和足部尺码来预测一个人的性别。

我们得到了由八个人的测量值组成的训练数据集。 假定这些测量值是正态分布的,因此我们用 NormalDist 来总结数据:

>>> height_male = NormalDist.from_samples([6, 5.92, 5.58, 5.92])
>>> height_female = NormalDist.from_samples([5, 5.5, 5.42, 5.75])
>>> weight_male = NormalDist.from_samples([180, 190, 170, 165])
>>> weight_female = NormalDist.from_samples([100, 150, 130, 150])
>>> foot_size_male = NormalDist.from_samples([12, 11, 12, 10])
>>> foot_size_female = NormalDist.from_samples([6, 8, 7, 9])

接下来,我们遇到一个特征测量值已知但性别未知的新人:

>>> ht = 6.0        # height
>>> wt = 130        # weight
>>> fs = 8          # foot size

从是男是女各 50% 的 先验概率 出发,我们通过将该先验概率乘以给定性别的特征度量值的可能性累积值来计算后验概率:

>>> prior_male = 0.5
>>> prior_female = 0.5
>>> posterior_male = (prior_male * height_male.pdf(ht) *
...                   weight_male.pdf(wt) * foot_size_male.pdf(fs))
>>> posterior_female = (prior_female * height_female.pdf(ht) *
...                     weight_female.pdf(wt) * foot_size_female.pdf(fs))

最终预测值应为最大后验概率值。 这种算法被称为 maximum a posteriori 或 MAP:

>>> 'male' if posterior_male > posterior_female else 'female'
'female'

文章作者: 杰克成
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 杰克成 !
评论
  目录