Python-Standard Library


Python 标准库

  • 多媒体服务
    • audioop —- 处理原始音频数据
    • aifc —- 读写 AIFF 和 AIFC 文件
    • sunau —- 读写 Sun AU 文件
    • wave —- 读写WAV格式文件
    • chunk —- 读取 IFF 分块数据
    • colorsys —- 颜色系统间的转换
    • imghdr —- 推测图像类型
    • sndhdr —- 推测声音文件的类型
    • ossaudiodev —- 访问兼容OSS的音频设备
  • 国际化
    • gettext —- 多语种国际化服务
    • locale —- 国际化服务
  • 程序框架
    • turtle —- 海龟绘图
    • cmd —- 支持面向行的命令解释器
    • shlex —— 简单的词法分析
  • Tk图形用户界面(GUI)
    • tkinter —- Tcl/Tk的Python接口
    • tkinter.colorchooser —- 颜色选择对话框
    • tkinter.font —- Tkinter 字体封装
    • Tkinter 对话框
    • tkinter.messagebox —- Tkinter 消息提示
    • tkinter.scrolledtext —- 滚动文字控件
    • tkinter.dnd —- 拖放操作支持
    • tkinter.ttk —- Tk主题部件
    • tkinter.tix —- TK扩展包
    • IDLE
  • 开发工具
    • typing —- 类型提示支持
    • pydoc —- 文档生成器和在线帮助系统
    • Python Development Mode
    • Effects of the Python Development Mode
    • ResourceWarning Example
    • Bad file descriptor error example
    • doctest —- 测试交互性的Python示例
    • unittest —- 单元测试框架
    • unittest.mock —- 模拟对象库
    • unittest.mock 上手指南
    • 2to3 - 自动将 Python 2 代码转为 Python 3 代码
    • test —- Python回归测试包
    • test.support —- Utilities for the Python test suite
    • test.support.socket_helper —- Utilities for socket tests
    • test.support.script_helper —- Utilities for the Python execution tests
    • test.support.bytecode_helper —- Support tools for testing correct bytecode generation
    • test.support.threading_helper —- Utilities for threading tests
    • test.support.os_helper —- Utilities for os tests
    • test.support.import_helper —- Utilities for import tests
    • test.support.warnings_helper —- Utilities for warnings tests
  • 调试和分析
    • 审计事件表
    • bdb —- Debugger framework
    • faulthandler —- Dump the Python traceback
    • pdb —- Python 的调试器
    • Python Profilers 分析器
    • timeit —- 测量小代码片段的执行时间
    • trace —- 跟踪Python语句的执行
    • tracemalloc —- 跟踪内存分配
  • 软件打包和分发
    • distutils —- 构建和安装 Python 模块
    • ensurepip —- Bootstrapping the pip installer
    • venv —- 创建虚拟环境
    • zipapp —- Manage executable Python zip archives
  • Python运行时服务
    • sys —- 系统相关的参数和函数
    • sysconfig —- Provide access to Python’s configuration information
    • builtins —- 内建对象
    • __main__ —- Top-level code environment
    • warnings —— 警告信息的控制
    • dataclasses —- 数据类
    • contextlib —- 为 with语句上下文提供的工具
    • abc —- 抽象基类
    • atexit —- 退出处理器
    • traceback —- 打印或检索堆栈回溯
    • __future__ —- Future 语句定义
    • gc —- 垃圾回收器接口
    • inspect —- 检查对象
    • site —— 指定域的配置钩子
  • 自定义 Python 解释器
    • code —- 解释器基类
    • codeop —- 编译Python代码
  • 导入模块
    • zipimport —- 从 Zip 存档中导入模块
    • pkgutil —- 包扩展工具
    • modulefinder —- 查找脚本使用的模块
    • runpy ——查找并执行 Python 模块
    • importlib —- import 的实现
    • Using importlib.metadata
  • Python 语言服务
    • ast —- 抽象语法树
    • symtable —- Access to the compiler’s symbol tables
    • token —- 与Python解析树一起使用的常量
    • keyword —- 检验Python关键字
    • tokenize —- 对 Python 代码使用的标记解析器
    • tabnanny —- 模糊缩进检测
    • pyclbr —- Python 模块浏览器支持
    • py_compile —- 编译 Python 源文件
    • compileall —- Byte-compile Python libraries
    • dis —- Python 字节码反汇编器
    • pickletools —- pickle 开发者工具集
  • Windows系统相关模块
    • msilib —- Read and write Microsoft Installer files
    • msvcrt —- 来自 MS VC++ 运行时的有用例程
    • winreg —- 访问 Windows 注册表
    • winsound —— Windows 系统的音频播放接口
  • Unix 专有服务
    • posix —- 最常见的 POSIX 系统调用
    • pwd —- 用户密码数据库
    • spwd —- The shadow password database
    • grp —- 组数据库
    • crypt —— 验证 Unix 口令的函数
    • termios —- POSIX 风格的 tty 控制
    • tty —- 终端控制功能
    • pty —- 伪终端工具
    • fcntl —— 系统调用 fcntlioctl
    • pipes —- 终端管道接口
    • resource —- Resource usage information
    • nis —- Sun 的 NIS (黄页) 接口
    • Unix syslog 库例程
  • 被取代的模块
    • optparse —- 解析器的命令行选项
    • imp —- Access the import internals
  • 未创建文档的模块
    • 平台特定模块
  • Security Considerations

多媒体服务

本章描述的模块实现了主要用于多媒体应用的各种算法或接口。 它们可在安装时自行决定。 这是一个概述:

  • audioop —- 处理原始音频数据
  • aifc —- 读写 AIFF 和 AIFC 文件
  • sunau —- 读写 Sun AU 文件
    • AU_read 对象
    • AU_write 对象
  • wave —- 读写WAV格式文件
    • Wave_read对象
    • Wave_write 对象
  • chunk —- 读取 IFF 分块数据
  • colorsys —- 颜色系统间的转换
  • imghdr —- 推测图像类型
  • sndhdr —- 推测声音文件的类型
  • ossaudiodev —- 访问兼容OSS的音频设备
    • Audio Device Objects
    • Mixer Device Objects

audioop —- 处理原始音频数据

audioop 模块包含针对声音片段的一些有用操作。它操作的声音片段由 8、16、24 或 32 位宽的有符号整型采样值组成,存储在 类字节串对象 中。除非特别说明,否则所有标量项目均为整数。

在 3.4 版更改: 增加了对 24 位采样的支持。现在,所有函数都接受任何 类字节串对象。而传入字符串会立即导致错误。

本模块提供对 a-LAW、u-LAW 和 Intel/DVI ADPCM 编码的支持。

部分更复杂的操作仅接受 16 位采样,而其他操作始终需要采样大小(以字节为单位)作为该操作的参数。

此模块定义了下列变量和函数:

exceptionaudioop.error

所有错误都会抛出此异常,比如采样值的字节数未知等等。

audioop.add(fragment1, fragment2, width)

两个采样作为参数传入,返回一个片段,该片段是两个采样的和。width 是采样位宽(以字节为单位),可以取 1, 2, 34。两个片段的长度应相同。如果发生溢出,较长的采样将被截断。

audioop.adpcm2lin(adpcmfragment, width, state)

将 Intel/DVI ADPCM 编码的片段解码为线性片段。关于 ADPCM 编码的详情请参阅 lin2adpcm() 的描述。返回一个元组 (sample, newstate),其中 sample 的位宽由 width 指定。

audioop.alaw2lin(fragment, width)

将 a-LAW 编码的声音片段转换为线性编码声音片段。由于 a-LAW 编码采样值始终为 8 位,因此这里的 width 仅指输出片段的采样位宽。

audioop.avg(fragment, width)

返回片段中所有采样值的平均值。

audioop.avgpp(fragment, width)

返回片段中所有采样值的平均峰峰值。由于没有进行过滤,因此该例程的实用性尚存疑。

audioop.bias(fragment, width, bias)

返回一个片段,该片段由原始片段中的每个采样值加上偏差组成。在溢出时采样值会回卷 (wrap around)。

audioop.byteswap(fragment, width)

“按字节交换”片段中的所有采样值,返回修改后的片段。将大端序采样转换为小端序采样,反之亦然。

3.4 新版功能.

audioop.cross(fragment, width)

将片段作为参数传入,返回其中过零点的数量。

audioop.findfactor(fragment, reference)

返回一个系数 F 使得 rms(add(fragment, mul(reference, -F))) 最小,即返回的系数乘以 reference 后与 fragment 最匹配。两个片段都应包含 2 字节宽的采样。

本例程所需的时间与 len(fragment) 成正比。

audioop.findfit(fragment, reference)

尽可能尝试让 reference 匹配 fragment 的一部分(fragment 应较长)。从概念上讲,完成这些靠从 fragment 中取出切片,使用 findfactor() 计算最佳匹配,并最小化结果。两个片段都应包含 2 字节宽的采样。返回一个元组 (offset, factor),其中 offset 是在 fragment 中的偏移量(整数),表示从此处开始最佳匹配,而 factor 是由 findfactor() 定义的因数(浮点数)。

audioop.findmax(fragment, length)

fragment 中搜索所有长度为 length 的采样切片(不是字节!)中,能量最大的那一个切片,即返回 i 使得 rms(fragment[i*2:(i+length)*2]) 最大。两个片段都应包含 2 字节宽的采样。

本例程所需的时间与 len(fragment) 成正比。

audioop.getsample(fragment, width, index)

返回片段中采样值索引 index 的值。

audioop.lin2adpcm(fragment, width, state)

将采样转换为 4 位 Intel/DVI ADPCM 编码。ADPCM 编码是一种自适应编码方案,其中每个 4 比特数字是一个采样值与下一个采样值之间的差除以(不定的)步长。IMA 已选择使用 Intel/DVI ADPCM 算法,因此它很可能成为标准。

state 是一个表示编码器状态的元组。编码器返回一个元组 (adpcmfrag, newstate),而 newstate 要在下一次调用 lin2adpcm() 时传入。在初始调用中,可以将 None 作为 state 传递。adpcmfrag 是 ADPCM 编码的片段,每个字节打包了 2 个 4 比特值。

audioop.lin2alaw(fragment, width)

将音频片段中的采样值转换为 a-LAW 编码,并将其作为字节对象返回。a-LAW 是一种音频编码格式,仅使用 8 位采样即可获得大约 13 位的动态范围。Sun 音频硬件等使用该编码。

audioop.lin2lin(fragment, width, newwidth)

将采样在 1、2、3 和 4 字节格式之间转换。

注解

在某些音频格式(如 .WAV 文件)中,16、24 和 32 位采样是有符号的,但 8 位采样是无符号的。因此,当将这些格式转换为 8 位宽采样时,还需使结果加上 128:

new_frames = audioop.lin2lin(frames, old_width,1)
new_frames = audioop.bias(new_frames,1,128)

反之,将 8 位宽的采样转换为 16、24 或 32 位时,必须采用相同的处理。

audioop.lin2ulaw(fragment, width)

将音频片段中的采样值转换为 u-LAW 编码,并将其作为字节对象返回。u-LAW 是一种音频编码格式,仅使用 8 位采样即可获得大约 14 位的动态范围。Sun 音频硬件等使用该编码。

audioop.max(fragment, width)

返回片段中所有采样值的最大 绝对值

audioop.maxpp(fragment, width)

返回声音片段中的最大峰峰值。

audioop.minmax(fragment, width)

返回声音片段中所有采样值的最小值和最大值组成的元组。

audioop.mul(fragment, width, factor)

返回一个片段,该片段由原始片段中的每个采样值乘以浮点值 factor 组成。如果发生溢出,采样将被截断。

audioop.ratecv(fragment, width, nchannels, inrate, outrate, state[, weightA[, weightB]])

转换输入片段的帧速率。

state 是一个表示转换器状态的元组。转换器返回一个元组 (newfragment, newstate),而 newstate 要在下一次调用 ratecv() 时传入。初始调用应传入 None 作为 state。

参数 weightAweightB 是简单数字滤波器的参数,默认分别为 10

audioop.reverse(fragment, width)

将片段中的采样值反转,返回修改后的片段。

audioop.rms(fragment, width)

返回片段的均方根值,即 sqrt(sum(S_i^2)/n)

测量音频信号的能量。

audioop.tomono(fragment, width, lfactor, rfactor)

将立体声片段转换为单声道片段。左通道乘以 lfactor,右通道乘以 rfactor,然后两个通道相加得到单声道信号。

audioop.tostereo(fragment, width, lfactor, rfactor)

由单声道片段生成立体声片段。立体声片段中的两对采样都是从单声道计算而来的,即左声道是乘以 lfactor,右声道是乘以 rfactor

audioop.ulaw2lin(fragment, width)

将 u-LAW 编码的声音片段转换为线性编码声音片段。由于 u-LAW 编码采样值始终为 8 位,因此这里的 width 仅指输出片段的采样位宽。

请注意,诸如 mul()max() 之类的操作在单声道和立体声间没有区别,即所有采样都作相同处理。如果出现问题,应先将立体声片段拆分为两个单声道片段,之后再重组。以下是如何进行该操作的示例:

def mul_stereo(sample, width, lfactor, rfactor):
    lsample = audioop.tomono(sample, width,1,0)
    rsample = audioop.tomono(sample, width,0,1)
    lsample = audioop.mul(lsample, width, lfactor)
    rsample = audioop.mul(rsample, width, rfactor)
    lsample = audioop.tostereo(lsample, width,1,0)
    rsample = audioop.tostereo(rsample, width,0,1)
return audioop.add(lsample, rsample, width)

如果使用 ADPCM 编码器构造网络数据包,并且希望协议是无状态的(即能够容忍数据包丢失),则不仅需要传输数据,还应该传输状态。请注意,必须将初始状态(传入 lin2adpcm() 的状态)发送给解码器,不能发送最终状态(编码器返回的状态)。如果要使用 struct.Struct 以二进制保存状态,可以将第一个元素(预测值)用 16 位编码,将第二个元素(增量索引)用 8 位编码。

本 ADPCM 编码器从不与其他 ADPCM 编码器对立,仅针对自身。本开发者可能会误读标准,这种情况下它们将无法与相应标准互操作。

乍看之下 find*() 例程可能有些可笑。它们主要是用于回声消除,一种快速有效的方法是选取输出样本中能量最高的片段,在输入样本中定位该片段,然后从输入样本中减去整个输出样本:

def echocancel(outputdata, inputdata):
    pos = audioop.findmax(outputdata,800)# one tenth second
    out_test = outputdata[pos*2:]
    in_test = inputdata[pos*2:]
    ipos, factor = audioop.findfit(in_test, out_test)
# Optional (for better cancellation):
# factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)],
#              out_test)
    prefill ='\0'*(pos+ipos)*2
    postfill ='\0'*(len(inputdata)-len(prefill)-len(outputdata))
    outputdata = prefill + audioop.mul(outputdata,2,-factor)+ postfill
return audioop.add(inputdata, outputdata,2)

aifc —- 读写 AIFF 和 AIFC 文件

源代码: Lib/aifc.py


本模块提供读写 AIFF 和 AIFF-C 文件的支持。AIFF 是音频交换文件格式 (Audio Interchange File Format),一种用于在文件中存储数字音频采样的格式。AIFF-C 是该格式的更新版本,其中包括压缩音频数据的功能。

音频文件内有许多参数,用于描述音频数据。采样率或帧率是每秒对声音采样的次数。通道数表示音频是单声道,双声道还是四声道。每个通道的每个帧包含一次采样。采样大小是以字节表示的每次采样的大小。因此,一帧由 nchannels * samplesize (通道数采样大小)字节组成,而一秒钟的音频包含 nchannels * samplesize * framerate (通道数采样大小*帧率)字节。

例如,CD 质量的音频采样大小为 2 字节(16位),使用 2 个声道(立体声),且帧速率为 44,100 帧/秒。这表示帧大小为 4 字节 (22),一秒钟占用 22*44100 字节(176,400 字节)。

aifc 模块定义了以下函数:

aifc.open(file, mode=None)

打开一个 AIFF 或 AIFF-C 文件并返回一个对象实例,该实例具有下方描述的方法。参数 file 是文件名称字符串或 文件对象。当打开文件用于读取时,mode 必须为 'r''rb',当打开文件用于写入时,mode 必须为 'w''wb'。如果该参数省略,则使用 file.mode 的值(如果有),否则使用 'rb'。当文件用于写入时,文件对象应该支持 seek 操作,除非提前获知写入的采样总数,并使用 writeframesraw()setnframes()open() 函数可以在 with 语句中使用。当 with 块执行完毕,将调用 close() 方法。

在 3.4 版更改: 添加了对 with 语句的支持。

当打开文件用于读取时,由 open() 返回的对象具有以下几种方法:

aifc.getnchannels()

返回音频的通道数(单声道为 1,立体声为 2)。

aifc.getsampwidth()

返回以字节表示的单个采样的大小。

aifc.getframerate()

返回采样率(每秒的音频帧数)。

aifc.getnframes()

返回文件中的音频帧总数。

aifc.getcomptype()

返回一个长度为 4 的字节数组,描述了音频文件中使用的压缩类型。对于 AIFF 文件,返回值为 b'NONE'

aifc.getcompname()

返回一个字节数组,可转换为人类可读的描述,描述的是音频文件中使用的压缩类型。对于 AIFF 文件,返回值为 b'not compressed'

aifc.getparams()

返回一个 namedtuple() (nchannels, sampwidth, framerate, nframes, comptype, compname),与 get*() 方法的输出相同。

aifc.getmarkers()

返回一个列表,包含音频文件中的所有标记。标记由一个 3 元素的元组组成。第一个元素是标记 ID(整数),第二个是标记位置,从数据开头算起的帧数(整数),第三个是标记的名称(字符串)。

aifc.getmark(id)

根据传入的标记 id 返回元组,元组与 getmarkers() 中描述的一致。

aifc.readframes(nframes)

从音频文件读取并返回后续 nframes 个帧。返回的数据是一个字符串,包含每个帧所有通道的未压缩采样值。

aifc.rewind()

倒回读取指针。下一次 readframes() 将从头开始。

aifc.setpos(pos)

移动读取指针到指定的帧上。

aifc.tell()

返回当前的帧号。

aifc.close()

关闭 AIFF 文件。调用此方法后,对象将无法再使用。

打开文件用于写入时,open() 返回的对象具有上述所有方法,但 readframes()setpos() 除外,并额外具备了以下方法。只有调用了 set*() 方法之后,才能调用相应的 get*() 方法。在首次调用 writeframes()writeframesraw() 之前,必须填写除帧数以外的所有参数。

aifc.aiff()

创建一个 AIFF 文件,默认创建 AIFF-C 文件,除非文件名以 '.aiff' 为后缀,在此情况下默认创建 AIFF 文件。

aifc.aifc()

创建一个 AIFF-C 文件。 默认创建 AIFF-C 文件,除非文件名以 '.aiff' 为后缀,在此情况下默认创建 AIFF 文件。

aifc.setnchannels(nchannels)

指明音频文件中的通道数。

aifc.setsampwidth(width)

指明以字节为单位的音频采样大小。

aifc.setframerate(rate)

指明以每秒帧数表示的采样频率。

aifc.setnframes(nframes)

指明要写入到音频文件的帧数。 如果未设定此形参或者未正确设定,则文件需要支持位置查找。

aifc.setcomptype(type, name)

指明压缩类型。 如果未指明,则音频数据将不会被压缩。 在 AIFF 文件中,压缩是无法实现的。 name 形参应当为以字节数组表示的人类可读的压缩类型描述,type 形参应当为长度为 4 的字节数组。 目前支持的压缩类型如下: b'NONE', b'ULAW', b'ALAW', b'G722'

aifc.setparams(nchannels, sampwidth, framerate, comptype, compname)

一次性设置上述所有参数。 该参数是由多个形参组成的元组。 这意味着可以使用 getparams() 调用的结果作为 setparams() 的参数。

aifc.setmark(id, pos, name)

添加具有给定 id (大于 0),以及在给定位置上给定名称的标记。 此方法可在 close() 之前的任何时候被调用。

aifc.tell()

返回输出文件中的当前写入位置。 适用于与 setmark() 进行协同配合。

aifc.writeframes(data)

将数据写入到输出文件。 此方法只能在设置了音频文件形参之后被调用。

在 3.4 版更改: 现在可接受任意 bytes-like object。

aifc.writeframesraw(data)

类似于 writeframes(),不同之处在于音频文件的标头不会被更新。

在 3.4 版更改: 现在可接受任意 bytes-like object。

aifc.close()

关闭 AIFF 文件。 文件的标头会被更新以反映音频数据的实际大小。 在调用此方法之后,对象将无法再被使用。

sunau —- 读写 Sun AU 文件

源代码: Lib/sunau.py


sunau 模拟提供了一个处理 Sun AU 声音格式的便利接口。请注意此模块与 aifcwave 是兼容接口的。

音频文件由标头和数据组成。标头的字段为:

目录
magic word 四个字节 .snd
header size 标头的大小,包括信息,以字节为单位。
data size 数据的物理大小,以字节为单位。
编码 指示音频样本的编码方式。
sample rate 采样率
# of channels 采样中的通道数。
info 提供音频文件描述的ASCII字符串(用空字节填充)。

Apart from the info field, all header fields are 4 bytes in size. They are all 32-bit unsigned integers encoded in big-endian byte order.

The sunau module defines the following functions:

sunau.open(file, mode)

If file is a string, open the file by that name, otherwise treat it as a seekable file-like object. mode can be any of

  • 'r'

    只读模式。

    'w'

    只写模式。

Note that it does not allow read/write files.

A mode of 'r' returns an AU_read object, while a mode of 'w' or 'wb' returns an AU_write object.

The sunau module defines the following exception:

exception sunau.Error

An error raised when something is impossible because of Sun AU specs or implementation deficiency.

The sunau module defines the following data items:

sunau.AUDIO_FILE_MAGIC

An integer every valid Sun AU file begins with, stored in big-endian form. This is the string .snd interpreted as an integer.

sunau.AUDIO_FILE_ENCODING_MULAW_8
sunau.AUDIO_FILE_ENCODING_LINEAR_8
sunau.AUDIO_FILE_ENCODING_LINEAR_16
sunau.AUDIO_FILE_ENCODING_LINEAR_24
sunau.AUDIO_FILE_ENCODING_LINEAR_32
sunau.AUDIO_FILE_ENCODING_ALAW_8

Values of the encoding field from the AU header which are supported by this module.

sunau.AUDIO_FILE_ENCODING_FLOAT
sunau.AUDIO_FILE_ENCODING_DOUBLE
sunau.AUDIO_FILE_ENCODING_ADPCM_G721
sunau.AUDIO_FILE_ENCODING_ADPCM_G722
sunau.AUDIO_FILE_ENCODING_ADPCM_G723_3
sunau.AUDIO_FILE_ENCODING_ADPCM_G723_5

Additional known values of the encoding field from the AU header, but which are not supported by this module.

AU_read 对象

AU_read objects, as returned by open() above, have the following methods:

AU_read.close()

Close the stream, and make the instance unusable. (This is called automatically on deletion.)

AU_read.getnchannels()

Returns number of audio channels (1 for mono, 2 for stereo).

AU_read.getsampwidth()

返回采样字节长度。

AU_read.getframerate()

返回采样频率。

AU_read.getnframes()

返回音频总帧数。

AU_read.getcomptype()

Returns compression type. Supported compression types are 'ULAW', 'ALAW' and 'NONE'.

AU_read.getcompname()

Human-readable version of getcomptype(). The supported types have the respective names 'CCITT G.711 u-law', 'CCITT G.711 A-law' and 'not compressed'.

AU_read.getparams()

返回一个 namedtuple() (nchannels, sampwidth, framerate, nframes, comptype, compname),与 get*() 方法的输出相同。

AU_read.readframes(n)

Reads and returns at most n frames of audio, as a bytes object. The data will be returned in linear format. If the original data is in u-LAW format, it will be converted.

AU_read.rewind()

重置文件指针至音频开头.

以下两个方法都使用指针,具体实现由其底层决定。

AU_read.setpos(pos)

Set the file pointer to the specified position. Only values returned from tell() should be used for pos.

AU_read.tell()

Return current file pointer position. Note that the returned value has nothing to do with the actual position in the file.

The following two functions are defined for compatibility with the aifc, and don’t do anything interesting.

AU_read.getmarkers()

返回 None

AU_read.getmark(id)

引发错误异常。

AU_write 对象

AU_write objects, as returned by open() above, have the following methods:

AU_write.setnchannels(n)

设置声道数。

AU_write.setsampwidth(n)

Set the sample width (in bytes.)

在 3.4 版更改: Added support for 24-bit samples.

AU_write.setframerate(n)

Set the frame rate.

AU_write.setnframes(n)

Set the number of frames. This can be later changed, when and if more frames are written.

AU_write.setcomptype(type, name)

Set the compression type and description. Only 'NONE' and 'ULAW' are supported on output.

AU_write.setparams(tuple)

The tuple should be (nchannels, sampwidth, framerate, nframes, comptype, compname), with values valid for the set*() methods. Set all parameters.

AU_write.tell()

Return current position in the file, with the same disclaimer for the AU_read.tell() and AU_read.setpos() methods.

AU_write.writeframesraw(data)

写入音频数据但不更新 nframes

在 3.4 版更改: 现在可接受任意 bytes-like object。

AU_write.writeframes(data)

写入音频数据并更新 nframes

在 3.4 版更改: 现在可接受任意 bytes-like object。

AU_write.close()

Make sure nframes is correct, and close the file.

This method is called upon deletion.

Note that it is invalid to set any parameters after calling writeframes() or writeframesraw().

wave —- 读写WAV格式文件

源代码: Lib/wave.py


wave 模块提供了一个处理 WAV 声音格式的便利接口。它不支持压缩/解压,但是支持单声道/立体声。

wave 模块定义了以下函数和异常:

wave.open(file, mode=None)

如果 file 是一个字符串,打开对应文件名的文件。否则就把它作为文件类对象来处理。mode 可以为以下值:

  • 'rb'

    只读模式。

    'wb'

    只写模式。

注意不支持同时读写WAV文件。

mode 设为 'rb' 时返回一个 Wave_read 对象,而 mode 设为 'wb' 时返回一个 Wave_write 对象。如果省略 mode 并指定 file 来传入一个文件类对象,则 file.mode 会被用作 mode 的默认值。

如果操作的是文件对象,当使用 wave 对象的 close() 方法时,并不会真正关闭文件对象,这需要调用者负责来关闭文件对象。

open() 函数可以在 with 语句中使用。 当 with 阻塞结束时,Wave_read.close()Wave_write.close() 方法会被调用。

在 3.4 版更改: 添加了对不可搜索文件的支持。

exception wave.Error

当不符合WAV格式或无法操作时引发的错误。

Wave_read对象

open() 返回的 Wave_read 对象,有以下几种方法:

Wave_read.close()

关闭 wave 打开的数据流并使对象不可用。当对象销毁时会自动调用。

Wave_read.getnchannels()

返回声道数量(1 为单声道,2 为立体声)

Wave_read.getsampwidth()

返回采样字节长度。

Wave_read.getframerate()

返回采样频率。

Wave_read.getnframes()

返回音频总帧数。

Wave_read.getcomptype()

返回压缩类型(只支持 'NONE' 类型)

Wave_read.getcompname()

getcomptype() 的通俗版本。使用 'not compressed' 代替 'NONE'

Wave_read.getparams()

返回一个 namedtuple() (nchannels, sampwidth, framerate, nframes, comptype, compname),与 get*() 方法的输出相同。

Wave_read.readframes(n)

读取并返回以 bytes 对象表示的最多 n 帧音频。

Wave_read.rewind()

重置文件指针至音频开头.

后面两个方法是为了和 aifc 保持兼容,实际不做任何事情。

Wave_read.getmarkers()

返回 None

Wave_read.getmark(id)

引发错误异常。

以下两个方法都使用指针,具体实现由其底层决定。

Wave_read.setpos(pos)

设置文件指针到指定位置。

Wave_read.tell()

返回当前文件指针位置。

Wave_write 对象

对于可查找的输出流,wave 头将自动更新以反映实际写入的帧数。 对于不可查找的流,当写入第一帧时 nframes 值必须准确。 获取准确的 nframes 值可以通过调用 setnframes()setparams() 并附带 close() 被调用之前将要写入的帧数,然后使用 writeframesraw() 来写入帧数据,或者通过调用 writeframes() 并附带所有要写入的帧。 在后一种情况下 writeframes() 将计算数据中的帧数并在写入帧数据之前相应地设置 nframes

open() 返回的 Wave_write 对象,有以下几种方法:

在 3.4 版更改: 添加了对不可搜索文件的支持。

Wave_write.close()

确保 nframes 是正确的,并在文件被 wave 打开时关闭它。 此方法会在对象收集时被调用。 如果输出流不可查找且 nframes 与实际写入的帧数不匹配时引发异常。

Wave_write.setnchannels(n)

设置声道数。

Wave_write.setsampwidth(n)

设置采样字节长度为 n

Wave_write.setframerate(n)

设置采样频率为 n

在 3.2 版更改: 对此方法的非整数输入会被舍入到最接近的整数。

Wave_write.setnframes(n)

设置总帧数为 n。 如果与之后实际写入的帧数不一致此值将会被更改( 如果输出流不可查找则此更改尝试将引发错误)。

Wave_write.setcomptype(type, name)

设置压缩格式。目前只支持 NONE 即无压缩格式。

Wave_write.setparams(tuple)

tuple 应该是 (nchannels, sampwidth, framerate, nframes, comptype, compname),每项的值应可用于 set*() 方法。设置所有形参。

Wave_write.tell()

返回当前文件指针,其指针含义和 Wave_read.tell() 以及 Wave_read.setpos() 是一致的。

Wave_write.writeframesraw(data)

写入音频数据但不更新 nframes

在 3.4 版更改: 现在可接受任意 bytes-like object。

Wave_write.writeframes(data)

写入音频帧并确保 nframes 是正确的。 如果输出流不可查找且在 data 被写入之后写入的总帧数与之前设定的has been written does not match the previously set value for nframes 值不匹配将会引发错误。

在 3.4 版更改: 现在可接受任意 bytes-like object。

注意在调用 writeframes()writeframesraw() 之后再设置任何格式参数是无效的,而且任何这样的尝试将引发 wave.Error

chunk —- 读取 IFF 分块数据

源代码: Lib/chunk.py


本模块提供了一个读取使用 EA IFF 85 分块的数据的接口chunks. 1 这种格式使用的场合有 Audio Interchange File Format (AIFF/AIFF-C) 和 Real Media File Format (RMFF) 等。 与它们密切相关的 WAVE 音频文件也可使用此模块来读取。

一个分块具有以下结构:

偏移 长度 目录
0 4 区块ID
4 4 大端字节顺序的块大小,不包括头
8 n 数据字节,其中 n 是前一字段中给出的大小
8 + n 0 或 1 如果 n 为奇数且使用块对齐,则需要填充字节

ID是一个4字节的字符串,用于标识块的类型。

大小字段(32 位的值,使用大端字节序编码)给出分块数据的大小,不包括 8 字节的标头。

使用由一个或更多分块组成的 IFF 类型文件。 此处定义的 Chunk 类的建议使用方式是在每个分块开始时实例化一个实例并从实例读取直到其末尾,在那之后可以再实例化新的实例。 到达文件末尾时,创建新实例将会失败并引发 EOFError 异常。

class chunk.Chunk(file, align=True, bigendian=True, inclheader=False)

代表一个分块的类。 file 参数预期为一个文件类对象。 特别地也允许该类的实例。 唯一必需的方法是 read()。 如果存在 seek()tell() 方法并且没有引发异常,它们也会被使用。 如果存在这些方法并且引发了异常,则它们不应改变目标对象。 如果可选参数 align 为真值,则分块应当以 2 字节边界对齐。 如果 align 为假值,则不使用对齐。 此参数默认为真值。 如果可选参数 bigendian 为假值,分块大小应当为小端序。 这对于 WAVE 音频文件是必须的。 此参数默认为真值。 如果可选参数 inclheader 为真值,则分块标头中给出的大小将包括标头的大小。 此参数默认为假值。

Chunk 对象支持下列方法:

  • getname()

    返回分块的名称(ID)。 这是分块的头 4 个字节。

  • getsize()

    返回分块的大小。

  • close()

    关闭并跳转到分块的末尾。 这不会关闭下层的文件。

close() 方法已被调用后其余方法将会引发 OSError。 在 Python 3.3 之前,它们曾会引发 IOError,现在这是 OSError 的一个别名。

  • isatty()

    返回 False

  • seek(pos, whence=0)

    设置分块的当前位置。 whence 参数为可选项并且默认为 0 (绝对文件定位);其他值还有 1 (相对当前位置查找) 和 2 (相对文件末尾查找)。 没有返回值。 如果下层文件不支持查找,则只允许向前查找。

  • tell()

    将当前位置返回到分块。

  • read(size=- 1)

    从分块读取至多 size 个字节(如果在获得 size 个字节之前已到达分块末尾则读取的字节会少于此数量)。 如果 size 参数为负值或被省略,则读取所有字节直到分块末尾。 当立即遇到分块末尾则返回空字节串对象。

  • skip()

    跳到分块末尾。此后对分块再次调用 read() 将返回 b''。 如果你对分块的内容不感兴趣,则应当调用此方法以使文件指向下一分块的开头。

colorsys —- 颜色系统间的转换

源代码: Lib/colorsys.py


colorsys 模块定义了计算机显示器所用的 RGB (Red Green Blue) 色彩空间与三种其他色彩坐标系统 YIQ, HLS (Hue Lightness Saturation) 和 HSV (Hue Saturation Value) 表示的颜色值之间的双向转换。 所有这些色彩空间的坐标都使用浮点数值来表示。 在 YIQ 空间中,Y 坐标取值为 0 和 1 之间,而 I 和 Q 坐标均可以为正数或负数。 在所有其他空间中,坐标取值均为 0 和 1 之间。

参见

有关色彩空间的更多信息可访问 https://poynton.ca/ColorFAQ.htmlhttps://www.cambridgeincolour.com/tutorials/color-spaces.htm。

colorsys 模块定义了如下函数:

colorsys.rgb_to_yiq(r, g, b)

把颜色从RGB值转为YIQ值。

colorsys.yiq_to_rgb(y, i, q)

把颜色从YIQ值转为RGB值。

colorsys.rgb_to_hls(r, g, b)

把颜色从RGB值转为HLS值。

colorsys.hls_to_rgb(h, l, s)

把颜色从HLS值转为RGB值。

colorsys.rgb_to_hsv(r, g, b)

把颜色从RGB值转为HSV值。

colorsys.hsv_to_rgb(h, s, v)

把颜色从HSV值转为RGB值。

示例:

>>> import colorsys
>>> colorsys.rgb_to_hsv(0.2, 0.4, 0.4)
(0.5, 0.5, 0.4)
>>> colorsys.hsv_to_rgb(0.5, 0.5, 0.4)
(0.2, 0.4, 0.4)

imghdr —- 推测图像类型

源代码 Lib/imghdr.py


imghdr 模块推测文件或字节流中的图像的类型。

imghdr 模块定义了以下类型:

imghdr.what(file, h=None)

测试包含在名为 file 的文件中的图像数据,并返回描述该图像类型的字符串。 如果提供了可选的 h,则 file 参数会被忽略并且 h 会被视为包含要测试的字节流。

在 3.6 版更改: 接受一个 path-like object。

接下来的图像类型是可识别的,返回值来自 what()

图像格式
‘rgb’ SGI 图像库文件
‘gif’ GIF 87a 和 89a 文件
‘pbm’ 便携式位图文件
‘pgm’ 便携式灰度图文件
‘ppm’ 便携式像素表文件
‘tiff’ TIFF 文件
‘rast’ Sun 光栅文件
‘xbm’ X 位图文件
‘jpeg’ JFIF 或 Exif 格式的 JPEG 数据
‘bmp’ BMP 文件
‘png’ 便携式网络图像
‘webp’ WebP 文件
‘exr’ OpenEXR 文件

3.5 新版功能: exrwebp 格式被添加。

你可以扩展此 imghdr 可以被追加的这个变量识别的文件格式的列表:

imghdr.tests

执行单个测试的函数列表。每个函数都有两个参数:字节流和类似开放文件的对象。当 what() 用字节流调用时,类文件对象将是 None

如果测试成功,这个测试函数应当返回一个描述图像类型的字符串,否则返回 None

示例:

>>> import imghdr
>>> imghdr.what('bass.gif')
'gif'

sndhdr —- 推测声音文件的类型

源代码 Lib/sndhdr.py


sndhdr 提供了企图猜测文件中的声音数据类型的功能函数。当这些函数可以推测出存储在文件中的声音数据的类型是,它们返回一个 collections.namedtuple(),包含了五种属性:(filetype, framerate, nchannels, nframes, sampwidth)。这些 type 的值表示数据的类型,会是以下字符串之一: 'aifc', 'aiff', 'au', 'hcom', 'sndr', 'sndt', 'voc', 'wav', '8svx', 'sb', 'ub', or 'ul'sampling_rate 可能是实际值或者当未知或者难以解码时的 0。类似的, channels 也会返回实际值或者在无法推测或者难以解码时返回 0frames 则是实际值或 -1。 元组的最后一项, bits_per_sample 将会为比特表示的 sample 大小或者 A-LAW 时为 'A', u-LAW 时为 'U'

sndhdr.what(filename)

使用 whathdr() 推测存储在 filename 文件中的声音数据的类型。如果成功,返回上述的命名元组,否则返回 None

在 3.5 版更改: 将结果从元组改为命名元组。

sndhdr.whathdr(filename)

基于文件头推测存储在文件中的声音数据类型。文件名由 filename 给出。这个函数在成功时返回上述命名元组,或者在失败时返回 None

在 3.5 版更改: 将结果从元组改为命名元组。

ossaudiodev —- 访问兼容OSS的音频设备

该模块允许您访问 OSS(开放式音响系统)音频接口。 OSS 可用于广泛的开源和商业 Unices,并且是 Linux 和最新版本的 FreeBSD 的标准音频接口。

在 3.3 版更改: 此模块中过去会引发 IOError 的操作现在将引发 OSError

参见

开放之声系统程序员手册

OSS C API 的官方文档

该模块定义了大量由OSS设备驱动提供的常量; 请参阅<sys/soundcard.h> Linux 或 FreeBSD 上的列表。

ossaudiodev defines the following variables and functions:

exception ossaudiodev.OSSAudioError

This exception is raised on certain errors. The argument is a string describing what went wrong.

(If ossaudiodev receives an error from a system call such as open(), write(), or ioctl(), it raises OSError. Errors detected directly by ossaudiodev result in OSSAudioError.)

(For backwards compatibility, the exception class is also available as ossaudiodev.error.)

ossaudiodev.open(mode)

ossaudiodev.open(device, mode)

Open an audio device and return an OSS audio device object. This object supports many file-like methods, such as read(), write(), and fileno() (although there are subtle differences between conventional Unix read/write semantics and those of OSS audio devices). It also supports a number of audio-specific methods; see below for the complete list of methods.

device is the audio device filename to use. If it is not specified, this module first looks in the environment variable AUDIODEV for a device to use. If not found, it falls back to /dev/dsp.

mode is one of 'r' for read-only (record) access, 'w' for write-only (playback) access and 'rw' for both. Since many sound cards only allow one process to have the recorder or player open at a time, it is a good idea to open the device only for the activity needed. Further, some sound cards are half-duplex: they can be opened for reading or writing, but not both at once.

Note the unusual calling syntax: the first argument is optional, and the second is required. This is a historical artifact for compatibility with the older linuxaudiodev module which ossaudiodev supersedes.

ossaudiodev.openmixer([device])

Open a mixer device and return an OSS mixer device object. device is the mixer device filename to use. If it is not specified, this module first looks in the environment variable MIXERDEV for a device to use. If not found, it falls back to /dev/mixer.

Audio Device Objects

Before you can write to or read from an audio device, you must call three methods in the correct order:

  1. setfmt() to set the output format
  2. channels() to set the number of channels
  3. speed() to set the sample rate

Alternately, you can use the setparameters() method to set all three audio parameters at once. This is more convenient, but may not be as flexible in all cases.

The audio device objects returned by open() define the following methods and (read-only) attributes:

oss_audio_device.close()

Explicitly close the audio device. When you are done writing to or reading from an audio device, you should explicitly close it. A closed device cannot be used again.

oss_audio_device.fileno()

Return the file descriptor associated with the device.

oss_audio_device.read(size)

Read size bytes from the audio input and return them as a Python string. Unlike most Unix device drivers, OSS audio devices in blocking mode (the default) will block read() until the entire requested amount of data is available.

oss_audio_device.write(data)

Write a bytes-like object data to the audio device and return the number of bytes written. If the audio device is in blocking mode (the default), the entire data is always written (again, this is different from usual Unix device semantics). If the device is in non-blocking mode, some data may not be written—-see writeall().

在 3.5 版更改: 现在接受可写的 字节类对象。

oss_audio_device.writeall(data)

Write a bytes-like object data to the audio device: waits until the audio device is able to accept data, writes as much data as it will accept, and repeats until data has been completely written. If the device is in blocking mode (the default), this has the same effect as write(); writeall() is only useful in non-blocking mode. Has no return value, since the amount of data written is always equal to the amount of data supplied.

在 3.5 版更改: 现在接受可写的 字节类对象。

在 3.2 版更改: Audio device objects also support the context management protocol, i.e. they can be used in a with statement.

The following methods each map to exactly one ioctl() system call. The correspondence is obvious: for example, setfmt() corresponds to the SNDCTL_DSP_SETFMT ioctl, and sync() to SNDCTL_DSP_SYNC (this can be useful when consulting the OSS documentation). If the underlying ioctl() fails, they all raise OSError.

oss_audio_device.nonblock()

Put the device into non-blocking mode. Once in non-blocking mode, there is no way to return it to blocking mode.

oss_audio_device.getfmts()

Return a bitmask of the audio output formats supported by the soundcard. Some of the formats supported by OSS are:

格式 描述
AFMT_MU_LAW a logarithmic encoding (used by Sun .au files and /dev/audio)
AFMT_A_LAW a logarithmic encoding
AFMT_IMA_ADPCM a 4:1 compressed format defined by the Interactive Multimedia Association
AFMT_U8 Unsigned, 8-bit audio
AFMT_S16_LE Signed, 16-bit audio, little-endian byte order (as used by Intel processors)
AFMT_S16_BE Signed, 16-bit audio, big-endian byte order (as used by 68k, PowerPC, Sparc)
AFMT_S8 Signed, 8 bit audio
AFMT_U16_LE Unsigned, 16-bit little-endian audio
AFMT_U16_BE Unsigned, 16-bit big-endian audio

Consult the OSS documentation for a full list of audio formats, and note that most devices support only a subset of these formats. Some older devices only support AFMT_U8; the most common format used today is AFMT_S16_LE.

oss_audio_device.setfmt(format)

Try to set the current audio format to format-—see getfmts() for a list. Returns the audio format that the device was set to, which may not be the requested format. May also be used to return the current audio format—-do this by passing an “audio format” of AFMT_QUERY.

oss_audio_device.channels(nchannels)

Set the number of output channels to nchannels. A value of 1 indicates monophonic sound, 2 stereophonic. Some devices may have more than 2 channels, and some high-end devices may not support mono. Returns the number of channels the device was set to.

oss_audio_device.speed(samplerate)

Try to set the audio sampling rate to samplerate samples per second. Returns the rate actually set. Most sound devices don’t support arbitrary sampling rates. Common rates are:

采样率 描述
8000 /dev/audio 的默认采样率
11025 语音录音
22050
44100 CD品质的音频(16位采样和2通道)
96000 DVD品质的音频(24位采样)

oss_audio_device.sync()

Wait until the sound device has played every byte in its buffer. (This happens implicitly when the device is closed.) The OSS documentation recommends closing and re-opening the device rather than using sync().

oss_audio_device.reset()

Immediately stop playing or recording and return the device to a state where it can accept commands. The OSS documentation recommends closing and re-opening the device after calling reset().

oss_audio_device.post()

Tell the driver that there is likely to be a pause in the output, making it possible for the device to handle the pause more intelligently. You might use this after playing a spot sound effect, before waiting for user input, or before doing disk I/O.

The following convenience methods combine several ioctls, or one ioctl and some simple calculations.

oss_audio_device.setparameters(format, nchannels, samplerate[, strict=False])

Set the key audio sampling parameters—-sample format, number of channels, and sampling rate—-in one method call. format, nchannels, and samplerate should be as specified in the setfmt(), channels(), and speed() methods. If strict is true, setparameters() checks to see if each parameter was actually set to the requested value, and raises OSSAudioError if not. Returns a tuple (format, nchannels, samplerate) indicating the parameter values that were actually set by the device driver (i.e., the same as the return values of setfmt(), channels(), and speed()).

For example,

(fmt, channels, rate) = dsp.setparameters(fmt, channels, rate)

is equivalent to

fmt = dsp.setfmt(fmt)
channels = dsp.channels(channels)
rate = dsp.rate(rate)

oss_audio_device.bufsize()

Returns the size of the hardware buffer, in samples.

oss_audio_device.obufcount()

Returns the number of samples that are in the hardware buffer yet to be played.

oss_audio_device.obuffree()

Returns the number of samples that could be queued into the hardware buffer to be played without blocking.

Audio device objects also support several read-only attributes:

oss_audio_device.closed

Boolean indicating whether the device has been closed.

oss_audio_device.name

String containing the name of the device file.

oss_audio_device.mode

The I/O mode for the file, either "r", "rw", or "w".

Mixer Device Objects

The mixer object provides two file-like methods:

oss_mixer_device.close()

This method closes the open mixer device file. Any further attempts to use the mixer after this file is closed will raise an OSError.

oss_mixer_device.fileno()

Returns the file handle number of the open mixer device file.

在 3.2 版更改: Mixer objects also support the context management protocol.

The remaining methods are specific to audio mixing:

oss_mixer_device.controls()

This method returns a bitmask specifying the available mixer controls (“Control” being a specific mixable “channel”, such as SOUND_MIXER_PCM or SOUND_MIXER_SYNTH). This bitmask indicates a subset of all available mixer controls—-the SOUND_MIXER_* constants defined at module level. To determine if, for example, the current mixer object supports a PCM mixer, use the following Python code:

mixer=ossaudiodev.openmixer()
if mixer.controls() & (1 << ossaudiodev.SOUND_MIXER_PCM):
    # PCM is supported
    ... code ...

For most purposes, the SOUND_MIXER_VOLUME (master volume) and SOUND_MIXER_PCM controls should suffice—-but code that uses the mixer should be flexible when it comes to choosing mixer controls. On the Gravis Ultrasound, for example, SOUND_MIXER_VOLUME does not exist.

oss_mixer_device.stereocontrols()

Returns a bitmask indicating stereo mixer controls. If a bit is set, the corresponding control is stereo; if it is unset, the control is either monophonic or not supported by the mixer (use in combination with controls() to determine which).

See the code example for the controls() function for an example of getting data from a bitmask.

oss_mixer_device.reccontrols()

Returns a bitmask specifying the mixer controls that may be used to record. See the code example for controls() for an example of reading from a bitmask.

oss_mixer_device.get(control)

Returns the volume of a given mixer control. The returned volume is a 2-tuple (left_volume,right_volume). Volumes are specified as numbers from 0 (silent) to 100 (full volume). If the control is monophonic, a 2-tuple is still returned, but both volumes are the same.

Raises OSSAudioError if an invalid control is specified, or OSError if an unsupported control is specified.

oss_mixer_device.set(control, (left, right))

Sets the volume for a given mixer control to (left,right). left and right must be ints and between 0 (silent) and 100 (full volume). On success, the new volume is returned as a 2-tuple. Note that this may not be exactly the same as the volume specified, because of the limited resolution of some soundcard’s mixers.

Raises OSSAudioError if an invalid mixer control was specified, or if the specified volumes were out-of-range.

oss_mixer_device.get_recsrc()

This method returns a bitmask indicating which control(s) are currently being used as a recording source.

oss_mixer_device.set_recsrc(bitmask)

Call this function to specify a recording source. Returns a bitmask indicating the new recording source (or sources) if successful; raises OSError if an invalid source was specified. To set the current recording source to the microphone input:

mixer.setrecsrc (1 << ossaudiodev.SOUND_MIXER_MIC)

国际化

本章中描述的模块列表是:

  • gettext —- 多语种国际化服务
    • GNU gettext API
    • 基于类的 API
      • NullTranslations
      • GNUTranslations
      • Solaris 消息编目支持
      • 编目构造器
    • 国际化 (I18N) 你的程序和模块
      • 本地化你的模块
      • 本地化你的应用程序
      • 即时更改语言
      • 延迟翻译
  • locale —- 国际化服务
    • Background, details, hints, tips and caveats
    • For extension writers and programs that embed Python
    • Access to message catalogs

gettext —- 多语种国际化服务

源代码: Lib/gettext.py


gettext 模块为 Python 模块和应用程序提供国际化 (Internationalization, I18N) 和本地化 (Localization, L10N) 服务。它同时支持 GNU gettext 消息编目 API 和更高级的、基于类的 API,后者可能更适合于 Python 文件。下方描述的接口允许用户使用一种自然语言编写模块和应用程序消息,并提供翻译后的消息编目,以便在不同的自然语言下运行。

同时还给出一些本地化 Python 模块及应用程序的小技巧。

GNU gettext API

模块 gettext 定义了下列 API,这与 gettext API 类似。如果你使用该 API,将会对整个应用程序产生全局的影响。如果你的应用程序支持多语种,而语言选择取决于用户的语言环境设置,这通常正是你所想要的。而如果你正在本地化某个 Python 模块,或者你的应用程序需要在运行时切换语言,相反你或许想用基于类的API。

gettext.bindtextdomain(domain, localedir=None)

domain 绑定到本地目录 localedir。 更具体地来说,模块 gettext 将使用路径 (在 Unix 系统中): `localedir/language/LC_MESSAGES/domain.mo查找二进制.mo文件,此处对应地查找 *language* 的位置是环境变量LANGUAGE,LC_ALL,LC_MESSAGESLANG` 中。

如果遗漏了 localedir 或者设置为 None,那么将返回当前 domain 所绑定的值

gettext.bind_textdomain_codeset(domain, codeset=None)

domain 绑定到 codeset,修改 lgettext(), ldgettext(), lngettext()ldngettext() 函数返回的字节串的字符编码。如果省略了 codeset,则返回当前绑定的编码集。

Deprecated since version 3.8, removed in version 3.10.

gettext.textdomain(domain=None)

修改或查询当前的全局域。如果 domainNone,则返回当前的全局域,不为 None 则将全局域设置为 domain,并返回它。

gettext.gettext(message)

返回 message 的本地化翻译,依据包括当前的全局域、语言和语言环境目录。本函数在本地命名空间中通常有别名 _() (参考下面的示例)。

gettext.dgettext(domain, message)

gettext() 类似,但在指定的 domain 中查找 message。

gettext.ngettext(singular, plural, n)

gettext() 类似,但考虑了复数形式。如果找到了翻译,则将 n 代入复数公式,然后返回得出的消息(某些语言具有两种以上的复数形式)。如果未找到翻译,则 n 为 1 时返回 singular,为其他数时返回 plural

复数公式取自编目头文件。它是 C 或 Python 表达式,有一个自变量 n,该表达式计算的是所需复数形式在编目中的索引号。关于在 .po 文件中使用的确切语法和各种语言的公式。

gettext.dngettext(domain, singular, plural, n)

ngettext() 类似,但在指定的 domain 中查找 message。

gettext.pgettext(context, message)

gettext.dpgettext(domain, context, message)

gettext.npgettext(context, singular, plural, n)

gettext.dnpgettext(domain, context, singular, plural, n)

与前缀中没有 p 的相应函数类似(即 gettext(), dgettext(), ngettext(), dngettext() ),但是仅翻译给定的 message context

3.8 新版功能.

gettext.lgettext(message)

gettext.ldgettext(domain, message)

gettext.lngettext(singular, plural, n)

gettext.ldngettext(domain, singular, plural, n)

与前缀中没有 l 的相应函数等效( gettext(), dgettext(), ngettext()dngettext() ),但是如果没有用 bind_textdomain_codeset() 显式设置其他编码,则返回的翻译将以首选系统编码来编码字节串。

警告

在 Python 3 中应避免使用这些函数,因为它们返回的是编码后的字节串。最好使用返回 Unicode 字符串的其他方法,因为大多数 Python 应用程序都希望将人类可读的文本作为字符串而不是字节来处理。此外,如果翻译后的字符串存在编码问题,则可能会意外出现与 Unicode 相关的异常。

Deprecated since version 3.8, removed in version 3.10.

注意,GNU gettext 还定义了 dcgettext() 方法,但它被认为不实用,因此目前没有实现它。

这是该 API 的典型用法示例:

import gettext
gettext.bindtextdomain('myapplication', '/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))

基于类的 API

与 GNU gettext API 相比,gettext 模块的基于类的 API 提供了更多的灵活性和更强的便利性。这是本地化 Python 应用程序和模块的推荐方法。gettext 定义了一个 GNUTranslations 类,该类实现了 GNU .mo 格式文件的解析,并且具有用于返回字符串的方法。本类的实例也可以将自身作为函数 _() 安装到内建命名空间中。

gettext.find(domain, localedir=None, languages=None, all=False)

本函数实现了标准的 .mo 文件搜索算法。它接受一个 domain*,它与 textdomain() 接受的域相同。可选参数 *localedirbindtextdomain() 中的相同。可选参数 languages 是多条字符串的列表,其中每条字符串都是一种语言代码。

如果没有传入 localedir,则使用默认的系统语言环境目录。如果没有传入 *languages,则搜索以下环境变量:LANGUAGELC_ALLLC_MESSAGESLANG。从这些变量返回的第一个非空值将用作 *languages 变量。环境变量应包含一个语言列表,由冒号分隔,该列表会被按冒号拆分,以产生所需的语言代码字符串列表。

find() 将扩展并规范化 language,然后遍历它们,搜索由这些组件构建的现有文件:

*localedir*/*language*/LC_MESSAGES/*domain*.mo

find() 返回找到类似的第一个文件名。如果找不到这样的文件,则返回 None。如果传入了 all,它将返回一个列表,包含所有文件名,并按它们在语言列表或环境变量中出现的顺序排列。

gettext.translation(domain, localedir=None, languages=None, class_=None, fallback=False, codeset=None)

根据 domainlocaledirlanguages,返回 *Translations 实例,首先应将前述参数传入 find() 以获取关联的 .mo 文件路径的列表。名字与 .mo 文件名相同的实例将被缓存。如果传入 class_,它将是实际被实例化的类,否则实例化 GNUTranslations。类的构造函数必须只接受一个 文件对象 参数。如果传入 codeset,那么在 lgettext()lngettext() 方法中,对翻译后的字符串进行编码的字符集将被改变。

如果找到多个文件,后找到的文件将用作先前文件的替补。为了设置替补,将使用 copy.copy() 从缓存中克隆每个 translation 对象。实际的实例数据仍在缓存中共享。

如果 .mo 文件未找到,且 fallback 为 false(默认值),则本函数引发 OSError 异常,如果 fallback 为 true,则返回一个 NullTranslations 实例。

在 3.3 版更改: 曾经是 IOError 被引发而不是 OSError

Deprecated since version 3.8, removed in version 3.10: codeset 参数。

gettext.install(domain, localedir=None, codeset=None, names=None)

根据传入 translation() 函数的 domainlocaledircodeset,在 Python 内建命名空间中安装 _() 函数。

names 参数的信息请参阅 translation 对象的 install() 方法的描述。

如下所示,通常将字符串包括在 _() 函数的调用中,以标记应用程序中待翻译的字符串,就像这样:

print(_('This string will be translated.'))

为了方便,一般将 _() 函数安装在 Python 内建命名空间中,以便在应用程序的所有模块中轻松访问它。

Deprecated since version 3.8, removed in version 3.10: codeset 参数。

NullTranslations

translation 类实际实现的是,将原始源文件消息字符串转换为已翻译的消息字符串。所有 translation 类使用的基类为 NullTranslations,它提供了基本的接口,可用于编写自己定制的 translation 类。以下是 NullTranslations 的方法:

class gettext.NullTranslations(fp=None)

接受一个可选参数 文件对象 fp*,该参数会被基类忽略。初始化由派生类设置的 “protected” (受保护的)实例变量 *_info_charset*,与 *_fallback 类似,但它是通过 add_fallback() 来设置的。如果 fp 不为 None,就会调用 self._parse(fp)

  • _parse(fp)

    在基类中没有操作,本方法接受文件对象 fp,从该文件读取数据,用来初始化消息编目。如果你手头的消息编目文件的格式不受支持,则应重写本方法来解析你的格式。

  • add_fallback(fallback)

    添加 fallback 为当前 translation 对象的替补对象。如果 translation 对象无法为指定消息提供翻译,则应向替补查询。

  • gettext(message)

    如果设置了替补,则转发 gettext() 给替补。否则返回 message。在派生类中被重写。

  • ngettext(singular, plural, n)

    如果设置了替补,则转发 ngettext() 给替补。否则,n 为 1 时返回 singular,为其他时返回 plural。在派生类中被重写。

  • pgettext(context, message)

    如果设置了替补,则转发 pgettext() 给替补。否则返回已翻译的消息。在派生类中被重写。

    3.8 新版功能.

  • npgettext(context, singular, plural, n)

    如果设置了替补,则转发 npgettext() 给替补。否则返回已翻译的消息。在派生类中被重写。

    3.8 新版功能.

  • lgettext(message)

  • lngettext(singular, plural, n)

    gettext()ngettext() 等效,但是如果没有用 set_output_charset() 显式设置编码,则返回的翻译将以首选系统编码来编码字节串。在派生类中被重写。

    警告

    应避免在 Python 3 中使用这些方法。

    Deprecated since version 3.8, removed in version 3.10.

  • info()

    返回 “protected”(受保护的) _info 变量,它是一个字典,包含在消息编目文件中找到的元数据。

  • charset()

    返回消息编目文件的编码。

  • output_charset()

    返回由 lgettext()lngettext() 翻译出的消息的编码。

    Deprecated since version 3.8, removed in version 3.10.

  • set_output_charset(charset)

    更改翻译出的消息的编码。

    Deprecated since version 3.8, removed in version 3.10.

  • install(names=None)

    本方法将 gettext() 安装至内建命名空间,并绑定为 _

    如果传入 names 参数,该参数必须是一个序列,包含除 _() 外其他要安装在内建命名空间中的函数的名称。支持的名称有 'gettext', 'ngettext', 'pgettext', 'npgettext', 'lgettext''lngettext'

    注意,这仅仅是使 _() 函数在应用程序中生效的一种方法,尽管也是最方便的方法。由于它会影响整个应用程序全局,特别是内建命名空间,因此已经本地化的模块不应该安装 _(),而是应该用下列代码使 _() 在各自模块中生效:

    import gettext
    t = gettext.translation('mymodule', ...)
    _ = t.gettext

    这只将 _() 放在其模块的全局命名空间中,所以只影响其模块内的调用。

    在 3.8 版更改: 添加了 'pgettext''npgettext'

GNUTranslations

gettext 模块提供了一个派生自 NullTranslations 的其他类:GNUTranslations。该类重写了 _parse(),同时能以大端序和小端序格式读取 GNU gettext 格式的 .mo 文件。

GNUTranslations 从翻译编目中解析出可选的元数据。GNU gettext 约定,将元数据包括在空字符串的翻译中。该元数据采用 RFC 822 样式的 key: value 键值对,且应该包含 Project-Id-Version 键。如果找到 Content-Type 键,那么将用 charset 属性去初始化 “protected”(受保护的) _charset 实例变量,而该变量在未找到键的情况下默认为 None。如果指定了字符编码,那么从编目中读取的所有消息 ID 和消息字符串都将使用此编码转换为 Unicode,若未指定编码,则假定编码为 ASCII。

由于消息 ID 也是作为 Unicode 字符串读取的,因此所有 *gettext() 方法都假定消息 ID 为 Unicode 字符串,而不是字节串。

整个键/值对集合将被放入一个字典,并设置为 “protected”(受保护的) _info 实例变量。

如果 .mo 文件的魔法值 (magic number) 无效,或遇到意外的主版本号,或在读取文件时发生其他问题,则实例化 GNUTranslations 类会引发 OSError

class gettext.GNUTranslations

下列方法是根据基类实现重写的:

  • gettext(message)

    在编目中查找 message ID,并以 Unicode 字符串形式返回相应的消息字符串。如果在编目中没有 message ID 条目,且配置了替补,则查找请求将被转发到替补的 gettext() 方法。否则,返回 message ID。

  • ngettext(singular, plural, n)

    查找消息 ID 的复数形式。singular 用作消息 ID,用于在编目中查找,同时 n 用于确定使用哪种复数形式。返回的消息字符串是 Unicode 字符串。

    如果在编目中没有找到消息 ID,且配置了替补,则查找请求将被转发到替补的 ngettext() 方法。否则,当 n 为 1 时返回 singular,其他情况返回 plural

    例如:

    n = len(os.listdir('.'))
    cat = GNUTranslations(somefile)
    message = cat.ngettext(
        'There is %(num)d file in this directory',
        'There are %(num)d files in this directory',
        n) % {'num': n}
  • pgettext(context, message)

    在编目中查找 contextmessage ID,并以 Unicode 字符串形式返回相应的消息字符串。如果在编目中没有 message ID 和 context 条目,且配置了替补,则查找请求将被转发到替补的 pgettext() 方法。否则,返回 message ID。

    3.8 新版功能.

  • npgettext(context, singular, plural, n)

    查找消息 ID 的复数形式。singular 用作消息 ID,用于在编目中查找,同时 n 用于确定使用哪种复数形式。

    如果在编目中没有找到 context 对应的消息 ID,且配置了替补,则查找请求将被转发到替补的 npgettext() 方法。否则,当 n 为 1 时返回 singular,其他情况返回 plural

    3.8 新版功能.

  • lgettext(message)

  • lngettext(singular, plural, n)

    gettext()ngettext() 等效,但是如果没有用 set_output_charset() 显式设置编码,则返回的翻译将以首选系统编码来编码字节串。

    警告

    应避免在 Python 3 中使用这些方法。

    Deprecated since version 3.8, removed in version 3.10.

Solaris 消息编目支持

Solaris 操作系统定义了自己的二进制 .mo 文件格式,但由于找不到该格式的文档,因此目前不支持该格式。

编目构造器

GNOME 用的 gettext 模块是 James Henstridge 写的版本,但该版本的 API 略有不同。它文档中的用法是:

import gettext
cat = gettext.Catalog(domain, localedir)
_ = cat.gettext
print(_('hello world'))

为了与本模块的旧版本兼容,Catalog() 函数是上述 translation() 函数的别名。

本模块与 Henstridge 的模块有一个区别:他的编目对象支持通过映射 API 进行访问,但是该特性似乎从未使用过,因此目前不支持该特性。

国际化 (I18N) 你的程序和模块

国际化 (I18N) 是指使程序可切换多种语言的操作。本地化 (L10N) 是指程序的适配能力,一旦程序被国际化,就能适配当地的语言和文化习惯。为了向 Python 程序提供不同语言的消息,需要执行以下步骤:

  1. 准备程序或模块,将可翻译的字符串特别标记起来
  2. 在已标记的文件上运行一套工具,用来生成原始消息编目
  3. 创建消息编目的不同语言的翻译
  4. 使用 gettext 模块,以便正确翻译消息字符串

为了准备代码以达成 I18N,需要巡视文件中的所有字符串。所有要翻译的字符串都应包括在 _('...') 内,以此打上标记——也就是调用 _() 函数。例如:

filename = 'mylog.txt'
message = _('writing a log message')
with open(filename, 'w') as fp:
    fp.write(message)

在这个例子中,字符串 'writing a log message' 被标记为待翻译,而字符串 'mylog.txt''w' 没有被标记。

有一些工具可以将待翻译的字符串提取出来。原版的 GNU gettext 仅支持 C 或 C++ 源代码,但其扩展版 xgettext 可以扫描多种语言的代码(包括 Python),来找出标记为可翻译的字符串。Babel 是一个 Python 国际化库,其中包含一个 pybabel 脚本,用于提取并编译消息编目。François Pinard 写的称为 xpot 的程序也能完成类似的工作,可从他的 po-utils 软件包 中获取。

(Python 还包括了这些程序的纯 Python 版本,称为 pygettext.pymsgfmt.py,某些 Python 发行版已经安装了它们。pygettext.py 类似于 xgettext,但只能理解 Python 源代码,无法处理诸如 C 或 C++ 的其他编程语言。pygettext.py 支持的命令行界面类似于 xgettext,查看其详细用法请运行 pygettext.py --helpmsgfmt.py 与 GNU msgfmt 是二进制兼容的。有了这两个程序,可以不需要 GNU gettext 包来国际化 Python 应用程序。)

xgettextpygettext 或类似工具生成的 .po 文件就是消息编目。它们是结构化的人类可读文件,包含源代码中所有被标记的字符串,以及这些字符串的翻译的占位符。

然后把这些 .po 文件的副本交给各个人工译者,他们为所支持的每种自然语言编写翻译。译者以 <语言名称>.po 文件的形式发送回翻译完的某个语言的版本,将该文件用 msgfmt 程序编译为机器可读的 .mo 二进制编目文件。gettext 模块使用 .mo 文件在运行时进行实际的翻译处理。

如何在代码中使用 gettext 模块取决于国际化单个模块还是整个应用程序。接下来的两节将讨论每种情况。

本地化你的模块

如果要本地化模块,则切忌进行全局性的更改,如更改内建命名空间。不应使用 GNU gettext API,而应使用基于类的 API。

假设你的模块叫做 “spam”,并且该模块的各种自然语言翻译 .mo 文件存放于 /usr/share/locale,为 GNU gettext 格式。以下内容应放在模块顶部:

import gettext
t = gettext.translation('spam', '/usr/share/locale')
_ = t.gettext

本地化你的应用程序

如果正在本地化应用程序,可以将 _() 函数全局安装到内建命名空间中,通常在应用程序的主文件中安装。这将使某个应用程序的所有文件都能使用 _('...'),而不必在每个文件中显式安装它。

最简单的情况,就只需将以下代码添加到应用程序的主程序文件中:

import gettext
gettext.install('myapplication')

如果需要设置语言环境目录,可以将其传递给 install() 函数:

import gettext
gettext.install('myapplication', '/usr/share/locale')

即时更改语言

如果程序需要同时支持多种语言,则可能需要创建多个翻译实例,然后在它们之间进行显式切换,如下所示:

import gettext
lang1 = gettext.translation('myapplication', languages=['en'])
lang2 = gettext.translation('myapplication', languages=['fr'])
lang3 = gettext.translation('myapplication', languages=['de'])
# start by using language1
lang1.install()
# ... time goes by, user selects language 2
lang2.install()
# ... more time goes by, user selects language 3
lang3.install()

延迟翻译

在大多数代码中,字符串会在编写位置进行翻译。但偶尔需要将字符串标记为待翻译,实际翻译却推迟到后面。一个典型的例子是:

animals = ['mollusk',
           'albatross',
           'rat',
           'penguin',
           'python', ]
# ...
for a in animals:
    print(a)

此处希望将 animals 列表中的字符串标记为可翻译,但不希望在打印之前对它们进行翻译。

这是处理该情况的一种方式:

def _(message): return message
animals = [_('mollusk'),
           _('albatross'),
           _('rat'),
           _('penguin'),
           _('python'), ]
del _
# ...
for a in animals:
    print(_(a))

该方法之所以可行,是因为 _() 的虚定义只是简单地返回了原本的字符串。并且该虚定义将临时覆盖内建命名空间中 _() 的定义(直到 del 命令)。即使先前在本地命名空间中已经有了 _() 的定义也请注意。

注意,第二次使用 _() 不会认为 “a” 可以传递给 gettext 程序去翻译,因为该参数不是字符串文字。

解决该问题的另一种方法是下面这个例子:

def N_(message): return message
animals = [N_('mollusk'),
           N_('albatross'),
           N_('rat'),
           N_('penguin'),
           N_('python'), ]
# ...
for a in animals:
    print(_(a))

这种情况下标记可翻译的字符串使用的是函数 N_(),该函数不会与 _() 的任何定义冲突。但是,需要教会消息提取程序去寻找用 N_() 标记的可翻译字符串。xgettext, pygettext, pybabel extractxpot 都支持此功能,使用 -k 命令行开关即可。这里选择 N_() 为名称完全是任意的,它也能轻易改为 MarkThisStringForTranslation()

locale —- 国际化服务

源代码: Lib/locale.py


The locale module opens access to the POSIX locale database and functionality. The POSIX locale mechanism allows programmers to deal with certain cultural issues in an application, without requiring the programmer to know all the specifics of each country where the software is executed.

The locale module is implemented on top of the _locale module, which in turn uses an ANSI C locale implementation if available.

The locale module defines the following exception and functions:

exception locale.Error

Exception raised when the locale passed to setlocale() is not recognized.

locale.setlocale(category, locale=None)

If locale is given and not None, setlocale() modifies the locale setting for the category. The available categories are listed in the data description below. locale may be a string, or an iterable of two strings (language code and encoding). If it’s an iterable, it’s converted to a locale name using the locale aliasing engine. An empty string specifies the user’s default settings. If the modification of the locale fails, the exception Error is raised. If successful, the new locale setting is returned.

If locale is omitted or None, the current setting for category is returned.

setlocale() is not thread-safe on most systems. Applications typically start with a call of

import localelocale.setlocale(locale.LC_ALL, '')

This sets the locale for all categories to the user’s default setting (typically specified in the LANG environment variable). If the locale is not changed thereafter, using multithreading should not cause problems.

locale.localeconv()

以字典的形式返回本地约定的数据库。此字典具有以下字符串作为键:

类别 含意
LC_NUMERIC ‘decimal_point’ 小数点字符。
‘grouping’ Sequence of numbers specifying which relative positions the ‘thousands_sep’ is expected. If the sequence is terminated with CHAR_MAX, no further grouping is performed. If the sequence terminates with a 0, the last group size is repeatedly used.
‘thousands_sep’ 组之间使用的字符。
LC_MONETARY ‘int_curr_symbol’ 国际货币符号。
‘currency_symbol’ 当地货币符号。
‘p_cs_precedes/n_cs_precedes’ 货币符号是否在值之前(对于正值或负值)。
‘p_sep_by_space/n_sep_by_space’ 货币符号是否通过空格与值分隔(对于正值或负值)。
‘mon_decimal_point’ 用于货币金额的小数点。
‘frac_digits’ 货币值的本地格式中使用的小数位数。
‘int_frac_digits’ 货币价值的国际格式中使用的小数位数。
‘mon_thousands_sep’ 用于货币值的组分隔符。
‘mon_grouping’ 相当于 ‘grouping’ ,用于货币价值。
‘positive_sign’ 用于标注正货币价值的符号。
‘negative_sign’ 用于注释负货币价值的符号。
‘p_sign_posn/n_sign_posn’ 符号的位置(对于正值或负值),见下文。

可以将所有数值设置为 CHAR_MAX ,以指示此语言环境中未指定任何值。

下面给出了 'p_sign_posn''n_sign_posn' 的可能值。

说明
0 被括号括起来的货币和金额。
1 该标志应位于值和货币符号之前。
2 该标志应位于值和货币符号之后。
3 标志应该紧跟在值之前。
4 标志应该紧跟值项。
CHAR_MAX 此语言环境中未指定任何内容。

The function sets temporarily the LC_CTYPE locale to the LC_NUMERIC locale or the LC_MONETARY locale if locales are different and numeric or monetary strings are non-ASCII. This temporary change affects other threads.

在 3.7 版更改: The function now sets temporarily the LC_CTYPE locale to the LC_NUMERIC locale in some cases.

locale.nl_langinfo(option)

Return some locale-specific information as a string. This function is not available on all systems, and the set of possible options might also vary across platforms. The possible argument values are numbers, for which symbolic constants are available in the locale module.

The nl_langinfo() function accepts one of the following keys. Most descriptions are taken from the corresponding description in the GNU C library.

  • locale.CODESET

    Get a string with the name of the character encoding used in the selected locale.

  • locale.D_T_FMT

    Get a string that can be used as a format string for time.strftime() to represent date and time in a locale-specific way.

  • locale.D_FMT

    Get a string that can be used as a format string for time.strftime() to represent a date in a locale-specific way.

  • locale.T_FMT

    Get a string that can be used as a format string for time.strftime() to represent a time in a locale-specific way.

  • locale.T_FMT_AMPM

    Get a format string for time.strftime() to represent time in the am/pm format.

  • DAY_1 ... DAY_7

    Get the name of the n-th day of the week.

    注解

    This follows the US convention of DAY_1 being Sunday, not the international convention (ISO 8601) that Monday is the first day of the week.

  • ABDAY_1 ... ABDAY_7

    Get the abbreviated name of the n-th day of the week.

  • MON_1 ... MON_12

    Get the name of the n-th month.

  • ABMON_1 ... ABMON_12

    Get the abbreviated name of the n-th month.

  • locale.RADIXCHAR

    Get the radix character (decimal dot, decimal comma, etc.).

  • locale.THOUSEP

    Get the separator character for thousands (groups of three digits).

  • locale.YESEXPR

    Get a regular expression that can be used with the regex function to recognize a positive response to a yes/no question.

    注解

    The expression is in the syntax suitable for the regex() function from the C library, which might differ from the syntax used in re.

  • locale.NOEXPR

    Get a regular expression that can be used with the regex(3) function to recognize a negative response to a yes/no question.

  • locale.CRNCYSTR

    Get the currency symbol, preceded by “-“ if the symbol should appear before the value, “+” if the symbol should appear after the value, or “.” if the symbol should replace the radix character.

  • locale.ERA

    Get a string that represents the era used in the current locale.

    Most locales do not define this value. An example of a locale which does define this value is the Japanese one. In Japan, the traditional representation of dates includes the name of the era corresponding to the then-emperor’s reign.

    Normally it should not be necessary to use this value directly. Specifying the E modifier in their format strings causes the time.strftime() function to use this information. The format of the returned string is not specified, and therefore you should not assume knowledge of it on different systems.

  • locale.ERA_D_T_FMT

    Get a format string for time.strftime() to represent date and time in a locale-specific era-based way.

  • locale.ERA_D_FMT

    Get a format string for time.strftime() to represent a date in a locale-specific era-based way.

  • locale.ERA_T_FMT

    Get a format string for time.strftime() to represent a time in a locale-specific era-based way.

  • locale.ALT_DIGITS

    Get a representation of up to 100 values used to represent the values 0 to 99.

locale.getdefaultlocale([envvars])

Tries to determine the default locale settings and returns them as a tuple of the form (language code, encoding).

According to POSIX, a program which has not called setlocale(LC_ALL, '') runs using the portable 'C' locale. Calling setlocale(LC_ALL, '') lets it use the default locale as defined by the LANG variable. Since we do not want to interfere with the current locale setting we thus emulate the behavior in the way described above.

To maintain compatibility with other platforms, not only the LANG variable is tested, but a list of variables given as envvars parameter. The first found to be defined will be used. envvars defaults to the search path used in GNU gettext; it must always contain the variable name 'LANG'. The GNU gettext search path contains 'LC_ALL', 'LC_CTYPE', 'LANG' and 'LANGUAGE', in that order.

Except for the code 'C', the language code corresponds to RFC 1766. language code and encoding may be None if their values cannot be determined.

locale.getlocale(category=LC_CTYPE)

Returns the current setting for the given locale category as sequence containing language code, encoding. category may be one of the LC_* values except LC_ALL. It defaults to LC_CTYPE.

Except for the code 'C', the language code corresponds to RFC 1766. language code and encoding may be None if their values cannot be determined.

locale.getpreferredencoding(do_setlocale=True)

Return the locale encoding used for text data, according to user preferences. User preferences are expressed differently on different systems, and might not be available programmatically on some systems, so this function only returns a guess.

On some systems, it is necessary to invoke setlocale() to obtain the user preferences, so this function is not thread-safe. If invoking setlocale is not necessary or desired, do_setlocale should be set to False.

On Android or if the Python UTF-8 Mode is enabled, always return 'UTF-8', the locale encoding and the do_setlocale argument are ignored.

The Python preinitialization configures the LC_CTYPE locale. See also the filesystem encoding and error handler.

在 3.7 版更改: The function now always returns UTF-8 on Android or if the Python UTF-8 Mode is enabled.

locale.normalize(localename)

Returns a normalized locale code for the given locale name. The returned locale code is formatted for use with setlocale(). If normalization fails, the original name is returned unchanged.

If the given encoding is not known, the function defaults to the default encoding for the locale code just like setlocale().

locale.resetlocale(category=LC_ALL)

Sets the locale for category to the default setting.

The default setting is determined by calling getdefaultlocale(). category defaults to LC_ALL.

locale.strcoll(string1, string2)

Compares two strings according to the current LC_COLLATE setting. As any other compare function, returns a negative, or a positive value, or 0, depending on whether string1 collates before or after string2 or is equal to it.

locale.strxfrm(string)

Transforms a string to one that can be used in locale-aware comparisons. For example, strxfrm(s1) < strxfrm(s2) is equivalent to strcoll(s1, s2) < 0. This function can be used when the same string is compared repeatedly, e.g. when collating a sequence of strings.

locale.format_string(format, val, grouping=False, monetary=False)

Formats a number val according to the current LC_NUMERIC setting. The format follows the conventions of the % operator. For floating point values, the decimal point is modified if appropriate. If grouping is true, also takes the grouping into account.

If monetary is true, the conversion uses monetary thousands separator and grouping strings.

Processes formatting specifiers as in format % val, but takes the current locale settings into account.

在 3.7 版更改: The monetary keyword parameter was added.

locale.format(format, val, grouping=False, monetary=False)

Please note that this function works like format_string() but will only work for exactly one %char specifier. For example, '%f' and '%.0f' are both valid specifiers, but '%f KiB' is not.

For whole format strings, use format_string().

3.7 版后已移除: Use format_string() instead.

locale.currency(val, symbol=True, grouping=False, international=False)

Formats a number val according to the current LC_MONETARY settings.

The returned string includes the currency symbol if symbol is true, which is the default. If grouping is true (which is not the default), grouping is done with the value. If international is true (which is not the default), the international currency symbol is used.

Note that this function will not work with the ‘C’ locale, so you have to set a locale via setlocale() first.

locale.str(float)

Formats a floating point number using the same format as the built-in function str(float), but takes the decimal point into account.

locale.delocalize(string)

Converts a string into a normalized number string, following the LC_NUMERIC settings.

3.5 新版功能.

locale.localize(string, grouping=False, monetary=False)

Converts a normalized number string into a formatted string following the LC_NUMERIC settings.

3.10 新版功能.

locale.atof(string)

Converts a string to a floating point number, following the LC_NUMERIC settings.

locale.atoi(string)

Converts a string to an integer, following the LC_NUMERIC conventions.

locale.LC_CTYPE

Locale category for the character type functions. Depending on the settings of this category, the functions of module string dealing with case change their behaviour.

locale.LC_COLLATE

Locale category for sorting strings. The functions strcoll() and strxfrm() of the locale module are affected.

locale.LC_TIME

Locale category for the formatting of time. The function time.strftime() follows these conventions.

locale.LC_MONETARY

Locale category for formatting of monetary values. The available options are available from the localeconv() function.

locale.LC_MESSAGES

Locale category for message display. Python currently does not support application specific locale-aware messages. Messages displayed by the operating system, like those returned by os.strerror() might be affected by this category.

locale.LC_NUMERIC

Locale category for formatting numbers. The functions format(), atoi(), atof() and str() of the locale module are affected by that category. All other numeric formatting operations are not affected.

locale.LC_ALL

Combination of all locale settings. If this flag is used when the locale is changed, setting the locale for all categories is attempted. If that fails for any category, no category is changed at all. When the locale is retrieved using this flag, a string indicating the setting for all categories is returned. This string can be later used to restore the settings.

locale.CHAR_MAX

This is a symbolic constant used for different values returned by localeconv().

示例:

>>> import locale
>>> loc = locale.getlocale()  # get current locale
# use German locale; name might vary with platform
>>> locale.setlocale(locale.LC_ALL, 'de_DE')
>>> locale.strcoll('f\xe4n', 'foo')  # compare a string containing an umlaut
>>> locale.setlocale(locale.LC_ALL, '')   # use user's preferred locale
>>> locale.setlocale(locale.LC_ALL, 'C')  # use default (C) locale
>>> locale.setlocale(locale.LC_ALL, loc)  # restore saved locale

Background, details, hints, tips and caveats

The C standard defines the locale as a program-wide property that may be relatively expensive to change. On top of that, some implementations are broken in such a way that frequent locale changes may cause core dumps. This makes the locale somewhat painful to use correctly.

Initially, when a program is started, the locale is the C locale, no matter what the user’s preferred locale is. There is one exception: the LC_CTYPE category is changed at startup to set the current locale encoding to the user’s preferred locale encoding. The program must explicitly say that it wants the user’s preferred locale settings for other categories by calling setlocale(LC_ALL, '').

It is generally a bad idea to call setlocale() in some library routine, since as a side effect it affects the entire program. Saving and restoring it is almost as bad: it is expensive and affects other threads that happen to run before the settings have been restored.

If, when coding a module for general use, you need a locale independent version of an operation that is affected by the locale (such as certain formats used with time.strftime()), you will have to find a way to do it without using the standard library routine. Even better is convincing yourself that using locale settings is okay. Only as a last resort should you document that your module is not compatible with non-C locale settings.

The only way to perform numeric operations according to the locale is to use the special functions defined by this module: atof(), atoi(), format(), str().

There is no way to perform case conversions and character classifications according to the locale. For (Unicode) text strings these are done according to the character value only, while for byte strings, the conversions and classifications are done according to the ASCII value of the byte, and bytes whose high bit is set (i.e., non-ASCII bytes) are never converted or considered part of a character class such as letter or whitespace.

For extension writers and programs that embed Python

Extension modules should never call setlocale(), except to find out what the current locale is. But since the return value can only be used portably to restore it, that is not very useful (except perhaps to find out whether or not the locale is C).

When Python code uses the locale module to change the locale, this also affects the embedding application. If the embedding application doesn’t want this to happen, it should remove the _locale extension module (which does all the work) from the table of built-in modules in the config.c file, and make sure that the _locale module is not accessible as a shared library.

Access to message catalogs

locale.gettext(msg)

locale.dgettext(domain, msg)

locale.dcgettext(domain, msg, category)

locale.textdomain(domain)

locale.bindtextdomain(domain, dir)

The locale module exposes the C library’s gettext interface on systems that provide this interface. It consists of the functions gettext(), dgettext(), dcgettext(), textdomain(), bindtextdomain(), and bind_textdomain_codeset(). These are similar to the same functions in the gettext module, but use the C library’s binary format for message catalogs, and the C library’s search algorithms for locating message catalogs.

Python applications should normally find no need to invoke these functions, and should use gettext instead. A known exception to this rule are applications that link with additional C libraries which internally invoke gettext() or dcgettext(). For these applications, it may be necessary to bind the text domain, so that the libraries can properly locate their message catalogs.

程序框架

本章描述的完整模块列表如下:

  • turtle —- 海龟绘图
    • 概述
    • 可用的 Turtle 和 Screen 方法概览
      • Turtle 方法
      • TurtleScreen/Screen 方法
    • RawTurtle/Turtle 方法和对应函数
      • 海龟动作
      • 获取海龟的状态
      • 度量单位设置
      • 画笔控制
        • 绘图状态
        • 颜色控制
        • 填充
        • 更多绘图控制
      • 海龟状态
        • 可见性
        • 外观
      • 使用事件
      • 特殊海龟方法
      • 复合形状
    • TurtleScreen/Screen 方法及对应函数
      • 窗口控制
      • 动画控制
      • 使用屏幕事件
      • 输入方法
      • 设置与特殊方法
      • Screen 专有方法, 而非继承自 TurtleScreen
    • 公共类
    • 帮助与配置
      • 如何使用帮助
      • 文档字符串翻译为不同的语言
      • 如何配置 Screen 和 Turtle
    • turtledemo —- 演示脚本集
    • Python 2.6 之后的变化
    • Python 3.0 之后的变化
  • cmd —- 支持面向行的命令解释器
    • Cmd 对象
    • Cmd 例子
  • shlex —— 简单的词法分析
    • shlex 对象
    • 解析规则
    • 改进的 shell 兼容性

turtle —- 海龟绘图

源码: Lib/turtle.py

概述

海龟绘图很适合用来引导孩子学习编程。 最初来自于 Wally Feurzeig, Seymour Papert 和 Cynthia Solomon 于 1967 年所创造的 Logo 编程语言。

请想象绘图区有一只机器海龟,起始位置在 x-y 平面的 (0, 0) 点。先执行 import turtle,再执行 turtle.forward(15),它将(在屏幕上)朝所面对的 x 轴正方向前进 15 像素,随着它的移动画出一条线段。再执行 turtle.right(25),它将原地右转 25 度。

Turtle star

使用海龟绘图可以编写重复执行简单动作的程序画出精细复杂的形状。

from turtle import *
color('red', 'yellow')
begin_fill()
while True:
    forward(200)
    left(170)
    if abs(pos()) < 1:
        break
end_fill()
done()

通过组合使用此类命令,可以轻松地绘制出精美的形状和图案。

turtle 模块是基于 Python 标准发行版 2.5 以来的同名模块重新编写并进行了功能扩展。

新模块尽量保持了原模块的特点,并且(几乎)100%与其兼容。这就意味着初学编程者能够以交互方式使用模块的所有命令、类和方法——运行 IDLE 时注意加 -n 参数。

turtle 模块提供面向对象和面向过程两种形式的海龟绘图基本组件。由于它使用 tkinter 实现基本图形界面,因此需要安装了 Tk 支持的 Python 版本。

面向对象的接口主要使用“2+2”个类:

  1. TurtleScreen 类定义图形窗口作为绘图海龟的运动场。它的构造器需要一个 tkinter.CanvasScrolledCanvas 作为参数。应在 turtle 作为某个程序的一部分的时候使用。

    Screen() 函数返回一个 TurtleScreen 子类的单例对象。此函数应在 turtle 作为独立绘图工具时使用。作为一个单例对象,其所属的类是不可被继承的。

    TurtleScreen/Screen 的所有方法还存在对应的函数,即作为面向过程的接口组成部分。

  2. RawTurtle (别名: RawPen) 类定义海龟对象在 TurtleScreen 上绘图。它的构造器需要一个 Canvas, ScrolledCanvas 或 TurtleScreen 作为参数,以指定 RawTurtle 对象在哪里绘图。

    从 RawTurtle 派生出子类 Turtle (别名: Pen),该类对象在 Screen 实例上绘图,如果实例不存在则会自动创建。

    RawTurtle/Turtle 的所有方法也存在对应的函数,即作为面向过程的接口组成部分。

过程式接口提供与 ScreenTurtle 类的方法相对应的函数。函数名与对应的方法名相同。当 Screen 类的方法对应函数被调用时会自动创建一个 Screen 对象。当 Turtle 类的方法对应函数被调用时会自动创建一个 (匿名的) Turtle 对象。

如果屏幕上需要有多个海龟,就必须使用面向对象的接口。

turtle简易教程

shlex —— 简单的词法分析

源代码: Lib/shlex.py


shlex 类可用于编写类似 Unix shell 的简单词法分析程序。通常可用于编写“迷你语言”(如 Python 应用程序的运行控制文件)或解析带引号的字符串。

shlex 模块中定义了以下函数:

shlex.split(s, comments=False, posix=True)

用类似 shell 的语法拆分字符串 s。如果 commentsFalse (默认值),则不会解析给定字符串中的注释 (commenters 属性的 shlex 实例设为空字符串)。 本函数默认工作于 POSIX 模式下,但若 posix 参数为 False,则采用非 POSIX 模式。

注解

Since the split() function instantiates a shlex instance, passing None for s will read the string to split from standard input.

3.9 版后已移除: 在以后的 Python 版本中,给 s 传入 None 将触发异常。

shlex.join(split_command)

将列表 split_command 中的词法单元(token)串联起来,返回一个字符串。本函数是 split() 的逆运算。

>>> from shlex import join
>>> print(join(['echo', '-n', 'Multiple words']))
echo -n 'Multiple words'

为防止注入漏洞,返回值是经过 shell 转义的。

3.8 新版功能.

shlex.quote(s)

返回经过 shell 转义的字符串 s 。返回值为字符串,可以安全地用作 shell 命令行中的词法单元,可用于不能使用列表的场合。

警告

shlex 模块 仅适用于 Unix shell

在不兼容 POSIX 的 shell 或其他操作系统(如Windows)的shell上,并不保证 quote() 函数能够正常使用。在这种 shell 中执行用本模块包装过的命令,有可能会存在命令注入漏洞。

请考虑采用命令参数以列表形式给出的函数,比如带了 shell=False 参数的 subprocess.run()

以下用法是不安全的:

>>> filename = 'somefile; rm -rf ~'
>>> command = 'ls -l {}'.format(filename)
>>> print(command)  # executed by a shell: boom!
ls -l somefile; rm -rf ~

quote() 可以堵住这种安全漏洞:

>>> from shlex import quote
>>> command = 'ls -l {}'.format(quote(filename))
>>> print(command)
ls -l 'somefile; rm -rf ~'
>>> remote_command = 'ssh home {}'.format(quote(command))
>>> print(remote_command)
ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''

这种包装方式兼容于 UNIX shell 和 split()

>>> from shlex import split
>>> remote_command = split(remote_command)
>>> remote_command
['ssh', 'home', "ls -l 'somefile; rm -rf ~'"]
>>> command = split(remote_command[-1])
>>> command
['ls', '-l', 'somefile; rm -rf ~']

3.3 新版功能.

shlex 模块中定义了以下类:

class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)

shlex 及其子类的实例是一种词义分析器对象。 利用初始化参数可指定从哪里读取字符。 初始化参数必须是具备 read()readline() 方法的文件/流对象,或者是一个字符串。 如果没有给出初始化参数,则会从 sys.stdin 获取输入。 第二个可选参数是个文件名字符串,用于设置 infile 属性的初始值。 如果 instream 参数被省略或等于 sys.stdin,则第二个参数默认为 “stdin”。 posix 参数定义了操作的模式:若 posix 不为真值(默认),则 shlex 实例将工作于兼容模式。 若运行于 POSIX 模式下,则 shlex 会尽可能地应用 POSIX shell 解析规则。 punctuation_chars 参数提供了一种使行为更接近于真正的 shell 解析的方式。 该参数可接受多种值:默认值、False、保持 Python 3.5 及更早版本的行为。 如果设为 True,则会改变对字符 ();<>|& 的解析方式:这些字符将作为独立的词法单元被返回(视作标点符号)。 如果设为非空字符串,则这些字符将被用作标点符号。 出现在 punctuation_chars 中的 wordchars 属性中的任何字符都会从 wordchars 中被删除。 punctuation_chars 只能在创建 shlex 实例时设置,以后不能再作修改。

在 3.6 版更改: 加入 punctuation_chars 参数。

配置文件解析器,类似于 Windows 的 .ini 文件。

shlex 对象

shlex 实例具备以下方法:

shlex.get_token()

返回一个词法单元。如果所有单词已用 push_token() 堆叠在一起了,则从堆栈中弹出一个词法单元。否则就从输入流中读取一个。如果读取时遇到文件结束符,则会返回 eof(在非 POSIX 模式下为空字符串 ‘’,在 POSIX 模式下为 ``None)。

shlex.push_token(str)

将参数值压入词法单元堆栈。

shlex.read_token()

读取一个原始词法单元。忽略堆栈,且不解释源请求。(通常没什么用,只是为了完整起见。)

shlex.sourcehook(filename)

shlex 检测到源请求,以下词法单元可作为参数,并应返回一个由文件名和打开的文件对象组成的元组。

通常本方法会先移除参数中的引号。如果结果为绝对路径名,或者之前没有有效的源请求,或者之前的源请求是一个流对象(比如 sys.stdin),那么结果将不做处理。否则,如果结果是相对路径名,那么前面将会加上目录部分,目录名来自于源堆栈中前一个文件名(类似于 C 预处理器对 #include "file.h" 的处理方式)。

结果被视为一个文件名,并作为元组的第一部分返回,元组的第二部分以此为基础调用 open() 获得。(注意:这与实例初始化过程中的参数顺序相反!)

此钩子函数是公开的,可用于实现路径搜索、添加文件扩展名或黑入其他命名空间。没有对应的“关闭”钩子函数,但 shlex 实例在返回 EOF 时会调用源输入流的 close() 方法。

若要更明确地控制源堆栈,请采用 push_source()pop_source() 方法。

shlex.push_source(newstream, newfile=None)

将输入源流压入输入堆栈。如果指定了文件名参数,以后错误信息中将会用到。sourcehook() 内部同样使用了本方法。

shlex.pop_source()

从输入堆栈中弹出最后一条输入源。当遇到输入流的 EOF 时,内部也使用同一方法。

shlex.error_leader(infile=None, lineno=None)

本方法生成一条错误信息的首部,以 Unix C 编译器错误标签的形式;格式为‘“%s”, line %d: ‘`,其中%s被替换为当前源文件的名称,%d` 被替换为当前输入行号(可用可选参数覆盖)。

这是个快捷函数,旨在鼓励 shlex 用户以标准的、可解析的格式生成错误信息,以便 Emacs 和其他 Unix 工具理解。

shlex 子类的实例有一些公共实例变量,这些变量可以控制词义分析,也可用于调试。

shlex.commenters

将被视为注释起始字符串。从注释起始字符串到行尾的所有字符都将被忽略。默认情况下只包括 '#'

shlex.wordchars

可连成多字符词法单元的字符串。默认包含所有 ASCII 字母数字和下划线。在 POSIX 模式下,Latin-1 字符集的重音字符也被包括在内。如果 punctuation_chars 不为空,则可出现在文件名规范和命令行参数中的 ~-./*?= 字符也将包含在内,任何 punctuation_chars 中的字符将从 wordchars 中移除。如果 whitespace_split 设为 True,则本规则无效。

shlex.whitespace

将被视为空白符并跳过的字符。空白符是词法单元的边界。默认包含空格、制表符、换行符和回车符。

shlex.escape

将视为转义字符。仅适用于 POSIX 模式,默认只包含 '\'

shlex.quotes

将视为引号的字符。词法单元中的字符将会累至再次遇到同样的引号(因此,不同的引号会像在 shell 中一样相互包含。)默认包含 ASCII 单引号和双引号。

shlex.escapedquotes

quotes 中的字符将会解析 escape 定义的转义字符。这只在 POSIX 模式下使用,默认只包含 '"'

shlex.whitespace_split

若为 True,则只根据空白符拆分词法单元。这很有用,比如用 shlex 解析命令行,用类似 shell 参数的方式读取各个词法单元。当与 punctuation_chars 一起使用时,将根据空白符和这些字符拆分词法单元。

在 3.8 版更改: punctuation_chars 属性已与 whitespace_split 属性兼容。

shlex.infile

当前输入的文件名,可能是在类实例化时设置的,或者是由后来的源请求堆栈生成的。在构建错误信息时可能会用到本属性。

shlex.instream

shlex 实例正从中读取字符的输入流。

shlex.source

本属性默认值为 None。 如果给定一个字符串,则会识别为包含请求,类似于各种 shell 中的 source 关键字。 也就是说,紧随其后的词法单元将作为文件名打开,作为输入流,直至遇到 EOF 后调用流的 close() 方法,然后原输入流仍变回输入源。Source 请求可以在词义堆栈中嵌套任意深度。

shlex.debug

如果本属性为大于 1 的数字,则 shlex 实例会把动作进度详细地输出出来。若需用到本属性,可阅读源代码来了解细节。

shlex.lineno

源的行数(到目前为止读到的换行符数量加 1)。

shlex.token

词法单元的缓冲区。在捕获异常时可能会用到。

shlex.eof

用于确定文件结束的词法单元。在非 POSIX 模式下,将设为空字符串 '',在 POSIX 模式下被设为 None

shlex.punctuation_chars

只读属性。表示应视作标点符号的字符。标点符号将作为单个词法单元返回。然而,请注意不会进行语义有效性检查:比如 “>>>” 可能会作为一个词法单元返回,虽然 shell 可能无法识别。

3.6 新版功能.

解析规则

在非 POSIX 模式下时,shlex 会试图遵守以下规则:

  • 不识别单词中的引号(Do"Not"Separate 解析为一个单词 Do"Not"Separate);
  • 不识别转义字符;
  • 引号包裹的字符保留字面意思;
  • 成对的引号会将单词分离("Do"Separate 解析为 "Do"Separate);
  • 如果 whitespace_splitFalse,则未声明为单词字符、空白或引号的字符将作为单字符的词法单元返回。若为 True, 则 shlex 只根据空白符拆分单词。
  • EOF 用空字符串('')表示;
  • 空字符串无法解析,即便是加了引号。

在 POSIX 模式时,shlex 将尝试遵守以下解析规则:

  • 引号会被剔除,且不会拆分单词( "Do"Not"Separate" 将解析为单个单词 DoNotSeparate);
  • 未加引号包裹的转义字符(如 '\' )保留后一个字符的字面意思;
  • 引号中的字符不属于 escapedquotes (例如,"'"),则保留引号中所有字符的字面值;
  • 若引号包裹的字符属于 escapedquotes (例如 '"'),则保留引号中所有字符的字面意思,属于 escape 中的字符除外。仅当后跟后半个引号或转义字符本身时,转义字符才保留其特殊含义。否则,转义字符将视作普通字符;
  • EOF 用 None 表示;
  • 允许出现引号包裹的空字符串('')。

改进的 shell 兼容性

3.6 新版功能.

shlex 类提供了与常见 Unix shell(如 bashdashsh)的解析兼容性。为了充分利用这种兼容性,请在构造函数中设定 punctuation_chars 参数。该参数默认为 False,维持 3.6 以下版本的行为。如果设为 True,则会改变对 ();<>|& 字符的解析方式:这些字符都将视为单个的词法单元返回。虽然不算是完整的 shell 解析程序(考虑到 shell 的多样性,超出了标准库的范围),但确实能比其他方式更容易进行命令行的处理。以下代码段演示了两者的差异:

 >>> import shlex
 >>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
 >>> s = shlex.shlex(text, posix=True)
 >>> s.whitespace_split = True
 >>> list(s)
 ['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
 >>> s = shlex.shlex(text, posix=True, punctuation_chars=True)
 >>> s.whitespace_split = True
 >>> list(s)
 ['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
 '(', 'def', 'ghi', ')']

当然,返回的词法单元对 shell 无效,需要对返回的词法单元自行进行错误检查。

punctuation_chars 参数可以不传入 True ,而是传入包含特定字符的字符串,用于确定由哪些字符构成标点符号。例如:

>>> import shlex
>>> s = shlex.shlex("a && b || c", punctuation_chars="|")
>>> list(s)
['a', '&', '&', 'b', '||', 'c']

注解

如果指定了 punctuation_chars,则 wordchars 属性的参数会是 ~-./*?=。因为这些字符可以出现在文件名(包括通配符)和命令行参数中(如 --color=auto)。因此:

>>> import shlex
>>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
...                 punctuation_chars=True)
>>> list(s)
['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']

不过为了尽可能接近于 shell ,建议在使用 punctuation_chars 时始终使用 posixwhitespace_split ,这将完全否定 wordchars

为了达到最佳效果,punctuation_chars 应与 posix=True 一起设置。(注意 posix=Falseshlex 的默认设置)。

cmd —- 支持面向行的命令解释器

源代码: Lib/cmd.py


Cmd 类提供简单框架用于编写面向行的命令解释器。 这些通常对测试工具,管理工具和原型有用,这些工具随后将被包含在更复杂的接口中。

class cmd.Cmd(completekey=’tab’, stdin=None, stdout=None)

一个 Cmd 实例或子类实例是面向行的解释器框架结构。 实例化 Cmd 本身是没有充分理由的, 它作为自定义解释器类的超类是非常有用的为了继承 Cmd 的方法并且封装动作方法。

可选参数 completekey 是完成键的 readline 名称;默认是 Tab 。如果 completekey 不是 None 并且 readline 是可用的, 命令完成会自动完成。

可选参数 stdinstdout 指定了Cmd实例或子类实例将用于输入和输出的输入和输出文件对象。如果没有指定,他们将默认为 sys.stdinsys.stdout

如果你想要使用一个给定的 stdin ,确保将实例的 use_rawinput 属性设置为 False ,否则 stdin 将被忽略。

Cmd 对象

Cmd 实例有下列方法:

Cmd.cmdloop(intro=None)

反复发出提示,接受输入,从收到的输入中解析出一个初始前缀,并分派给操作方法,将其余的行作为参数传递给它们。

可选参数是在第一个提示之前发布的横幅或介绍字符串(这将覆盖 intro 类属性)。

如果 readline 继承模块被加载,输入将自动继承类似 bash的历史列表编辑(例如, Control-P 滚动回到最后一个命令, Control-N 转到下一个命令,以 Control-F 非破坏性的方式向右 Control-B 移动光标,破坏性地等)。

输入的文件结束符被作为字符串传回 'EOF'

解释器实例将会识别命令名称 foo 当且仅当它有方法 do_foo() 。有一个特殊情况,分派始于字符 '?' 的行到方法 do_help() 。另一种特殊情况,分派始于字符 '!' 的行到方法 do_shell() (如果定义了这个方法)

这个方法将返回当 postcmd() 方法返回一个真值 。参数 stoppostcmd() 是命令对应的返回值 do_*() 的方法。

如果激活了完成,全部命令将会自动完成,并且通过调用 complete_foo() 参数 text , line, begidx ,和 endidx 完成全部命令参数。 text 是我们试图匹配的字符串前缀,所有返回的匹配项必须以它为开头。 line 是删除了前导空格的当前的输入行, begidxendidx 是前缀文本的开始和结束索引。,可以用于根据参数位置提供不同的完成。

所有 Cmd 的子类继承一个预定义 do_help() 。 这个方法使用参数 'bar' 调用, 调用对应的方法 help_bar() ,如果不存在,打印 do_bar() 的文档字符串,如果可用。没有参数的情况下, do_help() 方法会列出所有可用的帮助主题 (即所有具有相应的 help_*() 方法或命令的 文档字符串),也会列举所有未被记录的命令。

Cmd.onecmd(str)

解释该参数,就好像它是为响应提示而键入的一样。 这可能会被覆盖,但通常不应该被覆盖; 用于执行有用的挂钩。 返回值是一个标志,指示解释器对命令的解释是否应该停止。 如果命令 str 有一个 do_*() 方法,则返回该方法的返回值,否则返回 default() 方法的返回值。

Cmd.emptyline()

在响应提示输入空行时调用的方法。如果此方法未被覆盖,则重复输入的最后一个非空命令。

Cmd.default(line)

当命令前缀不能被识别的时候在输入行调用的方法。如果此方法未被覆盖,它将输出一个错误信息并返回。

Cmd.completedefault(text, line, begidx, endidx)

当没有特定于命令的 complete_*() 方法可用时,调用此方法完成输入行。默认情况下,它返回一个空列表。

Cmd.precmd(line)

钩方法在命令行 line 被解释之前执行,但是在输入提示被生成和发出后。这个方法是一个在 Cmd 中的存根;它的存在是为了被子类覆盖。返回值被用作 onecmd() 方法执行的命令; precmd() 的实现或许会重写命令或者简单的返回 line 不变。

Cmd.postcmd(stop, line)

钩方法只在命令调度完成后执行。这个方法是一个在 Cmd 中的存根;它的存在是为了子类被覆盖。 line 是被执行的命令行, stop 是一个表示在调用 postcmd() 之后是否终止执行的标志;这将作为 onecmd() 方法的返回值。这个方法的返回值被用作与 stop 相关联的内部标志的新值;返回 false 将导致解释继续。

Cmd.preloop()

钩方法当 cmdloop() 被调用时执行一次。方法是一个在 Cmd 中的存根;它的存在是为了被子类覆盖。

Cmd.postloop()

钩方法在 cmdloop() 即将返回时执行一次。这个方法是一个在 Cmd 中的存根;它的存在是为了被子类覆盖。

Instances of Cmd subclasses have some public instance variables:

Cmd.prompt

发出提示以请求输入。

Cmd.identchars

接受命令前缀的字符串。

Cmd.lastcmd

看到最后一个非空命令前缀。

Cmd.cmdqueue

排队的输入行列表。当需要新的输入时,在 cmdloop() 中检查 cmdqueue 列表;如果它不是空的,它的元素将被按顺序处理,就像在提示符处输入一样。

Cmd.intro

要作为简介或横幅发出的字符串。 可以通过给 cmdloop() 方法一个参数来覆盖它。

Cmd.doc_header

如果帮助输出具有记录命令的段落,则发出头文件。

Cmd.misc_header

如果帮助输出其他帮助主题的部分(即与 do_*() 方法没有关联的 help_*() 方法),则发出头文件。

Cmd.undoc_header

如果帮助输出未被记录命令的部分(即与 help_*() 方法没有关联的 do_*() 方法),则发出头文件。

Cmd.ruler

用于在帮助信息标题的下方绘制分隔符的字符,如果为空,则不绘制标尺线。这个字符默认是 '='

Cmd.use_rawinput

这是一个标志,默认为 true 。如果为 true ,, cmdloop() 使用 input() 先是提示并且阅读下一个命令;如果为 false , sys.stdout.write()sys.stdin.readline() 被使用。(这意味着解释器将会自动支持类似于 Emacs的行编辑和命令历史记录按键操作,通过导入 readline 在支持它的系统上。)

Cmd 例子

The cmd module is mainly useful for building custom shells that let a user work with a program interactively.

这部分提供了一个简单的例子来介绍如何使用一部分在 turtle 模块中的命令构建一个 shell 。

基础的 turtle 命令比如 forward() 被添加进一个 Cmd 子类,方法名为 do_forward() 。参数被转换成数字并且分发至 turtle 模块中。 docstring 是 shell 提供的帮助实用程序。

例子也包含使用 precmd() 方法实现基础的记录和回放的功能,这个方法负责将输入转换为小写并且将命令写入文件。 do_playback() 方法读取文件并添加记录命令至 cmdqueue 用于即时回放:

import cmd, sys
from turtle import *
class TurtleShell(cmd.Cmd):
    intro = 'Welcome to the turtle shell.   Type help or ? to list commands.\n'
    prompt = '(turtle) '
    file = None
    # ----- basic turtle commands -----
    def do_forward(self, arg):
        'Move the turtle forward by the specified distance:  FORWARD 10'
        forward(*parse(arg))
    def do_right(self, arg):
        'Turn turtle right by given number of degrees:  RIGHT 20'
        right(*parse(arg))
    def do_left(self, arg):
        'Turn turtle left by given number of degrees:  LEFT 90'
        left(*parse(arg))
    def do_goto(self, arg):
        'Move turtle to an absolute position with changing orientation.  GOTO 100 200'
        goto(*parse(arg))
    def do_home(self, arg):
        'Return turtle to the home position:  HOME'
        home()
    def do_circle(self, arg):
        'Draw circle with given radius an options extent and steps:  CIRCLE 50'
        circle(*parse(arg))
    def do_position(self, arg):
        'Print the current turtle position:  POSITION'
        print('Current position is %d %d\n' % position())
    def do_heading(self, arg):
        'Print the current turtle heading in degrees:  HEADING'
        print('Current heading is %d\n' % (heading(),))
    def do_color(self, arg):
        'Set the color:  COLOR BLUE'
        color(arg.lower())
    def do_undo(self, arg):
        'Undo (repeatedly) the last turtle action(s):  UNDO'
    def do_reset(self, arg):
        'Clear the screen and return turtle to center:  RESET'
        reset()
    def do_bye(self, arg):
        'Stop recording, close the turtle window, and exit:  BYE'
        print('Thank you for using Turtle')
        self.close()
        bye()
        return True
    # ----- record and playback -----
    def do_record(self, arg):
        'Save future commands to filename:  RECORD rose.cmd'
        self.file = open(arg, 'w')
    def do_playback(self, arg):
        'Playback commands from a file:  PLAYBACK rose.cmd'
        self.close()
        with open(arg) as f:
            self.cmdqueue.extend(f.read().splitlines())
    def precmd(self, line):
        line = line.lower()
        if self.file and 'playback' not in line:
            print(line, file=self.file)
        return line
    def close(self):
        if self.file:
            self.file.close()
            self.file = None
def parse(arg):
    'Convert a series of zero or more numbers to an argument tuple'
    return tuple(map(int, arg.split()))
if __name__ == '__main__':
    TurtleShell().cmdloop()

这是一个示例会话,其中 turtle shell 显示帮助功能,使用空行重复命令,以及简单的记录和回放功能:

Welcome to the turtle shell.   Type help or ? to list commands.
(turtle) ?
Documented commands (type help <topic>):
========================================
bye     color    goto     home  playback  record  right
circle  forward  heading  left  position  reset   undo
(turtle) help forward
Move the turtle forward by the specified distance:  FORWARD 10
(turtle) record spiral.cmd
(turtle) position
Current position is 0 0
(turtle) heading
Current heading is 0
(turtle) reset
(turtle) circle 20
(turtle) right 30
(turtle) circle 40
(turtle) right 30
(turtle) circle 60
(turtle) right 30
(turtle) circle 80
(turtle) right 30
(turtle) circle 100
(turtle) right 30
(turtle) circle 120
(turtle) right 30
(turtle) circle 120
(turtle) heading
Current heading is 180
(turtle) forward 100
(turtle)
(turtle) right 90
(turtle) forward 100
(turtle)
(turtle) right 90
(turtle) forward 400
(turtle) right 90
(turtle) forward 500
(turtle) right 90
(turtle) forward 400
(turtle) right 90
(turtle) forward 300
(turtle) playback spiral.cmd
Current position is 0 0
Current heading is 0
Current heading is 180
(turtle) bye
Thank you for using Turtle

Tk图形用户界面(GUI)

Tcl/Tk集成到Python中已经有一些年头了。Python程序员可以通过 tkinter 包和它的扩展, tkinter.tix 模块和 tkinter.ttk 模块,来使用这套鲁棒的、平台无关的窗口工具集。

tkinter 包是使用面向对象方式对 Tcl/Tk 进行的一层薄包装。 使用 tkinter,你不需要写 Tcl 代码,但你将需要参阅 Tk 文档,有时还需要参阅 Tcl 文档。 tkinter 是一组包装器,它将 Tk 的可视化部件实现为相应的 Python 类。

tkinter 的主要特点是速度很快,并且通常直接附带在 Python 中。 虽然它的官方文档做得不好,但还是有许多可用的资源,包括:在线参考、教程、入门书等等。 tkinter 还有众所周知的较过时的外观界面,这在 Tk 8.5 中已得到很大改进。 无论如何,你还可以考虑许多其他的 GUI 库。 Python wiki 例出了一些替代性的 GUI 框架和工具

开发工具

本章中描述的各模块可帮你编写 Python 程序。例如,pydoc 模块接受一个模块并根据该模块的内容来生成文档。doctestunittest 这两个模块包含了用于编写单元测试的框架,并可用于自动测试所编写的代码,验证预期的输出是否产生。2to3 程序能够将 Python 2.x 源代码翻译成有效的 Python 3.x 源代码。

本章中描述的模块列表是:

  • typing —- 类型提示支持
    • 类型别名
    • NewType
    • 可调对象(Callable)
    • 泛型(Generic)
    • 用户定义的泛型类型
    • Any 类型
    • 名义子类型 vs 结构子类型
    • 模块内容
      • 特殊类型原语
        • 特殊类型
        • 特殊形式
        • 构建泛型类型
        • 其他特殊指令
      • 泛型具象容器
        • 对应的内置类型
        • collections 对应类型
        • 其他具象类型
      • 抽象基类
        • collections.abc 对应的容器
        • collections.abc 对应的其他类型
        • 异步编程
        • 上下文管理器类型
      • 协议
      • 函数与装饰器
      • 内省辅助器
      • 常量
  • pydoc —- 文档生成器和在线帮助系统
  • Python Development Mode
  • Effects of the Python Development Mode
  • ResourceWarning Example
  • Bad file descriptor error example
  • doctest —- 测试交互性的Python示例
    • 简单用法:检查Docstrings中的示例
    • Simple Usage: Checking Examples in a Text File
    • How It Works
      • Which Docstrings Are Examined?
      • How are Docstring Examples Recognized?
      • What’s the Execution Context?
      • What About Exceptions?
      • Option Flags
      • Directives
      • 警告
    • Basic API
    • Unittest API
    • Advanced API
      • DocTest 对象
      • Example Objects
      • DocTestFinder 对象
      • DocTestParser 对象
      • DocTestRunner 对象
      • OutputChecker 对象
    • 调试
    • Soapbox
  • unittest —- 单元测试框架
    • 基本实例
    • 命令行接口
      • 命令行选项
    • 探索性测试
    • 组织你的测试代码
    • 复用已有的测试代码
    • 跳过测试与预计的失败
    • Distinguishing test iterations using subtests
    • 类与函数
      • 测试用例
        • Deprecated aliases
      • Grouping tests
      • Loading and running tests
        • load_tests Protocol
    • Class and Module Fixtures
      • setUpClass and tearDownClass
      • setUpModule and tearDownModule
    • 信号处理
  • unittest.mock —- 模拟对象库
    • 快速上手
    • Mock 类
      • Calling
      • Deleting Attributes
      • Mock names and the name attribute
      • Attaching Mocks as Attributes
    • The patchers
      • patch
      • patch.object
      • patch.dict
      • patch.multiple
      • patch methods: start and stop
      • patch builtins
      • TEST_PREFIX
      • Nesting Patch Decorators
      • Where to patch
      • Patching Descriptors and Proxy Objects
    • MagicMock and magic method support
      • Mocking Magic Methods
      • Magic Mock
    • Helpers
      • sentinel
      • DEFAULT
      • call
      • create_autospec
      • ANY
      • FILTER_DIR
      • mock_open
      • Autospeccing
      • Sealing mocks
  • unittest.mock 上手指南
    • 使用 mock
      • 模拟方法调用
      • 对象上的方法调用的 mock
      • Mocking Classes
      • Naming your mocks
      • Tracking all Calls
      • Setting Return Values and Attributes
      • Raising exceptions with mocks
      • Side effect functions and iterables
      • Mocking asynchronous iterators
      • Mocking asynchronous context manager
      • Creating a Mock from an Existing Object
    • Patch Decorators
    • Further Examples
      • Mocking chained calls
      • Partial mocking
      • Mocking a Generator Method
      • Applying the same patch to every test method
      • Mocking Unbound Methods
      • Checking multiple calls with mock
      • Coping with mutable arguments
      • Nesting Patches
      • Mocking a dictionary with MagicMock
      • Mock subclasses and their attributes
      • Mocking imports with patch.dict
      • Tracking order of calls and less verbose call assertions
      • More complex argument matching
  • 2to3 - 自动将 Python 2 代码转为 Python 3 代码
    • 使用 2to3
    • 修复器
    • lib2to3 —— 2to3 支持库
  • test —- Python回归测试包
    • Writing Unit Tests for the test package
    • Running tests using the command-line interface
  • test.support —- Utilities for the Python test suite
  • test.support.socket_helper —- Utilities for socket tests
  • test.support.script_helper —- Utilities for the Python execution tests
  • test.support.bytecode_helper —- Support tools for testing correct bytecode generation
  • test.support.threading_helper —- Utilities for threading tests
  • test.support.os_helper —- Utilities for os tests
  • test.support.import_helper —- Utilities for import tests
  • test.support.warnings_helper —- Utilities for warnings tests

typing —- 类型提示支持

3.5 新版功能.

源码: Lib/typing.py

注解

Python 运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具。


This module provides runtime support for type hints as specified by PEP 484, PEP 526, PEP 544, PEP 586, PEP 589, PEP 591, PEP 612 and PEP 613. The most fundamental support consists of the types Any, Union, Tuple, Callable, TypeVar, and Generic. For full specification please see PEP 484. For a simplified introduction to type hints see PEP 483.

下面的函数接收与返回的都是字符串,注解方式如下:

def greeting(name: str) -> str:
    return 'Hello ' + name

greeting 函数中,参数 name 的类型是 str,返回类型也是 str。子类型也可以当作参数。

类型别名

把类型赋给别名,就可以定义类型别名。本例中,Vectorlist[float] 相同,可互换:

Vector = list[float]
def scale(scalar: float, vector: Vector) -> Vector:
    return [scalar * num for num in vector]
# typechecks; a list of floats qualifies as a Vector.
new_vector = scale(2.0, [1.0, -4.2, 5.4])

类型别名适用于简化复杂的类型签名。例如:

from collections.abc import Sequence
ConnectionOptions = dict[str, str]
Address = tuple[str, int]
Server = tuple[Address, ConnectionOptions]
def broadcast_message(message: str, servers: Sequence[Server]) -> None:
    ...
# The static type checker will treat the previous type signature as
# being exactly equivalent to this one.
def broadcast_message(
        message: str,
        servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None:
    ...

注意,None 是一种类型提示特例,已被 type(None) 取代。

NewType

Use the NewType helper class to create distinct types:

from typing import NewType
UserId = NewType('UserId', int)
some_id = UserId(524313)

静态类型检查器把新类型当作原始类型的子类,这种方式适用于捕捉逻辑错误:

def get_user_name(user_id: UserId) -> str:
    ...
# typechecks
user_a = get_user_name(UserId(42351))
# does not typecheck; an int is not a UserId
user_b = get_user_name(-1)

UserId 类型的变量可执行所有 int 操作,但返回结果都是 int 类型。这种方式允许在预期 int 时传入 UserId,还能防止意外创建无效的 UserId

# 'output' is of type 'int', not 'UserId'
output = UserId(23413) + UserId(54341)

Note that these checks are enforced only by the static type checker. At runtime, the statement Derived = NewType('Derived', Base) will make Derived a class that immediately returns whatever parameter you pass it. That means the expression Derived(some_value) does not create a new class or introduce much overhead beyond that of a regular function call.

更确切地说,在运行时,some_value is Derived(some_value) 表达式总为 True。

It is invalid to create a subtype of Derived:

from typing import NewType
UserId = NewType('UserId', int)
# Fails at runtime and does not typecheck
class AdminUserId(UserId): pass

However, it is possible to create a NewType based on a ‘derived’ NewType:

from typing import NewType
UserId = NewType('UserId', int)
ProUserId = NewType('ProUserId', UserId)

同时,ProUserId 的类型检查也可以按预期执行。

详见 PEP 484

注解

回顾上文,类型别名声明了两种彼此 等价 的类型。 Alias = Original 时,静态类型检查器认为 AliasOriginal 完全等价。 这种方式适用于简化复杂类型签名。

反之,NewType 声明把一种类型当作另一种类型的 子类型*。Derived = NewType('Derived', Original) 时,静态类型检查器把 Derived 当作 Original 的 *子类 ,即,Original 类型的值不能用在预期 Derived 类型的位置。这种方式适用于以最小运行时成本防止逻辑错误。

3.5.2 新版功能.

在 3.10 版更改: NewType is now a class rather than a function. There is some additional runtime cost when calling NewType over a regular function. However, this cost will be reduced in 3.11.0.

可调对象(Callable)

预期特定签名回调函数的框架可以用 Callable[[Arg1Type, Arg2Type], ReturnType] 实现类型提示。

例如:

from collections.abc import Callable
def feeder(get_next_item: Callable[[], str]) -> None:
    # Body
def async_query(on_success: Callable[[int], None],
                on_error: Callable[[int, Exception], None]) -> None:
    # Body

无需指定调用签名,用省略号字面量替换类型提示里的参数列表: Callable[..., ReturnType],就可以声明可调对象的返回类型。

Callables which take other callables as arguments may indicate that their parameter types are dependent on each other using ParamSpec. Additionally, if that callable adds or removes arguments from other callables, the Concatenate operator may be used. They take the form Callable[ParamSpecVariable, ReturnType] and Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType] respectively.

在 3.10 版更改: Callable now supports ParamSpec and Concatenate. See PEP 612 for more information.

参见

The documentation for ParamSpec and Concatenate provide examples of usage in Callable.

泛型(Generic)

容器中,对象的类型信息不能以泛型方式静态推断,因此,抽象基类扩展支持下标,用于表示容器元素的预期类型。

from collections.abc import Mapping, Sequence
def notify_by_email(employees: Sequence[Employee],
                    overrides: Mapping[str, str]) -> None: ...

typing 模块中新推出的 TypeVar 工厂函数实现泛型参数化。

from collections.abc import Sequence
from typing import TypeVar
T = TypeVar('T')      # Declare type variable
def first(l: Sequence[T]) -> T:   # Generic function
    return l[0]

用户定义的泛型类型

用户定义的类可以定义为泛型类。

from typing import TypeVar, Generic
from logging import Logger
T = TypeVar('T')
class LoggedVar(Generic[T]):
    def __init__(self, value: T, name: str, logger: Logger) -> None:
        self.name = name
        self.logger = logger
        self.value = value
    def set(self, new: T) -> None:
        self.log('Set ' + repr(self.value))
        self.value = new
    def get(self) -> T:
        self.log('Get ' + repr(self.value))
        return self.value
    def log(self, message: str) -> None:
        self.logger.info('%s: %s', self.name, message)

Generic[T] 是定义类 LoggedVar 的基类,该类使用单类型参数 T。在该类体内,T 是有效的类型。

Generic 基类定义了 __class_getitem__() ,因此,LoggedVar[t] 也是有效类型:

from collections.abc import Iterable
def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
    for var in vars:
        var.set(0)

泛型类型支持多个类型变量,不过,类型变量可能会受到限制:

from typing import TypeVar, Generic
...
T = TypeVar('T')
S = TypeVar('S', int, str)
class StrangePair(Generic[T, S]):
    ...

Generic 类型变量的参数应各不相同。下列代码就是无效的:

from typing import TypeVar, Generic
...
T = TypeVar('T')
class Pair(Generic[T, T]):   # INVALID
    ...

Generic 支持多重继承:

from collections.abc import Sized
from typing import TypeVar, Generic
T = TypeVar('T')
class LinkedList(Sized, Generic[T]):
    ...

继承自泛型类时,可以修正某些类型变量:

from collections.abc import Mapping
from typing import TypeVar
T = TypeVar('T')
class MyDict(Mapping[str, T]):
    ...

比如,本例中 MyDict 调用的单参数,T

未指定泛型类的类型参数时,每个位置的类型都预设为 Any。下例中,MyIterable 不是泛型,但却隐式继承了 Iterable[Any]

from collections.abc import Iterable
class MyIterable(Iterable): # Same as Iterable[Any]

还支持用户定义的泛型类型别名。例如:

from collections.abc import Iterable
from typing import TypeVar
S = TypeVar('S')
Response = Iterable[S] | int
# Return type here is same as Iterable[str] | int
def response(query: str) -> Response[str]:
    ...
T = TypeVar('T', int, float, complex)
Vec = Iterable[tuple[T, T]]
def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
    return sum(x*y for x, y in v)

在 3.7 版更改: Generic 不再支持自定义元类。

User-defined generics for parameter expressions are also supported via parameter specification variables in the form Generic[P]. The behavior is consistent with type variables’ described above as parameter specification variables are treated by the typing module as a specialized type variable. The one exception to this is that a list of types can be used to substitute a ParamSpec:

>>> from typing import Generic, ParamSpec, TypeVar
>>> T = TypeVar('T')
>>> P = ParamSpec('P')
>>> class Z(Generic[T, P]): ...
...
>>> Z[int, [dict, float]]
__main__.Z[int, (<class 'dict'>, <class 'float'>)]

Furthermore, a generic with only one parameter specification variable will accept parameter lists in the forms X[[Type1, Type2, ...]] and also X[Type1, Type2, ...] for aesthetic reasons. Internally, the latter is converted to the former and are thus equivalent:

>>> class X(Generic[P]): ...
...
>>> X[int, str]
__main__.X[(<class 'int'>, <class 'str'>)]
>>> X[[int, str]]
__main__.X[(<class 'int'>, <class 'str'>)]

Do note that generics with ParamSpec may not have correct __parameters__ after substitution in some cases because they are intended primarily for static type checking.

在 3.10 版更改: Generic can now be parameterized over parameter expressions. See ParamSpec and PEP 612 for more details.

抽象基类可作为用户定义的泛型类的基类,且不会与元类冲突。现已不再支持泛型元类。参数化泛型的输出结果会被缓存,typing 模块的大多数类型都可哈希、可进行等价对比。

Any 类型

Any 是一种特殊的类型。静态类型检查器认为所有类型均与 Any 兼容,同样,Any 也与所有类型兼容。

也就是说,可对 Any 类型的值执行任何操作或方法调用,并赋值给任意变量:

from typing import Any
a = None    # type: Any
a = []      # OK
a = 2       # OK
s = ''      # type: str
s = a       # OK
def foo(item: Any) -> int:
    # Typechecks; 'item' could be any type,
    # and that type might have a 'bar' method
    item.bar()
    ...

注意,Any 类型的值赋给更精确的类型时,不执行类型检查。例如,把 a 赋给 s,在运行时,即便 s 已声明为 str 类型,但接收 int 值时,静态类型检查器也不会报错。

此外,未指定返回值与参数类型的函数,都隐式地默认使用 Any

def legacy_parser(text):
    ...
    return data
# A static type checker will treat the above
# as having the same signature as:
def legacy_parser(text: Any) -> Any:
    ...
    return data

需要混用动态与静态类型代码时,此操作把 Any 当作 应急出口

Anyobject 的区别。与 Any 相似,所有类型都是 object 的子类型。然而,与 Any 不同,object 不可逆:object 不是 其它类型的子类型。

就是说,值的类型是 object 时,类型检查器几乎会拒绝所有对它的操作,并且,把它赋给更精确的类型变量(或返回值)属于类型错误。例如:

def hash_a(item: object) -> int:
    # Fails; an object does not have a 'magic' method.
    item.magic()
    ...
def hash_b(item: Any) -> int:
    # Typechecks
    item.magic()
    ...
# Typechecks, since ints and strs are subclasses of object
hash_a(42)
hash_a("foo")
# Typechecks, since Any is compatible with all types
hash_b(42)
hash_b("foo")

使用 object,说明值能以类型安全的方式转为任何类型。使用 Any,说明值是动态类型。

名义子类型 vs 结构子类型

PEP 484 最初只是把 Python 静态类型系统定义为应用 名义子类型。即,当且仅当 AB 的子类时,才能在预期 B 类时应用 A 类。

此项要求以前也适用于抽象基类,例如,Iterable 。这种方式的问题在于,定义类时必须显式说明,既不 Pythonic,也不是动态类型式 Python 代码的惯用写法。例如,下列代码就遵从了 PEP 484 的规范:

from collections.abc import Sized, Iterable, Iterator
class Bucket(Sized, Iterable[int]):
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...

PEP 544 允许用户在类定义时不显式说明基类,从而解决了这一问题,静态类型检查器隐式认为 Bucket 既是 Sized 的子类型,又是 Iterable[int] 的子类型。这就是 结构子类型 (又称为静态鸭子类型):

from collections.abc import Iterator, Iterable
class Bucket:  # Note: no base classes
    ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[int]: ...
def collect(items: Iterable[int]) -> int: ...
result = collect(Bucket())  # Passes type check

此外,结构子类型的优势在于,通过继承特殊类 Protocol ,用户可以定义新的自定义协议(见下文中的例子)。

模块内容

本模块定义了下列类、函数和修饰器。

注解

本模块定义了一些类型,作为标准库中已有的类的子类,从而可以让 Generic 支持 [] 中的类型变量。Python 3.9 中,这些标准库的类已支持 [] ,因此,这些类型就变得冗余了。

Python 3.9 弃用了这些冗余类型,但解释器并未提供相应的弃用警告。标记弃用类型的工作留待支持 Python 3.9 及以上版本的类型检查器实现。

Python 3.9.0 发布五年后的首个 Python 发行版将从 typing 模块中移除这些弃用类型。详见 PEP 585标准集合的类型提示泛型》。

特殊类型原语

特殊类型

这些类型可用于类型注解,但不支持 []

typing.Any

不受限的特殊类型。

  • 所有类型都与 Any 兼容。
  • Any 与所有类型都兼容。
typing.NoReturn

标记没有返回值的函数的特殊类型。例如:

from typing import NoReturn
def stop() -> NoReturn:
    raise RuntimeError('no way')

3.5.4 新版功能.

3.6.2 新版功能.

typing.TypeAlias

Special annotation for explicitly declaring a type alias. For example:

from typing import TypeAlias
Factors: TypeAlias = list[int]

See PEP 613 for more details about explicit type aliases.

3.10 新版功能.

特殊形式

可用于类型注解,且支持 [] ,每种形式都有其独特的句法。

typing.Tuple

元组类型; Tuple[X, Y] 是二项元组类型,第一个元素的类型是 X,第二个元素的类型是 Y。空元组的类型可写为 Tuple[()]

例:Tuple[T1, T2] 是二项元组,类型变量分别为 T1 和 T2。Tuple[int, float, str] 是由整数、浮点数、字符串组成的三项元组。

可用省略号字面量指定同质变长元组,例如,Tuple[int, ...]TupleTuple[Any, ...] 等价,也与 tuple 等价。

3.9 版后已移除: builtins.tuple 现已支持 []。详见 PEP 585 与 Generic Alias Type。

typing.Union

Union type; Union[X, Y] is equivalent to X | Y and means either X or Y.

To define a union, use e.g. Union[int, str] or the shorthand int | str. Details:

  • 参数必须是某种类型,且至少有一个。

  • 联合类型之联合类型会被展平,例如:

    Union[Union[int, str], float] == Union[int, str, float]
  • 单参数之联合类型就是该参数自身,例如:

    Union[int] == int  # The constructor actually returns int
  • 冗余的参数会被跳过,例如:

    Union[int, str, int] == Union[int, str] == int | str
  • 比较联合类型,不涉及参数顺序,例如:

    Union[int, str] == Union[str, int]
  • You cannot subclass or instantiate a Union.

  • 不支持 Union[X][Y] 这种写法。

在 3.7 版更改: 在运行时,不要移除联合类型中的显式子类。

在 3.10 版更改: Unions can now be written as X | Y. See union type expressions.

typing.Optional

可选类型。

Optional[X] is equivalent to X | None (or Union[X, None]).

注意,可选类型与含默认值的可选参数不同。含默认值的可选参数不需要在类型注解上添加 Optional 限定符,因为它仅是可选的。例如:

def foo(arg: int = 0) -> None: 
    ...

另一方面,显式应用 None 值时,不管该参数是否可选, Optional 都适用。例如:

def foo(arg: Optional[int] = None) -> None:
    ...

在 3.10 版更改: Optional can now be written as X | None. See union type expressions.

typing.Callable

可调类型; Callable[[int], str] 是把(int)转为 str 的函数。

下标句法必须与参数列表和返回类型这两个值一起使用。参数列表只能是类型列表或省略号;返回类型只能是单一类型。

没有说明可选参数或关键字参数的句法;这类函数类型很少用作回调类型。Callable[..., ReturnType] (省略号字面量)可用于为接受任意数量参数,并返回 ReturnType 的可调对象提供类型提示。纯 Callable 等价于 Callable[..., Any],进而等价于 collections.abc.Callable

Callables which take other callables as arguments may indicate that their parameter types are dependent on each other using ParamSpec. Additionally, if that callable adds or removes arguments from other callables, the Concatenate operator may be used. They take the form Callable[ParamSpecVariable, ReturnType] and Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType] respectively.

3.9 版后已移除: collections.abc.Callable 现已支持 []。 详见 PEP 585 与 Generic Alias Type。

在 3.10 版更改: Callable now supports ParamSpec and Concatenate. See PEP 612 for more information.

参见

The documentation for ParamSpec and Concatenate provide examples of usage with Callable.

typing.Concatenate

Used with Callable and ParamSpec to type annotate a higher order callable which adds, removes, or transforms parameters of another callable. Usage is in the form Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]. Concatenate is currently only valid when used as the first argument to a Callable. The last parameter to Concatenate must be a ParamSpec.

For example, to annotate a decorator with_lock which provides a threading.Lock to the decorated function, Concatenate can be used to indicate that with_lock expects a callable which takes in a Lock as the first argument, and returns a callable with a different type signature. In this case, the ParamSpec indicates that the returned callable’s parameter types are dependent on the parameter types of the callable being passed in:

from collections.abc import Callable
from threading import Lock
from typing import Any, Concatenate, ParamSpec, TypeVar
P = ParamSpec('P')
R = TypeVar('R')
# Use this lock to ensure that only one thread is executing a function
# at any time.
my_lock = Lock()
def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
    '''A type-safe decorator which provides a lock.'''
    global my_lock
    def inner(*args: P.args, **kwargs: P.kwargs) -> R:
        # Provide the lock as the first argument.
        return f(my_lock, *args, **kwargs)
    return inner
@with_lock
def sum_threadsafe(lock: Lock, numbers: list[float]) -> float:
    '''Add a list of numbers together in a thread-safe manner.'''
    with lock:
        return sum(numbers)
# We don't need to pass in the lock ourselves thanks to the decorator.
sum_threadsafe([1.1, 2.2, 3.3])

3.10 新版功能.

参见

  • PEP 612 — Parameter Specification Variables (the PEP which introduced ParamSpec and Concatenate).
  • ParamSpec and Callable.

class typing.Type(Generic[CT_co])

C 注解的变量可以接受类型 C 的值。反之,用 Type[C] 注解的变量可以接受类自身的值 — 准确地说,是接受 C类对象,例如:

a = 3         # Has type 'int'
b = int       # Has type 'Type[int]'
c = type(a)   # Also has type 'Type[int]'

注意,Type[C] 为协变量:

class User: ...
class BasicUser(User): ...
class ProUser(User): ...
class TeamUser(User): ...
# Accepts User, BasicUser, ProUser, TeamUser, ...
def make_new_user(user_class: Type[User]) -> User:
    # ...
    return user_class()

Type[C] 为协变量的意思是指, C 的所有子类都应使用与 C 相同的构造器签名及类方法签名。类型检查器应标记违反此项规定的内容,但也应允许符合指定基类构造器调用的子类进行构造器调用。PEP 484 修订版将来可能会调整类型检查器对这种特例的处理方式。

Type 合法的参数仅有类、Any 、类型变量 以及上述类型的联合类型。例如:

def new_non_team_user(user_class: Type[BasicUser | ProUser]): 
    ...

Type[Any] 等价于 Type,进而等价于 Python 元类架构的根基,type

3.5.2 新版功能.

3.9 版后已移除: builtins.type 现已支持 []。详见 PEP 585 与 Generic Alias Type。

typing.Literal

表示类型检查器对应变量或函数参数的值等价于给定字面量(或多个字面量之一)的类型。例如:

def validate_simple(data: Any) -> Literal[True]:  # always returns True
    ...
MODE = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: MODE) -> str:
    ...
open_helper('/some/path', 'r')  # Passes type check
open_helper('/other/path', 'typo')  # Error in type checker

Literal[...] 不能创建子类。在运行时,任意值均可作为 Literal[...] 的类型参数,但类型检查器可以对此加以限制。字面量类型详见 PEP 586

3.8 新版功能.

在 3.9.1 版更改: Literal 现在能去除形参的重复。 Literal 对象的相等性比较不再依赖顺序。 现在如果有某个参数不为 hashable,Literal 对象在相等性比较期间将引发 TypeError

typing.ClassVar

标记类变量的特殊类型构造器。

PEP 526 所述,打包在 ClassVar 内的变量注解是指,给定属性应当用作类变量,而不应设置在类实例上。用法如下:

class Starship:
    stats: ClassVar[dict[str, int]] = {} # class variable
    damage: int = 10                     # instance variable

ClassVar 仅接受类型,也不能使用下标。

ClassVar 本身不是类,不应用于 isinstance()issubclass()ClassVar 不改变 Python 运行时行为,但可以用于第三方类型检查器。例如,类型检查器会认为以下代码有错:

enterprise_d = Starship(3000)
enterprise_d.stats = {} # Error, setting class variable on instance
Starship.stats = {}     # This is OK

3.5.3 新版功能.

typing.Final

告知类型检查器某名称不能再次赋值或在子类中重写的特殊类型构造器。例如:

MAX_SIZE: Final = 9000
MAX_SIZE += 1  # Error reported by type checker
class Connection:
    TIMEOUT: Final[int] = 10
class FastConnector(Connection):
    TIMEOUT = 1  # Error reported by type checker

这些属性没有运行时检查。详见 PEP 591

3.8 新版功能.

typing.Annotated

PEP 593灵活函数和变量注解)里引入的类型,可以用上下文特定元数据(Annotated 的参数可变,也可能用它的多个组成部分)装饰现有的类型。具体来说,就是类型提示 Annotated[T, x] 用元数据 x 注解类型 T。静态分析或运行时都能使用该元数据。库(或工具)处理类型提示 Annotated[T, x] 时,在元数据 x 不涉及特殊逻辑的情况下,可忽略该类型提示,仅把它当作类型 T。与 typing 模块中现有的 no_type_check 功能不同,该功能完全禁用了函数或类的类型检查注解,而 Annotated 类型则允许对 T 进行静态类型检查(例如,通过 mypy 或 Pyre,可安全地忽略 x),也可以在特定应用程序中实现 x 的运行时访问。

毕竟,如何解释注解(如有)由处理 Annotated 类型的工具/库负责。工具/库处理 Annotated 类型时,扫描所有注解以确定是否需要进行处理(例如,使用 isinstance())。

工具/库不支持注解,或遇到未知注解时,应忽略注解,并把注解类型当作底层类型。

是否允许客户端在一个类型上使用多个注解,以及如何合并这些注解,由处理注解的工具决定。

Annotated 类型支持把多个相同(或不同)的单个(或多个)类型注解置于任意节点。因此,使用这些注解的工具/库要负责处理潜在的重复项。例如,执行值范围分析时,应允许以下操作:

T1 = Annotated[int, ValueRange(-10, 5)]
T2 = Annotated[T1, ValueRange(-20, 3)]

传递 include_extras=Trueget_type_hints() ,即可在运行时访问额外的注解。

语义详情:

  • Annotated 的第一个参数必须是有效类型。

  • 支持多个类型标注(Annotated 支持可变参数):

    Annotated[int, ValueRange(3, 10), ctype("char")]
  • 调用 Annotated 至少要有两个参数(Annotated[int] 是无效的)

  • 注解的顺序会被保留,且影响等价检查:

    Annotated[int, ValueRange(3, 10), ctype("char")] != Annotated[
        int, ctype("char"), ValueRange(3, 10)
    ]
  • 嵌套 Annotated 类型会被展平,元数据从最内层注解依序展开:

    Annotated[Annotated[int, ValueRange(3, 10)], ctype("char")] == Annotated[
        int, ValueRange(3, 10), ctype("char")
    ]
  • 不移除注解重复项:

    Annotated[int, ValueRange(3, 10)] != Annotated[
        int, ValueRange(3, 10), ValueRange(3, 10)
    ]
  • Annotated 可用于嵌套或泛型别名:

    T = TypeVar('T')
    Vec = Annotated[list[tuple[T, T]], MaxLen(10)]
    V = Vec[int]
    V == Annotated[list[tuple[int, int]], MaxLen(10)]

3.9 新版功能.

typing.TypeGuard

Special typing form used to annotate the return type of a user-defined type guard function. TypeGuard only accepts a single type argument. At runtime, functions marked this way should return a boolean.

TypeGuard aims to benefit type narrowing — a technique used by static type checkers to determine a more precise type of an expression within a program’s code flow. Usually type narrowing is done by analyzing conditional code flow and applying the narrowing to a block of code. The conditional expression here is sometimes referred to as a “type guard”:

def is_str(val: str | float):
    # "isinstance" type guard
    if isinstance(val, str):
        # Type of ``val`` is narrowed to ``str``
        ...
    else:
        # Else, type of ``val`` is narrowed to ``float``.
        ...

Sometimes it would be convenient to use a user-defined boolean function as a type guard. Such a function should use TypeGuard[...] as its return type to alert static type checkers to this intention.

Using -> TypeGuard tells the static type checker that for a given function:

  1. The return value is a boolean.

  2. If the return value is True, the type of its argument is the type inside TypeGuard.

    例如:

    def is_str_list(val: List[object]) -> TypeGuard[List[str]]:
        '''Determines whether all objects in the list are strings'''
        return all(isinstance(x, str) for x in val)
    def func1(val: List[object]):
        if is_str_list(val):
            # Type of ``val`` is narrowed to ``List[str]``.
            print(" ".join(val))
        else:
            # Type of ``val`` remains as ``List[object]``.
            print("Not a list of strings!")

If is_str_list is a class or instance method, then the type in TypeGuard maps to the type of the second parameter after cls or self.

In short, the form def foo(arg: TypeA) -> TypeGuard[TypeB]: ..., means that if foo(arg) returns True, then arg narrows from TypeA to TypeB.

注解

TypeB need not be a narrower form of TypeA — it can even be a wider form. The main reason is to allow for things like narrowing List[object] to List[str] even though the latter is not a subtype of the former, since List is invariant. The responsibility of writing type-safe type guards is left to the user.

TypeGuard also works with type variables. For more information, see PEP 647 (User-Defined Type Guards).

3.10 新版功能.

构建泛型类型

以下内容是创建泛型类型的基石,但不在注解内使用。

class typing.Generic

用于泛型类型的抽象基类。

泛型类型一般通过继承含一个或多个类型变量的类实例进行声明。例如,泛型映射类型定义如下:

class Mapping(Generic[KT, VT]):
    def __getitem__(self, key: KT) -> VT:
        ...
        # Etc.

该类的用法如下:

X = TypeVar('X')
Y = TypeVar('Y')
def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y:
    try:
        return mapping[key]
    except KeyError:
        return default

class typing.TypeVar

类型变量。

用法:

T = TypeVar('T')  # Can be anything
A = TypeVar('A', str, bytes)  # Must be str or bytes

类型变量主要是为静态类型检查器提供支持,用于泛型类型与泛型函数定义的参数。有关泛型类型。泛型函数的写法如下:

def repeat(x: T, n: int) -> Sequence[T]:
    """Return a list containing n references to x."""
    return [x]*n
def longest(x: A, y: A) -> A:
    """Return the longest of two strings."""
    return x if len(x) >= len(y) else y

本质上,后例的签名重载了 (str, str) -> str(bytes, bytes) -> bytes。注意,参数是 str 子类的实例时,返回类型仍是纯 str

在运行时,isinstance(x, T) 会触发 TypeError 异常。一般而言,isinstance()issubclass() 不应与类型搭配使用。

通过 covariant=Truecontravariant=True 可以把类型变量标记为协变量或逆变量。详见 PEP 484。默认情况下,类型变量是不变量。类型变量还可以用 bound=<type> 指定上限。这里的意思是,(显式或隐式地)取代类型变量的实际类型必须是限定类型的子类,详见 PEP 484

class typing.ParamSpec(name, **, bound=None, covariant=False, contravariant=False*)

Parameter specification variable. A specialized version of type variables.

用法:

P = ParamSpec('P')

Parameter specification variables exist primarily for the benefit of static type checkers. They are used to forward the parameter types of one callable to another callable — a pattern commonly found in higher order functions and decorators. They are only valid when used in Concatenate, or as the first argument to Callable, or as parameters for user-defined Generics. See Generic for more information on generic types.

For example, to add basic logging to a function, one can create a decorator add_logging to log function calls. The parameter specification variable tells the type checker that the callable passed into the decorator and the new callable returned by it have inter-dependent type parameters:

from collections.abc import Callable
from typing import TypeVar, ParamSpec
import logging
T = TypeVar('T')
P = ParamSpec('P')
def add_logging(f: Callable[P, T]) -> Callable[P, T]:
    '''A type-safe decorator to add logging to a function.'''
    def inner(*args: P.args, **kwargs: P.kwargs) -> T:
        logging.info(f'{f.__name__} was called')
        return f(*args, **kwargs)
    return inner
@add_logging
def add_two(x: float, y: float) -> float:
    '''Add two numbers together.'''
    return x + y

Without ParamSpec, the simplest way to annotate this previously was to use a TypeVar with bound Callable[..., Any]. However this causes two problems:

  1. The type checker can’t type check the inner function because *args and **kwargs have to be typed Any.
  2. cast() may be required in the body of the add_logging decorator when returning the inner function, or the static type checker must be told to ignore the return inner.
  • args

  • kwargs

    Since ParamSpec captures both positional and keyword parameters, P.args and P.kwargs can be used to split a ParamSpec into its components. P.args represents the tuple of positional parameters in a given call and should only be used to annotate *args. P.kwargs represents the mapping of keyword parameters to their values in a given call, and should be only be used to annotate **kwargs. Both attributes require the annotated parameter to be in scope. At runtime, P.args and P.kwargs are instances respectively of ParamSpecArgs and ParamSpecKwargs.

Parameter specification variables created with covariant=True or contravariant=True can be used to declare covariant or contravariant generic types. The bound argument is also accepted, similar to TypeVar. However the actual semantics of these keywords are yet to be decided.

3.10 新版功能.

注解

Only parameter specification variables defined in global scope can be pickled.

参见

  • PEP 612 — Parameter Specification Variables (the PEP which introduced ParamSpec and Concatenate).
  • Callable and Concatenate.
typing.ParamSpecArgs
typing.ParamSpecKwargs

Arguments and keyword arguments attributes of a ParamSpec. The P.args attribute of a ParamSpec is an instance of ParamSpecArgs, and P.kwargs is an instance of ParamSpecKwargs. They are intended for runtime introspection and have no special meaning to static type checkers.

Calling get_origin() on either of these objects will return the original ParamSpec:

P = ParamSpec("P")
get_origin(P.args)  # returns P
get_origin(P.kwargs)  # returns P

3.10 新版功能.

typing.AnyStr

AnyStr 类型变量的定义为 AnyStr = TypeVar('AnyStr', str, bytes)

这里指的是,它可以接受任意同类字符串,但不支持混用不同类别的字符串。例如:

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
    return a + b
concat(u"foo", u"bar")  # Ok, output has type 'unicode'
concat(b"foo", b"bar")  # Ok, output has type 'bytes'
concat(u"foo", b"bar")  # Error, cannot mix unicode and bytes

class typing.Protocol(Generic)

Protocol 类的基类。Protocol 类的定义如下:

class Proto(Protocol):
    def meth(self) -> int:
        ...

这些类主要与静态类型检查器搭配使用,用来识别结构子类型(静态鸭子类型),例如:

class C:
    def meth(self) -> int:
        return 0
def func(x: Proto) -> int:
    return x.meth()
func(C())  # Passes static type check

详见 PEP 544。Protocol 类用 runtime_checkable() (见下文)装饰,忽略类型签名,仅检查给定属性是否存在,充当简要的运行时协议。

Protocol 类可以是泛型,例如:

class GenProto(Protocol[T]):
    def meth(self) -> T:
        ...

3.8 新版功能.

@``typing.runtime_checkable

用于把 Protocol 类标记为运行时协议。

该协议可以与 isinstance()issubclass() 一起使用。应用于非协议的类时,会触发 TypeError。该指令支持简易结构检查,与 collections.abcIterable 非常类似,只擅长做一件事。 例如:

@runtime_checkable
class Closable(Protocol):
    def close(self): ...
assert isinstance(open('/some/file'), Closable)

注解

runtime_checkable() will check only the presence of the required methods, not their type signatures. For example, ssl.SSLObject is a class, therefore it passes an issubclass() check against Callable. However, the ssl.SSLObject.__init__() method exists only to raise a TypeError with a more informative message, therefore making it impossible to call (instantiate) ssl.SSLObject.

3.8 新版功能.

其他特殊指令

这些特殊指令是声明类型的基石,但不在注解内使用。

class typing.NamedTuple

collections.namedtuple() 的类型版本。

用法:

class Employee(NamedTuple):
    name: str
    id: int

这相当于:

Employee = collections.namedtuple('Employee', ['name', 'id'])

为字段提供默认值,要在类体内赋值:

class Employee(NamedTuple):
    name: str
    id: int = 3
employee = Employee('Guido')
assert employee.id == 3

带默认值的字段必须在不带默认值的字段后面。

生成的类具有 __annotations__ 这个附加属性,提供了映射字段名与字段类型的字典。(字段名在 _fields 属性内,默认值在 _field_defaults 属性内,这两项都是命名元组 API 的组成部分。)

NamedTuple 子类也支持文档字符串与方法:

class Employee(NamedTuple):
    """Represents an employee."""
    name: str
    id: int = 3
    def __repr__(self) -> str:
        return f'<Employee {self.name}, id={self.id}>'

反向兼容用法:

Employee = NamedTuple('Employee', [('name', str), ('id', int)])

在 3.6 版更改: 添加了对 PEP 526 中变量注解句法的支持。

在 3.6.1 版更改: 添加了对默认值、方法、文档字符串的支持。

在 3.8 版更改: _field_types__annotations__ 属性现已使用常规字典,不再使用 OrderedDict 实例。

在 3.9 版更改: 移除了 _field_types 属性, 改用具有相同信息,但更标准的 __annotations__ 属性。

class typing.NewType(name, tp)

A helper class to indicate a distinct type to a typechecker, see NewType. At runtime it returns an object that returns its argument when called. Usage:

UserId = NewType('UserId', int)
first_user = UserId(1)

3.5.2 新版功能.

在 3.10 版更改: NewType is now a class rather than a function.

class typing.TypedDict(dict)

把类型提示添加至字典的特殊构造器。在运行时,它是纯 dict

TypedDict 声明一个字典类型,该类型预期所有实例都具有一组键集,其中,每个键都与对应类型的值关联。运行时不检查此预期,而是由类型检查器强制执行。用法如下:

class Point2D(TypedDict):
    x: int
    y: int
    label: str
a: Point2D = {'x': 1, 'y': 2, 'label': 'good'}  # OK
b: Point2D = {'z': 3, 'label': 'bad'}           # Fails type check
assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')

The type info for introspection can be accessed via Point2D.__annotations__, Point2D.__total__, Point2D.__required_keys__, and Point2D.__optional_keys__. To allow using this feature with older versions of Python that do not support PEP 526, TypedDict supports two additional equivalent syntactic forms:

Point2D = TypedDict('Point2D', x=int, y=int, label=str)
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})

By default, all keys must be present in a TypedDict. It is possible to override this by specifying totality. Usage:

class Point2D(TypedDict, total=False):
    x: int
    y: int

This means that a Point2D TypedDict can have any of the keys omitted. A type checker is only expected to support a literal False or True as the value of the total argument. True is the default, and makes all items defined in the class body required.

更多示例与 TypedDict 的详细规则,详见 PEP 589

3.8 新版功能.

泛型具象容器

对应的内置类型

class typing.Dict(dict, MutableMapping[KT, VT])

dict 的泛型版本。适用于注解返回类型。注解参数时,最好使用 Mapping 等抽象容器类型。

该类型用法如下:

def count_words(text: str) -> Dict[str, int]:
    ...

3.9 版后已移除: builtins.dict 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.List(list, MutableSequence[T])

list 的泛型版本。适用于注解返回类型。注解参数时,最好使用 SequenceIterable 等抽象容器类型。

该类型用法如下:

T = TypeVar('T', int, float)
def vec2(x: T, y: T) -> List[T]:
    return [x, y]
def keep_positives(vector: Sequence[T]) -> List[T]:
    return [item for item in vector if item > 0]

3.9 版后已移除: builtins.list 现已支持 []。详见 PEP 585 与 Generic Alias Type。

class typing.Set(set, MutableSet[T])

builtins.set 的泛型版本。适用于注解返回类型。注解参数时,最好使用 AbstractSet 等抽象容器类型。

3.9 版后已移除: builtins.set 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.FrozenSet(frozenset, AbstractSet[T_co])

builtins.frozenset 的泛型版本。

3.9 版后已移除: builtins.frozenset 现已支持 []。详见 PEP 585 和 Generic Alias Type。

注解

Tuple 是一种特殊形式。

collections 对应类型

class typing.DefaultDict(collections.defaultdict, MutableMapping[KT, VT])

collections.defaultdict 的泛型版本。

3.5.2 新版功能.

3.9 版后已移除: collections.defaultdict 现已支持 []。详见 PEP 585 与 Generic Alias Type。

class typing.OrderedDict(collections.OrderedDict, MutableMapping[KT, VT])

collections.OrderedDict 的泛型版本。

3.7.2 新版功能.

3.9 版后已移除: collections.OrderedDict 现已支持 []。详见 PEP 585 与 Generic Alias Type。

class typing.ChainMap(collections.ChainMap, MutableMapping[KT, VT])

collections.ChainMap 的泛型版本。

3.5.4 新版功能.

3.6.1 新版功能.

3.9 版后已移除: collections.ChainMap 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Counter(collections.Counter, Dict[T, int])

collections.Counter 的泛型版本。

3.5.4 新版功能.

3.6.1 新版功能.

3.9 版后已移除: collections.Counter 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Deque(deque, MutableSequence[T])

collections.deque 的泛型版本。

3.5.4 新版功能.

3.6.1 新版功能.

3.9 版后已移除: collections.deque 现已支持 []。详见 PEP 585 和 Generic Alias Type。

其他具象类型

class typing.IO

class typing.TextIO

class typing.BinaryIO

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

Deprecated since version 3.8, will be removed in version 3.12: The typing.io namespace is deprecated and will be removed. These types should be directly imported from typing instead.

class typing.Pattern

class typing.Match

这些类型对应的是从 re.compile()re.match() 返回的类型。 这些类型(及相应的函数)是 AnyStr 中的泛型并可通过编写 Pattern[str], Pattern[bytes], Match[str]Match[bytes] 来具体指定。

Deprecated since version 3.8, will be removed in version 3.12: The typing.re namespace is deprecated and will be removed. These types should be directly imported from typing instead.

3.9 版后已移除: re 模块中的 PatternMatch 类现已支持 []。详见 PEP 585 与 Generic Alias Type。

class typing.Text

Textstr 的别名。提供了对 Python 2 代码的向下兼容:Python 2 中,Textunicode 的别名。

使用 Text 时,值中必须包含 unicode 字符串,以兼容 Python 2 和 Python 3:

def add_unicode_checkmark(text: Text) -> Text:
    return text + u' \u2713'

3.5.2 新版功能.

抽象基类

collections.abc 对应的容器

class typing.AbstractSet(Sized, Collection[T_co])

collections.abc.Set 的泛型版本。

3.9 版后已移除: collections.abc.Set 现已支持 []。详见 PEP 585 与 Generic Alias Type。

class typing.ByteString(Sequence[int])

collections.abc.ByteString 的泛型版本。

该类型代表了 bytesbytearraymemoryview 等字节序列类型。

作为该类型的简称,bytes 可用于标注上述任意类型的参数。

3.9 版后已移除: collections.abc.ByteString 现已支持 []。详见 PEP 585 与 Generic Alias Type。

class typing.Collection(Sized, Iterable[T_co], Container[T_co])

collections.abc.Collection 的泛型版本。

3.6.0 新版功能.

3.9 版后已移除: collections.abc.Collection 现已支持 []。详见 PEP 585 与 Generic Alias Type。

class typing.Container(Generic[T_co])

collections.abc.Container 的泛型版本。

3.9 版后已移除: collections.abc.Container 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.ItemsView(MappingView, Generic[KT_co, VT_co])

collections.abc.ItemsView 的泛型版本。

3.9 版后已移除: collections.abc.ItemsView 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.KeysView(MappingView[KT_co], AbstractSet[KT_co])

collections.abc.KeysView 的泛型版本。

3.9 版后已移除: collections.abc.KeysView 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Mapping(Sized, Collection[KT], Generic[VT_co])

collections.abc.Mapping 的泛型版本。用法如下:

def get_position_in_index(word_list: Mapping[str, int], word: str) -> int:
    return word_list[word]

3.9 版后已移除: collections.abc.Mapping 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.MappingView(Sized, Iterable[T_co])

collections.abc.MappingView 的泛型版本。

3.9 版后已移除: collections.abc.MappingView 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.MutableMapping(Mapping[KT, VT])

collections.abc.MutableMapping 的泛型版本。

3.9 版后已移除: collections.abc.MutableMapping 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.MutableSequence(Sequence[T])

collections.abc.MutableSequence 的泛型版本。

3.9 版后已移除: collections.abc.MutableSequence 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.MutableSet(AbstractSet[T])

collections.abc.MutableSet 的泛型版本。

3.9 版后已移除: collections.abc.MutableSet 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Sequence(Reversible[T_co], Collection[T_co])

collections.abc.Sequence 的泛型版本。

3.9 版后已移除: collections.abc.Sequence 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.ValuesView(MappingView[VT_co])

collections.abc.ValuesView 的泛型版本。

3.9 版后已移除: collections.abc.ValuesView 现已支持 []。详见 PEP 585 和 Generic Alias Type。

collections.abc 对应的其他类型

class typing.Iterable(Generic[T_co])

collections.abc.Iterable 的泛型版本。

3.9 版后已移除: collections.abc.Iterable 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Iterator(Iterable[T_co])

collections.abc.Iterator 的泛型版本。

3.9 版后已移除: collections.abc.Iterator 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Generator(Iterator[T_co], Generic[T_co, T_contra, V_co])

生成器可以由泛型类型 Generator[YieldType, SendType, ReturnType] 注解。例如:

def echo_round() -> Generator[int, float, str]:
    sent = yield 0
    while sent >= 0:
        sent = yield round(sent)
    return 'Done'

注意,与 typing 模块里的其他泛型不同, GeneratorSendType 属于逆变行为,不是协变行为,也是不变行为。

如果生成器只产生值,可将 SendTypeReturnType 设为 None

def infinite_stream(start: int) -> Generator[int, None, None]:
    while True:
        yield start
        start += 1

此外,还可以把生成器的返回类型注解为 Iterable[YieldType]Iterator[YieldType]

def infinite_stream(start: int) -> Iterator[int]:
    while True:
        yield start
        start += 1

3.9 版后已移除: collections.abc.Generator 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Hashable

collections.abc.Hashable 的别名。

class typing.Reversible(Iterable[T_co])

collections.abc.Reversible 的泛型版本。

3.9 版后已移除: collections.abc.Reversible 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Sized

collections.abc.Sized 的别名。

异步编程

class typing.Coroutine(Awaitable[V_co], Generic[T_co, T_contra, V_co])

collections.abc.Coroutine 的泛型版本。类型变量的差异和顺序与 Generator 的内容相对应,例如:

from collections.abc import Coroutine
c = None # type: Coroutine[list[str], str, int]
...
x = c.send('hi') # type: list[str]
async def bar() -> None:
    x = await c # type: int

3.5.3 新版功能.

3.9 版后已移除: collections.abc.Coroutine 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.AsyncGenerator(AsyncIterator[T_co], Generic[T_co, T_contra])

异步生成器可由泛型类型 AsyncGenerator[YieldType, SendType] 注解。例如:

async def echo_round() -> AsyncGenerator[int, float]:
    sent = yield 0
    while sent >= 0.0:
        rounded = await round(sent)
        sent = yield rounded

与常规生成器不同,异步生成器不能返回值,因此没有 ReturnType 类型参数。 与 Generator 类似,SendType 也属于逆变行为。

如果生成器只产生值,可将 SendType 设置为 None

async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
    while True:
        yield start
        start = await increment(start)

此外,可用 AsyncIterable[YieldType]AsyncIterator[YieldType] 注解生成器的返回类型:

async def infinite_stream(start: int) -> AsyncIterator[int]:
    while True:
        yield start
        start = await increment(start)

3.6.1 新版功能.

3.9 版后已移除: collections.abc.AsyncGenerator 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.AsyncIterable(Generic[T_co])

collections.abc.AsyncIterable 的泛型版本。

3.5.2 新版功能.

3.9 版后已移除: collections.abc.AsyncIterable 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.AsyncIterator(AsyncIterable[T_co])

collections.abc.AsyncIterator 的泛型版本。

3.5.2 新版功能.

3.9 版后已移除: collections.abc.AsyncIterator 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.Awaitable(Generic[T_co])

collections.abc.Awaitable 的泛型版本。

3.5.2 新版功能.

3.9 版后已移除: collections.abc.Awaitable 现已支持 []。详见 PEP 585 和 Generic Alias Type。

上下文管理器类型

class typing.ContextManager(Generic[T_co])

contextlib.AbstractContextManager 的泛型版本。

3.5.4 新版功能.

3.6.0 新版功能.

3.9 版后已移除: contextlib.AbstractContextManager 现已支持 []。详见 PEP 585 和 Generic Alias Type。

class typing.AsyncContextManager(Generic[T_co])

contextlib.AbstractAsyncContextManager 的泛型版本。

3.5.4 新版功能.

3.6.2 新版功能.

3.9 版后已移除: contextlib.AbstractAsyncContextManager 现已支持 []。详见 PEP 585 和 Generic Alias Type。

协议

这些协议由 runtime_checkable() 装饰。

class typing.SupportsAbs

含抽象方法 __abs__ 的抽象基类,是其返回类型里的协变量。

class typing.SupportsBytes

含抽象方法 __bytes__ 的抽象基类。

class typing.SupportsComplex

含抽象方法 __complex__ 的抽象基类。

class typing.SupportsFloat

含抽象方法 __float__ 的抽象基类。

class typing.SupportsIndex

含抽象方法 __index__ 的抽象基类。

3.8 新版功能.

class typing.SupportsInt

含抽象方法 __int__ 的抽象基类。

class typing.SupportsRound

含抽象方法 __round__ 的抽象基类,是其返回类型的协变量。

函数与装饰器

typing.cast(typ, val)

把值强制转换为类型。

不变更返回值。对类型检查器而言,代表了返回值具有指定的类型,但运行时故意不做任何检查(以便让检查速度尽量快)。

@``typing.overload

@overload 装饰器可以修饰支持多个不同参数类型组合的函数或方法。@overload - 装饰定义的系列必须紧跟一个非 @overload-装饰定义(用于同一个函数/方法)。@overload-装饰定义仅是为了协助类型检查器, 因为该装饰器会被非 @overload-装饰定义覆盖,后者用于运行时,而且会被类型检查器忽略。在运行时直接调用 @overload 装饰的函数会触发 NotImplementedError。下面的重载示例给出了比联合类型或类型变量更精准的类型:

@overload
def process(response: None) -> None:
    ...
@overload
def process(response: int) -> tuple[int, str]:
    ...
@overload
def process(response: bytes) -> str:
    ...
def process(response):
    <actual implementation>

详见 PEP 484,与其他类型语义进行对比。

@``typing.final

告知类型检查器被装饰的方法不能被覆盖,且被装饰的类不能作为子类的装饰器,例如:

class Base:
    @final
    def done(self) -> None:
        ...
class Sub(Base):
    def done(self) -> None:  # Error reported by type checker
          ...
@final
class Leaf:
    ...
class Other(Leaf):  # Error reported by type checker
    ...

这些属性没有运行时检查。详见 PEP 591

3.8 新版功能.

@``typing.no_type_check

标明注解不是类型提示的装饰器。

用作类或函数的 decorator。用于类时,递归地应用于该类中定义的所有方法,(但不影响超类或子类中定义的方法)。

本方法可直接修改函数。

@``typing.no_type_check_decorator

让其他装饰器具有 no_type_check() 效果的装饰器。

本装饰器用 no_type_check() 里的装饰函数打包其他装饰器。

@``typing.type_check_only

标记类或函数内不可用于运行时的装饰器。

在运行时,该装饰器本身不可用。实现返回的是私有类实例时,它主要是用于标记在类型存根文件中定义的类。

@type_check_only
class Response:  # private or not available at runtime
    code: int
    def get_header(self, name: str) -> str: ...
def fetch_response() -> Response: ...

注意,建议不要返回私有类实例,最好将之设为公共类。

内省辅助器

typing.get_type_hints(obj, globalns=None, localns=None, include_extras=False)

返回函数、方法、模块、类对象的类型提示的字典。

一般情况下,与 obj.__annotations__ 相同。此外,可通过在 globalslocals 命名空间里进行评估,以此来处理编码为字符串字面量的前向引用。如有需要,在默认值设置为 None 时,可为函数或方法注解添加 Optional[t]。对于类 C,则返回由所有 __annotations__C.__mro__ 逆序合并而成的字典。

本函数以递归地方式用 T 替换所有 Annotated[T, ...], 除非将 include_extras 的值设置为 True 。例如:

class Student(NamedTuple):
    name: Annotated[str, 'some marker']
get_type_hints(Student) == {'name': str}
get_type_hints(Student, include_extras=False) == {'name': str}
get_type_hints(Student, include_extras=True) == {
    'name': Annotated[str, 'some marker']
}

注解

get_type_hints() does not work with imported type aliases that include forward references. Enabling postponed evaluation of annotations (PEP 563) may remove the need for most forward references.

在 3.9 版更改: PEP 593 的组成部分,添加了 include_extras 参数。

typing.get_args(tp)

typing.get_origin(tp)

为泛型类型与特殊类型形式提供了基本的内省功能。

For a typing object of the form X[Y, Z, ...] these functions return X and (Y, Z, ...). If X is a generic alias for a builtin or collections class, it gets normalized to the original class. If X is a union or Literal contained in another generic type, the order of (Y, Z, ...) may be different from the order of the original arguments [Y, Z, ...] due to type caching. For unsupported objects return None and () correspondingly. Examples:

assert get_origin(Dict[str, int]) is dict
assert get_args(Dict[int, str]) == (int, str)
assert get_origin(Union[int, str]) is Union
assert get_args(Union[int, str]) == (int, str)

3.8 新版功能.

typing.is_typeddict(tp)

Check if a type is a TypedDict.

例如:

class Film(TypedDict):
    title: str
    year: int
is_typeddict(Film)  # => True
is_typeddict(list | str)  # => False

3.10 新版功能.

class typing.ForwardRef

用于字符串前向引用的内部类型表示的类。 例如,List["SomeClass"] 会被隐式转换为 List[ForwardRef("SomeClass")]。 这个类不应由用户来实例化,但可以由内省工具使用。

注解

PEP 585 泛型类型例如 list["SomeClass"] 将不会被隐式地转换为 list[ForwardRef("SomeClass")] 因而将不会自动解析为 list[SomeClass]

3.7.4 新版功能.

常量

typing.TYPE_CHECKING

被第三方静态类型检查器假定为 True 的特殊常量。 在运行时为 False。 用法如下:

if TYPE_CHECKING:
    import expensive_mod
def fun(arg: 'expensive_mod.SomeType') -> None:
    local_var: expensive_mod.AnotherType = other_fun()

第一个类型注解必须用引号标注,才能把它当作“前向引用”,从而在解释器运行时中隐藏 expensive_mod 引用。局部变量的类型注释不会被评估,因此,第二个注解不需要用引号引起来。

注解

Python 3.7 或更高版本中使用 from __future__ import 时,函数定义时不处理注解, 而是把注解当作字符串存在 __annotations__ 里,这样就不必为注解使用引号。(详见 PEP 563)。

3.5.2 新版功能.

pydoc —- 文档生成器和在线帮助系统

源代码: Lib/pydoc.py


pydoc 模块会根据 Python 模块来自动生成文档。 生成的文档可在控制台中显示为文本页面,提供给 Web 浏览器访问或者保存为 HTML 文件。

对于模块、类、函数和方法,显示的文档内容取自文档字符串(即 __doc__ 属性),并会递归地从其带文档的成员中获取。 如果没有文档字符串,pydoc 会尝试从类、函数或方法定义上方,或是模块顶部的注释行段落获取

内置函数 help() 会发起调用交互式解释器的在线帮助系统,该系统使用 pydoc 在终端上生成文本形式的文档内容。 同样的文本文档也可以在 Python 解释器以外通过在操作系统的命令提示符下以脚本方式运行 pydoc 来查看。 例如,运行

pydoc sys

在终端提示符下将通过 sys 模块显示文档内容,其样式类似于 Unix man 命令所显示的指南页面。 pydoc 的参数可以为函数、模块、包,或带点号的对模块中的类、方法或函数以及包中的模块的引用。 如果传给 pydoc 的参数像是一个路径(即包含所在操作系统的路径分隔符,例如 Unix 的正斜杠),并且其指向一个现有的 Python 源文件,则会为该文件生成文档内容。

注解

为了找到对象及其文档内容,pydoc 会导入文档所在的模块。 因此,任何模块层级的代码都将被执行。 请使用 if __name__ == '__main__': 语句来确保一个文件的特定代码仅在作为脚本被发起调用时执行而不是在被导入时执行。

当打印输出到控制台时,pydoc 会尝试对输出进行分页以方便阅读。 如果设置了 PAGER 环境变量,pydoc 将使用该变量值作为分页程序。

在参数前指定 -w 旗标将把 HTML 文档写入到当前目录下的一个文件中,而不是在控制台中显示文本。

在参数前指定 -k 旗标将在全部可用模块的提要行中搜索参数所给定的关键字,具体方式同样类似于 Unix man 命令。 模块的提要行就是其文档字符串的第一行。

你还可以使用 pydoc 在本机上启动一个 HTTP 服务器并向来访的 Web 浏览器展示文档。 pydoc -p 1234 将在 1234 端口上启动 HTTP 服务器,允许在你使用 Web 浏览器通过 http://localhost:1234/ 来浏览文档内容。 指定 0 作为端口号将任意选择一个未使用的端口。

pydoc -n 将启动在给定主机名上执行监听的服务。 默认主机名为 ‘localhost’ 但如果你希望能从其他机器搜索该服务器,你可能会想要改变服务器所响应的主机名。 在开发阶段此特性会特别有用,因为这样你将能在一个容器中运行 pydoc。

pydoc -b 将启动服务并额外打开一个 Web 浏览器访问模块索引页。 所发布的每个页面顶端都带有导航栏,你可以点击 Get 获取特定条目的帮助,点击 Search 在所有模块的提要行中搜索特定关键词,或是点击 Module index, TopicsKeywords 前往相应的页面。

pydoc 生成文档内容时,它会使用当前环境和路径来定位模块。 因此,发起调用 pydoc spam 得到的文档版本会与你启动 Python 解释器并输入 import spam 时得到的模块版本完全相同。

核心模块的模块文档位置对应于 https://docs.python.org/X.Y/library/ 其中 XY 是 Python 解释器的主要版本号和小版本号。 这可通过设置 PYTHONDOCS 环境变量来重载为指向不同的 URL 或包含 Library Reference Manual 页面的本地目录。

在 3.2 版更改: 添加 -b 选项。

在 3.3 版更改: 命令行选项 -g 已经移除。

在 3.4 版更改: pydoc 现在会使用 inspect.signature() 而非 inspect.getfullargspec() 来从可调用对象中提取签名信息。

在 3.7 版更改: 添加 -n 选项。

Python 开发模式

doctest —- 测试交互性的Python示例

源代码 Lib/doctest.py


doctest 模块寻找像Python交互式代码的文本,然后执行这些代码来确保它们的确就像展示的那样正确运行,有许多方法来使用doctest:

  • 通过验证所有交互式示例仍然按照记录的方式工作,以此来检查模块的文档字符串是否是最新的。
  • 通过验证来自一个测试文件或一个测试对象的交互式示例按预期工作,来进行回归测试。
  • To write tutorial documentation for a package, liberally illustrated with input-output examples. Depending on whether the examples or the expository text are emphasized, this has the flavor of “literate testing” or “executable documentation”.

doctest

unittest —- 单元测试框架

源代码: Lib/unittest/init.py

2to3 - 自动将 Python 2 代码转为 Python 3 代码

2to3 是一个 Python 程序,它可以读取 Python 2.x 的源代码并使用一系列的 修复器 来将其转换为合法的 Python 3.x 代码。 标准库已包含了丰富的修复器,这足以处理几乎所有代码。 不过 2to3 的支持库 lib2to3 是一个很灵活通用的库,所以还可以编写你自己的 2to3 修复器。

使用 2to3

2to3 通常会作为脚本和 Python 解释器一起安装,你可以在 Python 根目录的 Tools/scripts 文件夹下找到它。

2to3 的基本调用参数是一个需要转换的文件或目录列表。对于目录,会递归地寻找其中的 Python 源码。

这里有一个 Python 2.x 的源码文件,example.py

def greet(name):
    print "Hello, {0}!".format(name)
print "What's your name?"
name = raw_input()
greet(name)

它可以在命令行中使用 2to3 转换成 Python 3.x 版本的代码:

$ 2to3 example.py

这个命令会打印出和源文件的区别。通过传入 -w 参数,2to3 也可以把需要的修改写回到原文件中(除非传入了 -n 参数,否则会为原始文件创建一个副本):

$ 2to3 -w example.py

在转换完成后,example.py 看起来像是这样:

def greet(name):
    print("Hello, {0}!".format(name))
print("What's your name?")
name = input()
greet(name)

注释和缩进都会在转换过程中保持不变。

默认情况下,2to3 会执行 预定义修复器 的集合。使用 -l 参数可以列出所有可用的修复器。使用 -f 参数可以明确指定需要使用的修复器集合。而使用 -x 参数则可以明确指定不使用的修复器。下面的例子会只使用 importshas_key 修复器运行:

$ 2to3 -f imports -f has_key example.py

这个命令会执行除了 apply 之外的所有修复器:

$ 2to3 -x apply example.py

有一些修复器是需要 显式指定 的,它们默认不会执行,必须在命令行中列出才会执行。比如下面的例子,除了默认的修复器以外,还会执行 idioms 修复器:

$ 2to3 -f all -f idioms example.py

注意这里使用 all 来启用所有默认的修复器。

有些情况下 2to3 会找到源码中有一些需要修改,但是无法自动处理的代码。在这种情况下,2to3 会在差异处下面打印一个警告信息。你应该定位到相应的代码并对其进行修改,以使其兼容 Python 3.x。

2to3 也可以重构 doctests。使用 -d 开启这个模式。需要注意只有 doctests 会被重构。这种模式下不需要文件是合法的 Python 代码。举例来说,reST 文档中类似 doctests 的示例也可以使用这个选项进行重构。

-v 选项可以输出更多转换程序的详细信息。

由于某些 print 语句可被解读为函数调用或是语句,2to3 并不总能读取包含 print 函数的文件。 当 2to3 检测到存在 from __future__ import print_function 编译器指令时,会修改其内部语法将 print() 解读为函数。 这一变动也可以使用 -p 旗标手动开启。 使用 -p 来为已转换过 print 语句的代码运行修复器。 也可以使用 -eexec() 解读为函数。

-o--output-dir 选项可以指定将转换后的文件写入其他目录中。由于这种情况下不会覆写原始文件,所以创建副本文件毫无意义,因此也需要使用 -n 选项来禁用创建副本。

3.2.3 新版功能: 增加了 -o 选项。

-W--write-unchanged-files 选项用来告诉 2to3 始终需要输出文件,即使没有任何改动。这在使用 -o 参数时十分有用,这样就可以将整个 Python 源码包完整地转换到另一个目录。这个选项隐含了 -w 选项,否则等于没有作用。

3.2.3 新版功能: 增加了 -W 选项。

--add-suffix 选项接受一个字符串,用来作为后缀附加在输出文件名后面的后面。由于写入的文件名与原始文件不同,所以没有必要创建副本,因此 -n 选项也是必要的。举个例子:

$ 2to3 -n -W --add-suffix=3 example.py

这样会把转换后的文件写入 example.py3 文件。

3.2.3 新版功能: 增加了 --add-suffix 选项。

将整个项目从一个目录转换到另一个目录可以用这样的命令:

$ 2to3 --output-dir=python3-version/mycode -W -n python2-version/mycode

修复器

转换代码的每一个步骤都封装在修复器中。可以使用 2to3 -l 来列出可用的修复器。之前已经提到,每个修复器都可以独立地打开或是关闭。下面会对各个修复器做更详细的描述。

apply

移除对 apply() 的使用,举例来说,apply(function, *args, **kwargs) 会被转换成 function(*args, **kwargs)

asserts

将已弃用的 unittest 方法替换为正确的。

failUnlessEqual(a, b) assertEqual(a, b)
assertEquals(a, b) assertEqual(a, b)
failIfEqual(a, b) assertNotEqual(a, b)
assertNotEquals(a, b) assertNotEqual(a, b)
failUnless(a) assertTrue(a)
assert_(a) assertTrue(a)
failIf(a) assertFalse(a)
failUnlessRaises(exc, cal) assertRaises(exc, cal)
failUnlessAlmostEqual(a, b) assertAlmostEqual(a, b)
assertAlmostEquals(a, b) assertAlmostEqual(a, b)
failIfAlmostEqual(a, b) assertNotAlmostEqual(a, b)
assertNotAlmostEquals(a, b) assertNotAlmostEqual(a, b)
basestring

basestring 转换为 str

buffer

buffer 转换为 memoryview。这个修复器是可选的,因为 memoryview API 和 buffer 很相似,但不完全一样。

dict

修复字典迭代方法。dict.iteritems() 会转换成 dict.items()dict.iterkeys() 会转换成 dict.keys()dict.itervalues() 会转换成 dict.values()。类似的,dict.viewitems()dict.viewkeys()dict.viewvalues() 会分别转换成 dict.items()dict.keys()dict.values()。另外也会将原有的 dict.items()dict.keys()dict.values() 方法调用用 list 包装一层。

except

except X, T 转换为 except X as T

exec

exec 语句转换为 exec() 函数调用。

execfile

移除 execfile() 的使用。execfile() 的实参会使用 open()compile()exec() 包装。

exitfunc

将对 sys.exitfunc 的赋值改为使用 atexit 模块代替。

filter

filter() 函数用 list 包装一层。

funcattrs

修复已经重命名的函数属性。比如 my_function.func_closure 会被转换为 my_function.__closure__

future

移除 from __future__ import new_feature 语句。

getcwdu

os.getcwdu() 重命名为 os.getcwd()

has_key

dict.has_key(key) 转换为 key in dict

idioms

这是一个可选的修复器,会进行多种转换,将 Python 代码变成更加常见的写法。类似 type(x) is SomeClasstype(x) == SomeClass 的类型对比会被转换成 isinstance(x, SomeClass)while 1 转换成 while True。这个修复器还会在合适的地方使用 sorted() 函数。举个例子,这样的代码块:

L = list(some_iterable)L.sort()

会被转换为:

L = sorted(some_iterable)
import

检测 sibling imports,并将其转换成相对 import。

imports

处理标准库模块的重命名。

imports2

处理标准库中其他模块的重命名。这个修复器由于一些技术上的限制,因此和 imports 拆分开了。

input

input(prompt) 转换为 eval(input(prompt))

intern

intern() 转换为 sys.intern()

isinstance

修复 isinstance() 函数第二个实参中重复的类型。举例来说,isinstance(x, (int, int)) 会转换为 isinstance(x, int), isinstance(x, (int, float, int)) 会转换为 isinstance(x, (int, float))

itertools_imports

移除 itertools.ifilter()itertools.izip() 以及 itertools.imap() 的 import。对 itertools.ifilterfalse() 的 import 也会替换成 itertools.filterfalse()

itertools

修改 itertools.ifilter()itertools.izip()itertools.imap() 的调用为对应的内建实现。itertools.ifilterfalse() 会替换成 itertools.filterfalse()

long

long 重命名为 int

map

list 包装 map()。同时也会将 map(None, x) 替换为 list(x)。使用 from future_builtins import map 禁用这个修复器。

metaclass

将老的元类语法(类体中的 __metaclass__ = Meta)替换为新的(class X(metaclass=Meta))。

methodattrs

修复老的方法属性名。例如 meth.im_func 会被转换为 meth.__func__

ne

转换老的不等语法,将 <> 转为 !=

next

将迭代器的 next() 方法调用转为 next() 函数。也会将 next() 方法重命名为 __next__()

nonzero

__nonzero__() 转换为 __bool__()

numliterals

将八进制字面量转为新的语法。

operator

operator 模块中的许多方法调用转为其他的等效函数调用。如果有需要,会添加适当的 import 语句,比如 import collections.abc。有以下转换映射:

operator.isCallable(obj) callable(obj)
operator.sequenceIncludes(obj) operator.contains(obj)
operator.isSequenceType(obj) isinstance(obj, collections.abc.Sequence)
operator.isMappingType(obj) isinstance(obj, collections.abc.Mapping)
operator.isNumberType(obj) isinstance(obj, numbers.Number)
operator.repeat(obj, n) operator.mul(obj, n)
operator.irepeat(obj, n) operator.imul(obj, n)
paren

在列表生成式中增加必须的括号。例如将 [x for x in 1, 2] 转换为 [x for x in (1, 2)]

print

print 语句转换为 print() 函数。

raise

raise E, V 转换为 raise E(V),将 raise E, V, T 转换为 raise E(V).with_traceback(T)。如果 E 是元组,这样的转换是不正确的,因为用元组代替异常的做法在 3.0 中已经移除了。

raw_input

raw_input() 转换为 input()

reduce

reduce() 转换为 functools.reduce()

reload

reload() 转换为 importlib.reload()

renames

sys.maxint 转换为 sys.maxsize

repr

将反引号 repr 表达式替换为 repr() 函数。

set_literal

set 构造函数替换为 set literals 写法。这个修复器是可选的。

standarderror

StandardError 重命名为 Exception

sys_exc

将弃用的 sys.exc_valuesys.exc_typesys.exc_traceback 替换为 sys.exc_info() 的用法。

throw

修复生成器的 throw() 方法的 API 变更。

tuple_params

移除隐式的元组参数解包。这个修复器会插入临时变量。

types

修复 type 模块中一些成员的移除引起的代码问题。

unicode

unicode 重命名为 str

urllib

urlliburllib2 重命名为 urllib 包。

ws_comma

移除逗号分隔的元素之间多余的空白。这个修复器是可选的。

xrange

xrange() 重命名为 range(),并用 list 包装原有的 range()

xreadlines

for x in file.xreadlines() 转换为 for x in file

zip

list 包装 zip()。如果使用了 from future_builtins import zip 的话会禁用。

lib2to3 —— 2to3 支持库

源代码: Lib/lib2to3/


Deprecated since version 3.11, will be removed in version 3.13: Python 3.9 switched to a PEG parser (see PEP 617) while lib2to3 is using a less flexible LL(1) parser. Python 3.10 includes new language syntax that is not parsable by lib2to3’s LL(1) parser (see PEP 634). The lib2to3 module was marked pending for deprecation in Python 3.9 (raising PendingDeprecationWarning on import) and fully deprecated in Python 3.11 (raising DeprecationWarning). It will be removed from the standard library in Python 3.13. Consider third-party alternatives such as LibCST or parso.

注解

lib2to3 API 并不稳定,并可能在未来大幅修改。

test —- Python回归测试包

调试和分析

这些库可以帮助你进行 Python 开发:调试器使你能够逐步执行代码,分析堆栈帧并设置中断点等等,性能分析器可以运行代码并为你提供执行时间的详细数据,使你能够找出你的程序中的瓶颈。 审计事件提供运行时行为的可见性,如果没有此工具则需要进行侵入式调试或修补。

审计事件表

下表包含了在整个 CPython 运行时和标准库中由 sys.audit()PySys_Audit() 调用所引发的全部事件。 这些调用是在 3.8.0 或更高版本中添加了 (参见 PEP 578)。

请参阅 sys.addaudithook()PySys_AddAuditHook() 了解有关处理这些事件的详细信息。

CPython implementation detail: 此表是根据 CPython 文档生成的,可能无法表示其他实现所引发的事件。 请参阅你的运行时专属的文档了解实际引发的事件。

Audit event Arguments References
array.new typecode, initializer [1]
builtins.breakpoint breakpointhook [1]
builtins.id id [1]
builtins.input prompt [1]
builtins.input/result result [1]
code.new code, filename, name, argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize, flags [1]
compile source, filename [1]
cpython.PyInterpreterState_Clear [1]
cpython.PyInterpreterState_New [1]
cpython._PySys_ClearAuditHooks [1]
cpython.run_command command [1]
cpython.run_file filename [1]
cpython.run_interactivehook hook [1]
cpython.run_module module-name [1]
cpython.run_startup filename [1]
cpython.run_stdin [1]
ctypes.addressof obj [1]
ctypes.call_function func_pointer, arguments [1]
ctypes.cdata address [1]
ctypes.cdata/buffer pointer, size, offset [1][2]
ctypes.create_string_buffer init, size [1]
ctypes.create_unicode_buffer init, size [1]
ctypes.dlopen name [1]
ctypes.dlsym library, name [1]
ctypes.dlsym/handle handle, name [1]
ctypes.get_errno [1]
ctypes.get_last_error [1]
ctypes.seh_exception code [1]
ctypes.set_errno errno [1]
ctypes.set_last_error error [1]
ctypes.string_at address, size [1]
ctypes.wstring_at address, size [1]
ensurepip.bootstrap root [1]
exec code_object [1][2]
fcntl.fcntl fd, cmd, arg [1]
fcntl.flock fd, operation [1]
fcntl.ioctl fd, request, arg [1]
fcntl.lockf fd, cmd, len, start, whence [1]
ftplib.connect self, host, port [1]
ftplib.sendcmd self, cmd [1][2]
function.new code [1]
gc.get_objects generation [1]
gc.get_referents objs [1]
gc.get_referrers objs [1]
glob.glob pathname, recursive [1][2]
glob.glob/2 pathname, recursive, root_dir, dir_fd [1][2]
http.client.connect self, host, port [1]
http.client.send self, data [1]
imaplib.open self, host, port [1]
imaplib.send self, data [1]
import module, filename, sys.path, sys.meta_path, sys.path_hooks [1]
marshal.dumps value, version [1]
marshal.load [1]
marshal.loads bytes [1]
mmap.new fileno, length, access, offset [1]
msvcrt.get_osfhandle fd [1]
msvcrt.locking fd, mode, nbytes [1]
msvcrt.open_osfhandle handle, flags [1]
nntplib.connect self, host, port [1][2]
nntplib.putline self, line [1][2]
object.delattr obj, name [1]
object.getattr obj, name [1]
object.setattr obj, name, value [1]
open path, mode, flags [1][2][3]
os.add_dll_directory path [1]
os.chdir path [1][2]
os.chflags path, flags [1][2]
os.chmod path, mode, dir_fd [1][2][3]
os.chown path, uid, gid, dir_fd [1][2][3]
os.exec path, args, env [1]
os.fork [1]
os.forkpty [1]
os.fwalk top, topdown, onerror, follow_symlinks, dir_fd [1]
os.getxattr path, attribute [1]
os.kill pid, sig [1]
os.killpg pgid, sig [1]
os.link src, dst, src_dir_fd, dst_dir_fd [1]
os.listdir path [1]
os.listxattr path [1]
os.lockf fd, cmd, len [1]
os.mkdir path, mode, dir_fd [1][2]
os.posix_spawn path, argv, env [1][2]
os.putenv key, value [1]
os.remove path, dir_fd [1][2][3]
os.removexattr path, attribute [1]
os.rename src, dst, src_dir_fd, dst_dir_fd [1][2][3]
os.rmdir path, dir_fd [1]
os.scandir path [1]
os.setxattr path, attribute, value, flags [1]
os.spawn mode, path, args, env [1]
os.startfile path, operation [1]
os.startfile/2 path, operation, arguments, cwd, show_cmd [1]
os.symlink src, dst, dir_fd [1]
os.system command [1]
os.truncate fd, length [1][2]
os.unsetenv key [1]
os.utime path, times, ns, dir_fd [1]
os.walk top, topdown, onerror, followlinks [1]
pathlib.Path.glob self, pattern [1]
pathlib.Path.rglob self, pattern [1]
pdb.Pdb [1]
pickle.find_class module, name [1]
poplib.connect self, host, port [1][2]
poplib.putline self, line [1][2]
pty.spawn argv [1]
resource.prlimit pid, resource, limits [1]
resource.setrlimit resource, limits [1]
setopencodehook [1]
shutil.chown path, user, group [1]
shutil.copyfile src, dst [1][2][3]
shutil.copymode src, dst [1][2]
shutil.copystat src, dst [1][2]
shutil.copytree src, dst [1]
shutil.make_archive base_name, format, root_dir, base_dir [1]
shutil.move src, dst [1]
shutil.rmtree path [1]
shutil.unpack_archive filename, extract_dir, format [1]
signal.pthread_kill thread_id, signalnum [1]
smtplib.connect self, host, port [1]
smtplib.send self, data [1]
socket.new self, family, type, protocol [1]
socket.bind self, address [1]
socket.connect self, address [1][2]
socket.getaddrinfo host, port, family, type, protocol [1]
socket.gethostbyaddr ip_address [1]
socket.gethostbyname hostname [1][2]
socket.gethostname [1]
socket.getnameinfo sockaddr [1]
socket.getservbyname servicename, protocolname [1]
socket.getservbyport port, protocolname [1]
socket.sendmsg self, address [1]
socket.sendto self, address [1]
socket.sethostname name [1]
sqlite3.connect database [1]
sqlite3.connect/handle connection_handle [1]
sqlite3.enable_load_extension connection, enabled [1]
sqlite3.load_extension connection, path [1]
subprocess.Popen executable, args, cwd, env [1]
sys._current_exceptions [1]
sys._current_frames [1]
sys._getframe [1]
sys.addaudithook [1][2]
sys.excepthook hook, type, value, traceback [1]
sys.set_asyncgen_hooks_finalizer [1]
sys.set_asyncgen_hooks_firstiter [1]
sys.setprofile [1]
sys.settrace [1]
sys.unraisablehook hook, unraisable [1]
syslog.closelog [1]
syslog.openlog ident, logoption, facility [1]
syslog.setlogmask maskpri [1]
syslog.syslog priority, message [1]
telnetlib.Telnet.open self, host, port [1]
telnetlib.Telnet.write self, buffer [1]
tempfile.mkdtemp fullpath [1][2]
tempfile.mkstemp fullpath [1][2][3]
urllib.Request fullurl, data, headers, method [1]
webbrowser.open url [1]
winreg.ConnectRegistry computer_name, key [1]
winreg.CreateKey key, sub_key, access [1][2]
winreg.DeleteKey key, sub_key, access [1][2]
winreg.DeleteValue key, value [1]
winreg.DisableReflectionKey key [1]
winreg.EnableReflectionKey key [1]
winreg.EnumKey key, index [1]
winreg.EnumValue key, index [1]
winreg.ExpandEnvironmentStrings str [1]
winreg.LoadKey key, sub_key, file_name [1]
winreg.OpenKey key, sub_key, access [1]
winreg.OpenKey/result key [1][2][3]
winreg.PyHKEY.Detach key [1]
winreg.QueryInfoKey key [1]
winreg.QueryReflectionKey key [1]
winreg.QueryValue key, sub_key, value_name [1][2]
winreg.SaveKey key, file_name [1]
winreg.SetValue key, sub_key, type, value [1][2]

下列事件只在内部被引发,而不会回应任何 CPython 公共 API:

审计事件 实参
_winapi.CreateFile file_name, desired_access, share_mode, creation_disposition, flags_and_attributes
_winapi.CreateJunction src_path, dst_path
_winapi.CreateNamedPipe name, open_mode, pipe_mode
_winapi.CreatePipe
_winapi.CreateProcess application_name, command_line, current_directory
_winapi.OpenProcess process_id, desired_access
_winapi.TerminateProcess handle, exit_code
ctypes.PyObj_FromPtr obj

软件打包和分发

这些库可帮助你发布和安装 Python 软件。 虽然这些模块设计为与Python 包索引 <[https://pypi.org](https://pypi.org/)>__结合使用,但它们也可以与本地索引服务器一起使用,或者根本不使用任何索引服务器。

  • distutils —- 构建和安装 Python 模块
  • ensurepip —- Bootstrapping the pip installer
    • Command line interface
    • Module API
  • venv —- 创建虚拟环境
    • 创建虚拟环境
    • API
    • 一个扩展 EnvBuilder 的例子
  • zipapp —- Manage executable Python zip archives
    • Basic Example
    • 命令行接口
    • Python API
    • 例子
    • Specifying the Interpreter
    • Creating Standalone Applications with zipapp
      • Making a Windows executable
      • Caveats
    • The Python Zip Application Archive Format

distutils —- 构建和安装 Python 模块

distutils 已被弃用并计划在 Python 3.12 中移除。


distutils 包为将待构建和安装的额外的模块,打包成 Python 安装包提供支持。新模块既可以是百分百的纯 Python,也可以是用 C 写的扩展模块,或者可以是一组包含了同时用 Python 和 C 编码的 Python 包。

大多数 Python 用户 不会 想要直接使用这个包,而是使用 Python 包官方维护的跨版本工具。特别地, setuptools 是一个对于 distutils 的增强选项,它能提供:

  • 对声明项目依赖的支持
  • 额外的用于配置哪些文件包含在源代码发布中的机制(包括与版本控制系统集成需要的插件)
  • 生成项目“进入点”的能力,进入点可用作应用插件系统的基础
  • 自动在安装时间生成 Windows 命令行可执行文件的能力,而不是需要预编译它们
  • 跨所有受支持的 Python 版本上的一致的表现

推荐的 pip 安装器用 setuptools 运行所有的 setup.py 脚本,即使脚本本身只引了 distutils 包。

为了打包工具的作者和用户能更好理解当前的打包和分发系统,遗留的基于 distutils 的用户文档和 API 参考保持可用:

ensurepip —- Bootstrapping the pip installer

3.4 新版功能.


The ensurepip package provides support for bootstrapping the pip installer into an existing Python installation or virtual environment. This bootstrapping approach reflects the fact that pip is an independent project with its own release cycle, and the latest available stable version is bundled with maintenance and feature releases of the CPython reference interpreter.

In most cases, end users of Python shouldn’t need to invoke this module directly (as pip should be bootstrapped by default), but it may be needed if installing pip was skipped when installing Python (or when creating a virtual environment) or after explicitly uninstalling pip.

注解

This module does not access the internet. All of the components needed to bootstrap pip are included as internal parts of the package.

Command line interface

The command line interface is invoked using the interpreter’s -m switch.

The simplest possible invocation is:

python -m ensurepip

This invocation will install pip if it is not already installed, but otherwise does nothing. To ensure the installed version of pip is at least as recent as the one available in ensurepip, pass the --upgrade option:

python -m ensurepip --upgrade

By default, pip is installed into the current virtual environment (if one is active) or into the system site packages (if there is no active virtual environment). The installation location can be controlled through two additional command line options:

  • --root <dir>: Installs pip relative to the given root directory rather than the root of the currently active virtual environment (if any) or the default root for the current Python installation.
  • --user: Installs pip into the user site packages directory rather than globally for the current Python installation (this option is not permitted inside an active virtual environment).

By default, the scripts pipX and pipX.Y will be installed (where X.Y stands for the version of Python used to invoke ensurepip). The scripts installed can be controlled through two additional command line options:

  • --altinstall: if an alternate installation is requested, the pipX script will not be installed.
  • --default-pip: if a “default pip” installation is requested, the pip script will be installed in addition to the two regular scripts.

Providing both of the script selection options will trigger an exception.

Module API

ensurepip exposes two functions for programmatic use:

ensurepip.version()

Returns a string specifying the available version of pip that will be installed when bootstrapping an environment.

ensurepip.bootstrap(root=None, upgrade=False, user=False, altinstall=False, default_pip=False, verbosity=0)

Bootstraps pip into the current or designated environment.

root specifies an alternative root directory to install relative to. If root is None, then installation uses the default install location for the current environment.

upgrade indicates whether or not to upgrade an existing installation of an earlier version of pip to the available version.

user indicates whether to use the user scheme rather than installing globally.

By default, the scripts pipX and pipX.Y will be installed (where X.Y stands for the current version of Python).

If altinstall is set, then pipX will not be installed.

If default_pip is set, then pip will be installed in addition to the two regular scripts.

Setting both altinstall and default_pip will trigger ValueError.

verbosity controls the level of output to sys.stdout from the bootstrapping operation.

Raises an auditing event ensurepip.bootstrap with argument root.

注解

The bootstrapping process has side effects on both sys.path and os.environ. Invoking the command line interface in a subprocess instead allows these side effects to be avoided.

注解

The bootstrapping process may install additional modules required by pip, but other software should not assume those dependencies will always be present by default (as the dependencies may be removed in a future version of pip).

venv —- 创建虚拟环境

3.3 新版功能.

源码: Lib/venv/


venv 模块支持使用自己的站点目录创建轻量级“虚拟环境”,可选择与系统站点目录隔离。每个虚拟环境都有自己的 Python 二进制文件(与用于创建此环境的二进制文件的版本相匹配),并且可以在其站点目录中拥有自己独立的已安装 Python 软件包集。

有关 Python 虚拟环境的更多信息,请参阅 PEP 405

参见

Python 打包用户指南:创建和使用虚拟环境

创建虚拟环境

通过执行 venv 指令来创建一个 虚拟环境:

python3 -m venv /path/to/new/virtual/environment

运行此命令将创建目标目录(父目录若不存在也将创建),并放置一个 pyvenv.cfg 文件在其中,文件中有一个 home 键,它的值指向运行此命令的 Python 安装(目标目录的常用名称是 .venv)。它还会创建一个 bin 子目录(在 Windows 上是 Scripts),其中包含 Python 二进制文件的副本或符号链接(视创建环境时使用的平台或参数而定)。它还会创建一个(初始为空的) lib/pythonX.Y/site-packages 子目录(在 Windows 上是 Lib\site-packages)。如果指定了一个现有的目录,这个目录就将被重新使用。

3.6 版后已移除: pyvenv 是 Python 3.3 和 3.4 中创建虚拟环境的推荐工具,不过 在 Python 3.6 中已弃用

在 3.5 版更改: 现在推荐使用 venv 来创建虚拟环境。

在 Windows 上,调用 venv 命令如下:

c:\>c:\Python35\python -m venv c:\path\to\myenv

或者,如果已经为 Python 安装 配置好 PATHPATHEXT 变量:

c:\>python -m venv c:\path\to\myenv

本命令如果以 -h 参数运行,将显示可用的选项:

usage: venv [-h] [--system-site-packages] [--symlinks | --copies] [--clear]
            [--upgrade] [--without-pip] [--prompt PROMPT] [--upgrade-deps]
            ENV_DIR [ENV_DIR ...]
Creates virtual Python environments in one or more target directories.
positional arguments:
  ENV_DIR               A directory to create the environment in.
optional arguments:
  -h, --help            show this help message and exit
  --system-site-packages
                        Give the virtual environment access to the system
                        site-packages dir.
  --symlinks            Try to use symlinks rather than copies, when symlinks
                        are not the default for the platform.
  --copies              Try to use copies rather than symlinks, even when
                        symlinks are the default for the platform.
  --clear               Delete the contents of the environment directory if it
                        already exists, before environment creation.
  --upgrade             Upgrade the environment directory to use this version
                        of Python, assuming Python has been upgraded in-place.
  --without-pip         Skips installing or upgrading pip in the virtual
                        environment (pip is bootstrapped by default)
  --prompt PROMPT       Provides an alternative prompt prefix for this
                        environment.
  --upgrade-deps        Upgrade core dependencies: pip setuptools to the
                        latest version in PyPI
Once an environment has been created, you may wish to activate it, e.g. by
sourcing an activate script in its bin directory.

在 3.9 版更改: 添加 --upgrade-deps 选项,用于将 pip + setuptools 升级到 PyPI 上的最新版本

在 3.4 版更改: 默认安装 pip,并添加 --without-pip--copies 选项

在 3.4 版更改: 在早期版本中,如果目标目录已存在,将引发错误,除非使用了 --clear--upgrade 选项。

注解

虽然 Windows 支持符号链接,但不推荐使用它们。特别注意,在文件资源管理器中双击 python.exe 将立即解析符号链接,并忽略虚拟环境。

注解

在 Microsoft Windows 上,为了启用 Activate.ps1 脚本,可能需要修改用户的执行策略。可以运行以下 PowerShell 命令来执行此操作:

PS C:> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

参阅 About Execution Policies 以获取更多信息。

生成的 pyvenv.cfg 文件还包括 include-system-site-packages 键,如果运行 venv 时带有 --system-site-packages 选项,则键值为 true,否则为 false

除非采用 --without-pip 选项,否则将会调用 ensurepippip 引导到虚拟环境中。

可以向 venv 传入多个路径,此时将根据给定的选项,在所给的每个路径上创建相同的虚拟环境。

创建虚拟环境后,可以使用虚拟环境的二进制目录中的脚本来“激活”该环境。不同平台调用的脚本是不同的(须将 替换为包含虚拟环境的目录路径):

平台 Shell 用于激活虚拟环境的命令
POSIX bash/zsh $ source <venv>/bin/activate
fish $ source <venv>/bin/activate.fish
csh/tcsh $ source <venv>/bin/activate.csh
PowerShell Core $ <venv>/bin/Activate.ps1
Windows cmd.exe C:> <venv>\Scripts\activate.bat
PowerShell PS C:> <venv>\Scripts\Activate.ps1

当一个虚拟环境被激活时,VIRTUAL_ENV 环境变量会被设为该虚拟环境的路径。 这可被用来检测程序是否运行在虚拟环境中。

激活环境不是 必须 的,激活只是将虚拟环境的二进制目录添加到搜索路径中,这样 “python” 命令将调用虚拟环境的 Python 解释器,可以运行其中已安装的脚本,而不必输入其完整路径。但是,安装在虚拟环境中的所有脚本都应在不激活的情况下可运行,并自动与虚拟环境的 Python 一起运行。

在 shell 中输入 “deactivate” 可以退出虚拟环境。具体机制取决于不同平台,并且是内部实现(通常使用脚本或 shell 函数)。

3.4 新版功能: fishcsh 激活脚本。

3.8 新版功能: 在 POSIX 上安装 PowerShell 激活脚本,以支持 PowerShell Core。

注解

虚拟环境是一个 Python 环境,安装到其中的 Python 解释器、库和脚本与其他虚拟环境中的内容是隔离的,且(默认)与“系统级” Python(操作系统的一部分)中安装的库是隔离的。

虚拟环境是一个目录树,其中包含 Python 可执行文件和其他文件,其他文件指示了这是一个是虚拟环境。

常用安装工具如 setuptools 和 pip 可以在虚拟环境中按预期工作。换句话说,当虚拟环境被激活,它们就会将 Python 软件包安装到虚拟环境中,无需明确指示。

当虚拟环境被激活(即虚拟环境的 Python 解释器正在运行),属性 sys.prefixsys.exec_prefix 指向的是虚拟环境的基础目录,而 sys.base_prefixsys.base_exec_prefix 指向非虚拟环境的 Python 安装,即曾用于创建虚拟环境的那个 Python 安装。如果虚拟环境没有被激活,则 sys.prefixsys.base_prefix 相同,且 sys.exec_prefixsys.base_exec_prefix 相同(它们均指向非虚拟环境的 Python 安装)。

当虚拟环境被激活,所有 distutils 配置文件中更改安装路径的选项都会被忽略,以防止无意中将项目安装在虚拟环境之外。

在命令行 shell 中工作时,用户可以运行虚拟环境可执行文件目录中的 activate 脚本来激活虚拟环境(调用该文件的确切文件名和命令取决于 shell),这会将虚拟环境的可执行文件目录添加到当前 shell 的 PATH 环境变量。在其他情况下,无需激活虚拟环境。安装到虚拟环境中的脚本有 “shebang” 行,指向虚拟环境的 Python 解释器。这意味着无论 PATH 的值如何,脚本都将与该解释器一起运行。在 Windows 上,如果已安装 Python Launcher for Windows,则支持处理 “shebang” 行(此功能在 Python 3.3 中添加,详情请参阅 PEP 397)。这样,在 Windows 资源管理器中双击已安装的脚本,应该会使用正确的解释器运行该脚本,而在 PATH 中无需指向其虚拟环境。

API

上述的高级方法使用了一个简单的 API,该 API 提供了一种机制,第三方虚拟环境创建者可以根据其需求自定义环境创建过程,该 API 为 EnvBuilder 类。

class venv.EnvBuilder(system_site_packages=False, clear=False, symlinks=False, upgrade=False, with_pip=False, prompt=None, upgrade_deps=False)

EnvBuilder 类在实例化时接受以下关键字参数:

  • system_site_packages — 一个布尔值,要求系统 Python 的 site-packages 对环境可用(默认为 False)。
  • clear — 一个布尔值,如果为 true,则在创建环境前将删除目标目录的现有内容。
  • symlinks — 一个布尔值,指示是否尝试符号链接 Python 二进制文件,而不是进行复制。
  • upgrade — 一个布尔值,如果为 true,则将使用当前运行的 Python 去升级一个现有的环境,这主要在原位置的 Python 更新后使用(默认为 False)。
  • with_pip — 一个布尔值,如果为 true,则确保在虚拟环境中已安装 pip。这使用的是带有 --default-pip 选项的 ensurepip
  • prompt — 激活虚拟环境后显示的提示符(默认为 None,表示使用环境所在的目录名称)。如果使用了 "." 这一特殊字符串,则使用当前目录的基本名称作为提示符。
  • upgrade_deps — 将基本 venv 模块更新为 PyPI 上的最新版本。

在 3.4 版更改: 添加 with_pip 参数

3.6 新版功能: 添加 prompt 参数

3.9 新版功能: 添加 upgrade_deps 参数

第三方虚拟环境工具的创建者可以自由地将此处提供的 EnvBuilder 类作为基类。

返回的 env-builder 是一个对象,包含一个 create 方法:

  • create(env_dir)

    指定要建立虚拟环境的目标目录(绝对路径或相对于当前路径)来创建虚拟环境。create 方法将在指定目录中创建环境,或者引发对应的异常。

    EnvBuilder 类的 create 方法定义了可用于定制子类的钩子:

    def create(self, env_dir):
        """
        Create a virtualized Python environment in a directory.
        env_dir is the target directory to create an environment in.
        """
        env_dir = os.path.abspath(env_dir)
        context = self.ensure_directories(env_dir)
        self.create_configuration(context)
        self.setup_python(context)
        self.setup_scripts(context)
        self.post_setup(context)

    每个方法 ensure_directories(), create_configuration(), setup_python(), setup_scripts()post_setup() 都可以被重写。

  • ensure_directories(env_dir)

    创建环境目录和所有必需的目录,并返回一个上下文对象。该对象只是一个容器,保存属性(如路径),供其他方法使用。允许目录已经存在,如果指定了 clearupgrade 就允许在现有环境目录上进行操作。

  • create_configuration(context)

    在环境中创建 pyvenv.cfg 配置文件。

  • setup_python(context)

    在环境中创建 Python 可执行文件的拷贝或符号链接。在 POSIX 系统上,如果给定了可执行文件 python3.x,将创建指向该可执行文件的 pythonpython3 符号链接,除非相同名称的文件已经存在。

  • setup_scripts(context)

    将适用于平台的激活脚本安装到虚拟环境中。

  • upgrade_dependencies(context)

    升级环境中 venv 依赖的核心软件包(当前为 pipsetuptools)。通过在环境中使用 pip 可执行文件来完成。

    3.9 新版功能.

  • post_setup(context)

    占位方法,可以在第三方实现中重写,用于在虚拟环境中预安装软件包,或是其他创建后要执行的步骤。

在 3.7.2 版更改: Windows 现在为 python[w].exe 使用重定向脚本,而不是复制实际的二进制文件。仅在 3.7.2 中,除非运行的是源码树中的构建,否则 setup_python() 不会执行任何操作。

在 3.7.3 版更改: Windows 将重定向脚本复制为 setup_python() 的一部分而非 setup_scripts()。在 3.7.2 中不是这种情况。使用符号链接时,将链接至原始可执行文件。

此外,EnvBuilder 提供了如下实用方法,可以从子类的 setup_scripts()post_setup() 调用,用来将自定义脚本安装到虚拟环境中。

  • install_scripts(context, path)

    path 是一个目录的路径,该目录应包含子目录 “common”, “posix”, “nt”,每个子目录存有发往对应环境中 bin 目录的脚本。在下列占位符替换完毕后,将复制 “common” 的内容和与 os.name 对应的子目录:

    • __VENV_DIR__ 会被替换为环境目录的绝对路径。
    • __VENV_NAME__ 会被替换为环境名称(环境目录的最后一个字段)。
    • __VENV_PROMPT__ 会被替换为提示符(用括号括起来的环境名称紧跟着一个空格)。
    • __VENV_BIN_NAME__ 会被替换为 bin 目录的名称( binScripts )。
    • __VENV_PYTHON__ 会被替换为环境可执行文件的绝对路径。

    允许目录已存在(用于升级现有环境时)。

有一个方便实用的模块级别的函数:

venv.create(env_dir, system_site_packages=False, clear=False, symlinks=False, with_pip=False, prompt=None, upgrade_deps=False)

通过关键词参数来创建一个 EnvBuilder,并且使用 env_dir 参数来调用它的 create() 方法。

3.3 新版功能.

在 3.4 版更改: 添加 with_pip 参数

在 3.6 版更改: 添加 prompt 参数

在 3.9 版更改: 添加 upgrade_deps 参数

一个扩展 EnvBuilder 的例子

下面的脚本展示了如何通过实现一个子类来扩展 EnvBuilder。这个子类会安装 setuptotols 和 pip 的到被创建的虚拟环境中。

import os
import os.path
from subprocess import Popen, PIPE
import sys
from threading import Thread
from urllib.parse import urlparse
from urllib.request import urlretrieve
import venv
class ExtendedEnvBuilder(venv.EnvBuilder):
    """
    This builder installs setuptools and pip so that you can pip or
    easy_install other packages into the created virtual environment.
    :param nodist: If true, setuptools and pip are not installed into the
                   created virtual environment.
    :param nopip: If true, pip is not installed into the created
                  virtual environment.
    :param progress: If setuptools or pip are installed, the progress of the
                     installation can be monitored by passing a progress
                     callable. If specified, it is called with two
                     arguments: a string indicating some progress, and a
                     context indicating where the string is coming from.
                     The context argument can have one of three values:
                     'main', indicating that it is called from virtualize()
                     itself, and 'stdout' and 'stderr', which are obtained
                     by reading lines from the output streams of a subprocess
                     which is used to install the app.
                     If a callable is not specified, default progress
                     information is output to sys.stderr.
    """
    def __init__(self, *args, **kwargs):
        self.nodist = kwargs.pop('nodist', False)
        self.nopip = kwargs.pop('nopip', False)
        self.progress = kwargs.pop('progress', None)
        self.verbose = kwargs.pop('verbose', False)
        super().__init__(*args, **kwargs)
    def post_setup(self, context):
        """
        Set up any packages which need to be pre-installed into the
        virtual environment being created.
        :param context: The information for the virtual environment
                        creation request being processed.
        """
        os.environ['VIRTUAL_ENV'] = context.env_dir
        if not self.nodist:
            self.install_setuptools(context)
        # Can't install pip without setuptools
        if not self.nopip and not self.nodist:
            self.install_pip(context)
    def reader(self, stream, context):
        """
        Read lines from a subprocess' output stream and either pass to a progress
        callable (if specified) or write progress information to sys.stderr.
        """
        progress = self.progress
        while True:
            s = stream.readline()
            if not s:
                break
            if progress is not None:
                progress(s, context)
            else:
                if not self.verbose:
                    sys.stderr.write('.')
                else:
                    sys.stderr.write(s.decode('utf-8'))
                sys.stderr.flush()
        stream.close()
    def install_script(self, context, name, url):
        _, _, path, _, _, _ = urlparse(url)
        fn = os.path.split(path)[-1]
        binpath = context.bin_path
        distpath = os.path.join(binpath, fn)
        # Download script into the virtual environment's binaries folder
        urlretrieve(url, distpath)
        progress = self.progress
        if self.verbose:
            term = '\n'
        else:
            term = ''
        if progress is not None:
            progress('Installing %s ...%s' % (name, term), 'main')
        else:
            sys.stderr.write('Installing %s ...%s' % (name, term))
            sys.stderr.flush()
        # Install in the virtual environment
        args = [context.env_exe, fn]
        p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath)
        t1 = Thread(target=self.reader, args=(p.stdout, 'stdout'))
        t1.start()
        t2 = Thread(target=self.reader, args=(p.stderr, 'stderr'))
        t2.start()
        p.wait()
        t1.join()
        t2.join()
        if progress is not None:
            progress('done.', 'main')
        else:
            sys.stderr.write('done.\n')
        # Clean up - no longer needed
        os.unlink(distpath)
    def install_setuptools(self, context):
        """
        Install setuptools in the virtual environment.
        :param context: The information for the virtual environment
                        creation request being processed.
        """
        url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py'
        self.install_script(context, 'setuptools', url)
        # clear up the setuptools archive which gets downloaded
        pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz')
        files = filter(pred, os.listdir(context.bin_path))
        for f in files:
            f = os.path.join(context.bin_path, f)
            os.unlink(f)
    def install_pip(self, context):
        """
        Install pip in the virtual environment.
        :param context: The information for the virtual environment
                        creation request being processed.
        """
        url = 'https://bootstrap.pypa.io/get-pip.py'
        self.install_script(context, 'pip', url)
def main(args=None):
    compatible = True
    if sys.version_info < (3, 3):
        compatible = False
    elif not hasattr(sys, 'base_prefix'):
        compatible = False
    if not compatible:
        raise ValueError('This script is only for use with '
                         'Python 3.3 or later')
    else:
        import argparse
        parser = argparse.ArgumentParser(prog=__name__,
                                         description='Creates virtual Python '
                                                     'environments in one or '
                                                     'more target '
                                                     'directories.')
        parser.add_argument('dirs', metavar='ENV_DIR', nargs='+',
                            help='A directory in which to create the '
                                 'virtual environment.')
        parser.add_argument('--no-setuptools', default=False,
                            action='store_true', dest='nodist',
                            help="Don't install setuptools or pip in the "
                                 "virtual environment.")
        parser.add_argument('--no-pip', default=False,
                            action='store_true', dest='nopip',
                            help="Don't install pip in the virtual "
                                 "environment.")
        parser.add_argument('--system-site-packages', default=False,
                            action='store_true', dest='system_site',
                            help='Give the virtual environment access to the '
                                 'system site-packages dir.')
        if os.name == 'nt':
            use_symlinks = False
        else:
            use_symlinks = True
        parser.add_argument('--symlinks', default=use_symlinks,
                            action='store_true', dest='symlinks',
                            help='Try to use symlinks rather than copies, '
                                 'when symlinks are not the default for '
                                 'the platform.')
        parser.add_argument('--clear', default=False, action='store_true',
                            dest='clear', help='Delete the contents of the '
                                               'virtual environment '
                                               'directory if it already '
                                               'exists, before virtual '
                                               'environment creation.')
        parser.add_argument('--upgrade', default=False, action='store_true',
                            dest='upgrade', help='Upgrade the virtual '
                                                 'environment directory to '
                                                 'use this version of '
                                                 'Python, assuming Python '
                                                 'has been upgraded '
                                                 'in-place.')
        parser.add_argument('--verbose', default=False, action='store_true',
                            dest='verbose', help='Display the output '
                                               'from the scripts which '
                                               'install setuptools and pip.')
        options = parser.parse_args(args)
        if options.upgrade and options.clear:
            raise ValueError('you cannot supply --upgrade and --clear together.')
        builder = ExtendedEnvBuilder(system_site_packages=options.system_site,
                                       clear=options.clear,
                                       symlinks=options.symlinks,
                                       upgrade=options.upgrade,
                                       nodist=options.nodist,
                                       nopip=options.nopip,
                                       verbose=options.verbose)
        for d in options.dirs:
            builder.create(d)
if __name__ == '__main__':
    rc = 1
    try:
        main()
        rc = 0
    except Exception as e:
        print('Error: %s' % e, file=sys.stderr)
    sys.exit(rc)

zipapp —- Manage executable Python zip archives

3.5 新版功能.

Source code: Lib/zipapp.py


This module provides tools to manage the creation of zip files containing Python code, which can be executed directly by the Python interpreter. The module provides both a 命令行接口 and a Python API.

Basic Example

The following example shows how the 命令行接口 can be used to create an executable archive from a directory containing Python code. When run, the archive will execute the main function from the module myapp in the archive.

$ python -m zipapp myapp -m "myapp:main"
$ python myapp.pyz
<output from myapp>

命令行接口

When called as a program from the command line, the following form is used:

$ python -m zipapp source [options]

If source is a directory, this will create an archive from the contents of source. If source is a file, it should be an archive, and it will be copied to the target archive (or the contents of its shebang line will be displayed if the —info option is specified).

The following options are understood:

-o` `<output>``,` `--output``=<output>

Write the output to a file named output. If this option is not specified, the output filename will be the same as the input source, with the extension .pyz added. If an explicit filename is given, it is used as is (so a .pyz extension should be included if required).

An output filename must be specified if the source is an archive (and in that case, output must not be the same as source).

-p` `<interpreter>``,` `--python``=<interpreter>

Add a #! line to the archive specifying interpreter as the command to run. Also, on POSIX, make the archive executable. The default is to write no #! line, and not make the file executable.

-m` `<mainfn>``,` `--main``=<mainfn>

Write a __main__.py file to the archive that executes mainfn. The mainfn argument should have the form “pkg.mod:fn”, where “pkg.mod” is a package/module in the archive, and “fn” is a callable in the given module. The __main__.py file will execute that callable.

--main cannot be specified when copying an archive.

-c``,` `--compress

Compress files with the deflate method, reducing the size of the output file. By default, files are stored uncompressed in the archive.

--compress has no effect when copying an archive.

3.7 新版功能.

--info

Display the interpreter embedded in the archive, for diagnostic purposes. In this case, any other options are ignored and SOURCE must be an archive, not a directory.

-h``,` `--help

Print a short usage message and exit.

Python API

The module defines two convenience functions:

zipapp.create_archive(source, target=None, interpreter=None, main=None, filter=None, compressed=False)

Create an application archive from source. The source can be any of the following:

  • The name of a directory, or a path-like object referring to a directory, in which case a new application archive will be created from the content of that directory.
  • The name of an existing application archive file, or a path-like object referring to such a file, in which case the file is copied to the target (modifying it to reflect the value given for the interpreter argument). The file name should include the .pyz extension, if required.
  • A file object open for reading in bytes mode. The content of the file should be an application archive, and the file object is assumed to be positioned at the start of the archive.

The target argument determines where the resulting archive will be written:

  • If it is the name of a file, or a path-like object, the archive will be written to that file.
  • If it is an open file object, the archive will be written to that file object, which must be open for writing in bytes mode.
  • If the target is omitted (or None), the source must be a directory and the target will be a file with the same name as the source, with a .pyz extension added.

The interpreter argument specifies the name of the Python interpreter with which the archive will be executed. It is written as a “shebang” line at the start of the archive. On POSIX, this will be interpreted by the OS, and on Windows it will be handled by the Python launcher. Omitting the interpreter results in no shebang line being written. If an interpreter is specified, and the target is a filename, the executable bit of the target file will be set.

The main argument specifies the name of a callable which will be used as the main program for the archive. It can only be specified if the source is a directory, and the source does not already contain a __main__.py file. The main argument should take the form “pkg.module:callable” and the archive will be run by importing “pkg.module” and executing the given callable with no arguments. It is an error to omit main if the source is a directory and does not contain a __main__.py file, as otherwise the resulting archive would not be executable.

The optional filter argument specifies a callback function that is passed a Path object representing the path to the file being added (relative to the source directory). It should return True if the file is to be added.

The optional compressed argument determines whether files are compressed. If set to True, files in the archive are compressed with the deflate method; otherwise, files are stored uncompressed. This argument has no effect when copying an existing archive.

If a file object is specified for source or target, it is the caller’s responsibility to close it after calling create_archive.

When copying an existing archive, file objects supplied only need read and readline, or write methods. When creating an archive from a directory, if the target is a file object it will be passed to the zipfile.ZipFile class, and must supply the methods needed by that class.

3.7 新版功能: Added the filter and compressed arguments.

zipapp.get_interpreter(archive)

Return the interpreter specified in the #! line at the start of the archive. If there is no #! line, return None. The archive argument can be a filename or a file-like object open for reading in bytes mode. It is assumed to be at the start of the archive.

例子

Pack up a directory into an archive, and run it.

$ python -m zipapp myapp
$ python myapp.pyz
<output from myapp>

The same can be done using the create_archive() function:

>>> import zipapp
>>> zipapp.create_archive('myapp', 'myapp.pyz')

To make the application directly executable on POSIX, specify an interpreter to use.

$ python -m zipapp myapp -p "/usr/bin/env python"
$ ./myapp.pyz
<output from myapp>

To replace the shebang line on an existing archive, create a modified archive using the create_archive() function:

>>> import zipapp
>>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3')

To update the file in place, do the replacement in memory using a BytesIO object, and then overwrite the source afterwards. Note that there is a risk when overwriting a file in place that an error will result in the loss of the original file. This code does not protect against such errors, but production code should do so. Also, this method will only work if the archive fits in memory:

>>> import zipapp
>>> import io
>>> temp = io.BytesIO()
>>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2')
>>> with open('myapp.pyz', 'wb') as f:
>>>     f.write(temp.getvalue())

Specifying the Interpreter

Note that if you specify an interpreter and then distribute your application archive, you need to ensure that the interpreter used is portable. The Python launcher for Windows supports most common forms of POSIX #! line, but there are other issues to consider:

  • If you use “/usr/bin/env python” (or other forms of the “python” command, such as “/usr/bin/python”), you need to consider that your users may have either Python 2 or Python 3 as their default, and write your code to work under both versions.
  • If you use an explicit version, for example “/usr/bin/env python3” your application will not work for users who do not have that version. (This may be what you want if you have not made your code Python 2 compatible).
  • There is no way to say “python X.Y or later”, so be careful of using an exact version like “/usr/bin/env python3.4” as you will need to change your shebang line for users of Python 3.5, for example.

Typically, you should use an “/usr/bin/env python2” or “/usr/bin/env python3”, depending on whether your code is written for Python 2 or 3.

Creating Standalone Applications with zipapp

Using the zipapp module, it is possible to create self-contained Python programs, which can be distributed to end users who only need to have a suitable version of Python installed on their system. The key to doing this is to bundle all of the application’s dependencies into the archive, along with the application code.

The steps to create a standalone archive are as follows:

  1. Create your application in a directory as normal, so you have a myapp directory containing a __main__.py file, and any supporting application code.

  2. Install all of your application’s dependencies into the myapp directory, using pip:

    $ python -m pip install -r requirements.txt --target myapp

    (this assumes you have your project requirements in a requirements.txt file - if not, you can just list the dependencies manually on the pip command line).

  3. Optionally, delete the .dist-info directories created by pip in the myapp directory. These hold metadata for pip to manage the packages, and as you won’t be making any further use of pip they aren’t required - although it won’t do any harm if you leave them.

  4. Package the application using:

    $ python -m zipapp -p "interpreter" myapp

This will produce a standalone executable, which can be run on any machine with the appropriate interpreter available. See Specifying the Interpreter for details. It can be shipped to users as a single file.

On Unix, the myapp.pyz file is executable as it stands. You can rename the file to remove the .pyz extension if you prefer a “plain” command name. On Windows, the myapp.pyz[w] file is executable by virtue of the fact that the Python interpreter registers the .pyz and .pyzw file extensions when installed.

Making a Windows executable

On Windows, registration of the .pyz extension is optional, and furthermore, there are certain places that don’t recognise registered extensions “transparently” (the simplest example is that subprocess.run(['myapp']) won’t find your application - you need to explicitly specify the extension).

On Windows, therefore, it is often preferable to create an executable from the zipapp. This is relatively easy, although it does require a C compiler. The basic approach relies on the fact that zipfiles can have arbitrary data prepended, and Windows exe files can have arbitrary data appended. So by creating a suitable launcher and tacking the .pyz file onto the end of it, you end up with a single-file executable that runs your application.

A suitable launcher can be as simple as the following:

#define Py_LIMITED_API 1
#include "Python.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#ifdef WINDOWS
int WINAPI wWinMain(
    HINSTANCE hInstance,      /* handle to current instance */
    HINSTANCE hPrevInstance,  /* handle to previous instance */
    LPWSTR lpCmdLine,         /* pointer to command line */
    int nCmdShow              /* show state of window */
)
#else
int wmain()
#endif
{
    wchar_t **myargv = _alloca((__argc + 1) * sizeof(wchar_t*));
    myargv[0] = __wargv[0];
    memcpy(myargv + 1, __wargv, __argc * sizeof(wchar_t *));
    return Py_Main(__argc+1, myargv);
}

If you define the WINDOWS preprocessor symbol, this will generate a GUI executable, and without it, a console executable.

To compile the executable, you can either just use the standard MSVC command line tools, or you can take advantage of the fact that distutils knows how to compile Python source:

>>> from distutils.ccompiler import new_compiler
>>> import distutils.sysconfig
>>> import sys
>>> import os
>>> from pathlib import Path
>>> def compile(src):
>>>     src = Path(src)
>>>     cc = new_compiler()
>>>     exe = src.stem
>>>     cc.add_include_dir(distutils.sysconfig.get_python_inc())
>>>     cc.add_library_dir(os.path.join(sys.base_exec_prefix, 'libs'))
>>>     # First the CLI executable
>>>     objs = cc.compile([str(src)])
>>>     cc.link_executable(objs, exe)
>>>     # Now the GUI executable
>>>     cc.define_macro('WINDOWS')
>>>     objs = cc.compile([str(src)])
>>>     cc.link_executable(objs, exe + 'w')
>>> if __name__ == "__main__":
>>>     compile("zastub.c")

The resulting launcher uses the “Limited ABI”, so it will run unchanged with any version of Python 3.x. All it needs is for Python (python3.dll) to be on the user’s PATH.

For a fully standalone distribution, you can distribute the launcher with your application appended, bundled with the Python “embedded” distribution. This will run on any PC with the appropriate architecture (32 bit or 64 bit).

Caveats

There are some limitations to the process of bundling your application into a single file. In most, if not all, cases they can be addressed without needing major changes to your application.

  1. If your application depends on a package that includes a C extension, that package cannot be run from a zip file (this is an OS limitation, as executable code must be present in the filesystem for the OS loader to load it). In this case, you can exclude that dependency from the zipfile, and either require your users to have it installed, or ship it alongside your zipfile and add code to your __main__.py to include the directory containing the unzipped module in sys.path. In this case, you will need to make sure to ship appropriate binaries for your target architecture(s) (and potentially pick the correct version to add to sys.path at runtime, based on the user’s machine).
  2. If you are shipping a Windows executable as described above, you either need to ensure that your users have python3.dll on their PATH (which is not the default behaviour of the installer) or you should bundle your application with the embedded distribution.
  3. The suggested launcher above uses the Python embedding API. This means that in your application, sys.executable will be your application, and not a conventional Python interpreter. Your code and its dependencies need to be prepared for this possibility. For example, if your application uses the multiprocessing module, it will need to call multiprocessing.set_executable() to let the module know where to find the standard Python interpreter.

The Python Zip Application Archive Format

Python has been able to execute zip files which contain a __main__.py file since version 2.6. In order to be executed by Python, an application archive simply has to be a standard zip file containing a __main__.py file which will be run as the entry point for the application. As usual for any Python script, the parent of the script (in this case the zip file) will be placed on sys.path and thus further modules can be imported from the zip file.

The zip file format allows arbitrary data to be prepended to a zip file. The zip application format uses this ability to prepend a standard POSIX “shebang” line to the file (#!/path/to/interpreter).

Formally, the Python zip application format is therefore:

  1. An optional shebang line, containing the characters b'#!' followed by an interpreter name, and then a newline (b'\n') character. The interpreter name can be anything acceptable to the OS “shebang” processing, or the Python launcher on Windows. The interpreter should be encoded in UTF-8 on Windows, and in sys.getfilesystemencoding() on POSIX.
  2. Standard zipfile data, as generated by the zipfile module. The zipfile content must include a file called __main__.py (which must be in the “root” of the zipfile - i.e., it cannot be in a subdirectory). The zipfile data can be compressed or uncompressed.

If an application archive has a shebang line, it may have the executable bit set on POSIX systems, to allow it to be executed directly.

There is no requirement that the tools in this module are used to create application archives - the module is a convenience, but archives in the above format created by any means are acceptable to Python.

Python运行时服务

本章里描述的模块提供了和Python解释器及其环境交互相关的广泛服务。以下是综述:

  • sys —- 系统相关的参数和函数
  • sysconfig —- Provide access to Python’s configuration information
    • 配置变量
    • 安装路径
    • 其他功能
    • Using sysconfig as a script
  • builtins —- 内建对象
  • __main__ —- Top-level code environment
    • __name__ == '__main__'
      • What is the “top-level code environment”?
      • Idiomatic Usage
      • Packaging Considerations
    • __main__.py in Python Packages
      • Idiomatic Usage
    • import __main__
  • warnings —— 警告信息的控制
    • 警告类别
    • 警告过滤器
      • 警告过滤器的介绍
      • 默认警告过滤器
      • 重写默认的过滤器
    • 暂时禁止警告
    • 测试警告
    • 为新版本的依赖关系更新代码
    • 可用的函数
    • 可用的上下文管理器
  • dataclasses —- 数据类
    • 模块内容
    • 初始化后处理
    • 类变量
    • 仅初始化变量
    • 冻结的实例
    • 继承
    • __init__() 中仅限关键字字段的重新排序
    • 默认工厂函数
    • 可变的默认值
  • contextlib —- 为 with语句上下文提供的工具
    • 工具
    • 例子和配方
      • Supporting a variable number of context managers
      • Catching exceptions from __enter__ methods
      • Cleaning up in an __enter__ implementation
      • Replacing any use of try-finally and flag variables
      • Using a context manager as a function decorator
    • Single use, reusable and reentrant context managers
      • Reentrant context managers
      • Reusable context managers
  • abc —- 抽象基类
  • atexit —- 退出处理器
    • atexit 示例
  • traceback —- 打印或检索堆栈回溯
    • TracebackException Objects
    • StackSummary Objects
    • FrameSummary Objects
    • Traceback Examples
  • __future__ —- Future 语句定义
  • gc —- 垃圾回收器接口
  • inspect —- 检查对象
    • 类型和成员
    • Retrieving source code
    • Introspecting callables with the Signature object
    • 类与函数
    • The interpreter stack
    • Fetching attributes statically
    • Current State of Generators and Coroutines
    • Code Objects Bit Flags
    • 命令行界面
  • site —— 指定域的配置钩子
    • Readline 配置
    • 模块内容
    • 命令行界面

sys —- 系统相关的参数和函数

该模块提供了一些变量和函数。这些变量可能被解释器使用,也可能由解释器提供。这些函数会影响解释器。本模块总是可用的。

sys.abiflags

在POSIX系统上,以标准的 configure 脚本构建的 Python 中,这个变量会包含 PEP 3149 中定义的ABI标签。

在 3.8 版更改: 默认的 flags 变为了空字符串(用于 pymalloc 的 m 旗标已经移除)

3.2 新版功能.

sys.addaudithook(hook)

将可调用对象 hook 附加到当前(子)解释器的活动的审计钩子列表中。

当通过 sys.audit() 函数引发审计事件时,每个钩子将按照其被加入的先后顺序被调用,调用时会传入事件名称和参数元组。 由 PySys_AddAuditHook() 添加的原生钩子会先被调用,然后是当前(子)解释器中添加的钩子。 接下来这些钩子会记录事件,引发异常来中止操作,或是完全终止进程。

调用 sys.addaudithook() 时它自身将引发一个名为 sys.addaudithook 的审计事件且不附带参数。 如果任何现有的钩子引发了派生自 RuntimeError 的异常,则新的钩子不会被添加并且该异常会被抑制。 其结果就是,调用者无法确保他们的钩子已经被添加,除非他们控制了全部现有的钩子。

3.8 新版功能.

在 3.8.1 版更改: 派生自 Exception (而非 RuntimeError )的异常不会被抑制。

CPython implementation detail: 启用跟踪时,仅当可调用对象(钩子)的 __cantrace__ 成员设置为 true 时,才会跟踪该钩子。否则,跟踪功能将跳过该钩子。

sys.argv

一个列表,其中包含了被传递给 Python 脚本的命令行参数。 argv[0] 为脚本的名称(是否是完整的路径名取决于操作系统)。如果是通过 Python 解释器的命令行参数 -c 来执行的, argv[0] 会被设置成字符串 '-c' 。如果没有脚本名被传递给 Python 解释器, argv[0] 为空字符串。

注解

在 Unix 上,系统传递的命令行参数是字节类型的。Python 使用文件系统编码和 “surrogateescape” 错误处理方案对它们进行解码。当需要原始字节时,可以通过 [os.fsencode(arg) for arg in sys.argv] 来获取。

sys.audit(event, \args*)

引发一个审计事件并触发任何激活的审计钩子。 event 是一个用于标识事件的字符串,args 会包含有关事件的更多信息的可选参数。 特定事件的参数的数量和类型会被视为是公有的稳定 API 且不应当在版本之间进行修改。

例如,有一个审计事件的名称为 os.chdir。 此事件具有一个名为 path 的参数,该参数将包含所请求的新工作目录。

sys.audit() 将调用现有的审计钩子,传入事件名称和参数,并将重新引发来自任何钩子的第一个异常。 通常来说,如果有一个异常被引发,则它不应当被处理且其进程应当被尽可能快地终止。 这将允许钩子实现来决定对特定事件要如何反应:它们可以只是将事件写入日志或是通过引发异常来中止操作。

钩子程序由 sys.addaudithook()PySys_AddAuditHook() 函数添加。

与本函数相等效的原生函数是 PySys_Audit(),应尽量使用原生函数。

3.8 新版功能.

sys.base_exec_prefix

site.py 运行之前, Python 启动的时候被设置为跟 exec_prefix 同样的值。如果不是运行在 虚拟环境 中,两个值会保持相同;如果 site.py 发现处于一个虚拟环境中, prefixexec_prefix 将会指向虚拟环境。然而 base_prefixbase_exec_prefix 将仍然会指向基础的 Python 环境(用来创建虚拟环境的 Python 环境)

3.3 新版功能.

sys.base_prefix

site.py 运行之前, Python 启动的时候被设置为跟 prefix 同样的值。如果不是运行在 虚拟环境 中, 两个值会保持相同;如果 site.py 发现处于一个虚拟环境中, prefixexec_prefix 将会指向虚拟环境。然而 base_prefixbase_exec_prefix 将仍然会指向基础的 Python 环境(用来创建虚拟环境的 Python 环境)

3.3 新版功能.

sys.byteorder

本地字节顺序的指示符。在大端序(最高有效位优先)操作系统上值为 'big' ,在小端序(最低有效位优先)操作系统上为 'little'

sys.builtin_module_names

一个包含所有被编译进 Python 解释器的模块的名称的字符串元组。 (此信息无法通过任何其他办法获取 —- modules.keys() 仅会列出导入的模块。)

另请参阅 sys.stdlib_module_names 列表。

sys.call_tracing(func, args)

在启用跟踪时调用 func(*args) 来保存跟踪状态,然后恢复跟踪状态。这将从检查点的调试器调用,以便递归地调试其他的一些代码。

sys.copyright

一个字符串,包含了 Python 解释器有关的版权信息

sys._clear_type_cache()

清除内部的类型缓存。类型缓存是为了加速查找方法和属性的。在调试引用泄漏的时候调用这个函数 只会 清除不必要的引用。

这个函数应该只在内部为了一些特定的目的使用。

sys._current_frames()

返回一个字典,存放着每个线程的标识符与(调用本函数时)该线程栈顶的帧(当前活动的帧)之间的映射。注意 traceback 模块中的函数可以在给定某一帧的情况下构建调用堆栈。

这对于调试死锁最有用:本函数不需要死锁线程的配合,并且只要这些线程的调用栈保持死锁,它们就是冻结的。在调用本代码来检查栈顶的帧的那一刻,非死锁线程返回的帧可能与该线程当前活动的帧没有任何关系。

这个函数应该只在内部为了一些特定的目的使用。

引发一个 审计事件 sys._current_frames,没有附带参数。

sys._current_exceptions()

返回一个字典,存放着每个线程的标识与调用此函数时该线程当前活动帧的栈顶异常之间的映射。 如果某个线程当前未在处理异常,它将不被包括在结果字典中。

这对于静态性能分析来说最为有用。

这个函数应该只在内部为了一些特定的目的使用。

引发一个 审计事件 sys._current_exceptions,不附带任何参数。

sys.breakpointhook()

本钩子函数由内建函数 breakpoint() 调用。默认情况下,它将进入 pdb 调试器,但可以将其改为任何其他函数,以选择使用哪个调试器。

该函数的特征取决于其调用的函数。例如,默认绑定(即 pdb.set_trace() )不要求提供参数,但可以将绑定换成要求提供附加参数(位置参数/关键字参数)的函数。内建函数 breakpoint() 直接将其 *args**kws 传入。breakpointhooks() 返回的所有内容都会从 breakpoint() 返回。

默认的实现首先会查询环境变量 PYTHONBREAKPOINT。如果将该变量设置为 "0",则本函数立即返回,表示在断点处无操作。如果未设置该环境变量或将其设置为空字符串,则调用 pdb.set_trace()。否则,此变量应指定要运行的函数,指定函数时应使用 Python 的点导入命名法,如 package.subpackage.module.function。这种情况下将导入 package.subpackage.module,且导入的模块必须有一个名为 function() 的可调用对象。该可调用对象会运行,*args**kws 会传入,且无论 function() 返回什么,sys.breakpointhook() 都将返回到內建函数 breakpoint()

请注意,如果在导入 PYTHONBREAKPOINT 指定的可调用对象时出错,则将报告一个 RuntimeWarning 并忽略断点。

另请注意,如果以编程方式覆盖 sys.breakpointhook(),则 不会 查询 PYTHONBREAKPOINT

3.7 新版功能.

sys._debugmallocstats()

将有关 CPython 内存分配器状态的底层的信息打印至 stderr。

如果 Python 是 以调试模式编译的 <debug-build> (configure --with-pydebug option),它还会执行一些消耗性能的内部一致性检查。

3.3 新版功能.

CPython implementation detail: 本函数仅限 CPython。此处没有定义确切的输出格式,且可能会更改。

sys.dllhandle

指向 Python DLL 句柄的整数。

可用性: Windows。

sys.displayhook(value)

如果 value 不是 None,则本函数会将 repr(value) 打印至 sys.stdout,并将 value 保存在 builtins._ 中。如果 repr(value) 无法用 sys.stdout.errors 错误处理方案(可能为 'strict' )编码为 sys.stdout.encoding,则用 'backslashreplace' 错误处理方案将其编码为 sys.stdout.encoding

在交互式 Python 会话中运行 expression 产生结果后,将在结果上调用 sys.displayhook。若要自定义这些 value 的显示,可以将 sys.displayhook 指定为另一个单参数函数。

伪代码:

def displayhook(value):
    if value is None:
        return
    # Set '_' to None to avoid recursion
    builtins._ = None
    text = repr(value)
    try:
        sys.stdout.write(text)
    except UnicodeEncodeError:
        bytes = text.encode(sys.stdout.encoding, 'backslashreplace')
        if hasattr(sys.stdout, 'buffer'):
            sys.stdout.buffer.write(bytes)
        else:
            text = bytes.decode(sys.stdout.encoding, 'strict')
            sys.stdout.write(text)
    sys.stdout.write("\n")
    builtins._ = value

在 3.2 版更改: 在发生 UnicodeEncodeError 时使用 'backslashreplace' 错误处理方案。

sys.dont_write_bytecode

如果该值为 true,则 Python 在导入源码模块时将不会尝试写入 .pyc 文件。该值会被初始化为 TrueFalse,依据是 -B 命令行选项和 PYTHONDONTWRITEBYTECODE 环境变量,可以自行设置该值,来控制是否生成字节码文件。

sys.pycache_prefix

如果将该值设为某个目录(不是 None ),Python 会将字节码缓存文件 .pyc 写入到以该目录为根的并行目录树中(并从中读取),而不是在源码树中的 __pycache__ 目录下读写。源码树中所有的 __pycache__ 目录都将被忽略,并将在 pycache prefix 内写入新的 .pyc 文件。因此,如果使用 compileall 作为预构建步骤,则必须确保预构建时使用的 pycache prefix (如果有)与将来运行的时候相同。

相对路径将解释为相对于当前工作目录。

该值的初值设置,依据 -X pycache_prefix=PATH 命令行选项或 PYTHONPYCACHEPREFIX 环境变量的值(命令行优先)。如果两者均未设置,则为 None

3.8 新版功能.

sys.excepthook(type, value, traceback)

本函数会将所给的回溯和异常输出到 sys.stderr 中。

当抛出一个异常,且未被捕获时,解释器将调用 sys.excepthook 并带有三个参数:异常类、异常实例和一个回溯对象。在交互式会话中,这会在控制权返回到提示符之前发生。在 Python 程序中,这会在程序退出之前发生。如果要自定义此类顶级异常的处理过程,可以将另一个 3 个参数的函数赋给 sys.excepthook

引发一个 审计事件 sys.excepthook,附带参数 hook, type, value, traceback

参见

sys.unraisablehook() 函数处理无法抛出的异常,threading.excepthook() 函数处理 threading.Thread.run() 抛出的异常。

sys.__breakpointhook__
sys.__displayhook__
sys.__excepthook__
sys.__unraisablehook__

程序开始时,这些对象存有 breakpointhookdisplayhookexcepthookunraisablehook 的初始值。保存它们是为了可以在 breakpointhookdisplayhookexcepthookunraisablehook 被破坏或被替换时恢复它们。

3.7 新版功能: breakpointhook

3.8 新版功能: unraisablehook

sys.exc_info()

本函数返回的元组包含三个值,它们给出当前正在处理的异常的信息。返回的信息仅限于当前线程和当前堆栈帧。如果当前堆栈帧没有正在处理的异常,则信息将从下级被调用的堆栈帧或上级调用者等位置获取,依此类推,直到找到正在处理异常的堆栈帧为止。此处的“处理异常”指的是“执行 except 子句”。任何堆栈帧都只能访问当前正在处理的异常的信息。

如果整个堆栈都没有正在处理的异常,则返回包含三个 None 值的元组。否则返回值为 (type, value, traceback)。它们的含义是:type 是正在处理的异常类型(它是 BaseException 的子类);value 是异常实例(异常类型的实例);traceback 是一个 回溯对象,该对象封装了最初发生异常时的调用堆栈。

sys.exec_prefix

一个字符串,提供特定域的目录前缀,该目录中安装了与平台相关的 Python 文件,默认也是 '/usr/local'。该目录前缀可以在构建时使用 configure 脚本的 --exec-prefix 参数进行设置。具体而言,所有配置文件(如 pyconfig.h 头文件)都安装在目录 *exec_prefix*/lib/python*X.Y*/config 中,共享库模块安装在 *exec_prefix*/lib/python*X.Y*/lib-dynload 中,其中 X.Y 是 Python 的版本号,如 3.2

注解

如果在一个 虚拟环境 中,那么该值将在 site.py 中被修改,指向虚拟环境。Python 安装位置仍然可以用 base_exec_prefix 来获取。

sys.executable

一个字符串,提供 Python 解释器的可执行二进制文件的绝对路径,仅在部分系统中此值有意义。如果 Python 无法获取其可执行文件的真实路径,则 sys.executable 将为空字符串或 None

sys.exit([arg])

从 Python 中退出。实现方式是抛出一个 SystemExit 异常,因此异常抛出后 try 语句的 finally 分支的清除动作将被触发,这样可能会打断外层的退出尝试。

可选参数 arg 可以是表示退出状态的整数(默认为 0),也可以是其他类型的对象。如果它是整数,则 shell 等将 0 视为“成功终止”,非零值视为“异常终止”。大多数系统要求该值的范围是 0—127,否则会产生不确定的结果。某些系统为退出代码约定了特定的含义,但通常尚不完善;Unix 程序通常用 2 表示命令行语法错误,用 1 表示所有其他类型的错误。传入其他类型的对象,如果传入 None 等同于传入 0,如果传入其他对象则将其打印至 stderr,且退出代码为 1。特别地,sys.exit("some error message") 可以在发生错误时快速退出程序。

由于 exit() 最终“只是”抛出一个异常,因此当从主线程调用时,只会从进程退出;而异常不会因此被打断。

在 3.6 版更改: 在 Python 解释器捕获 SystemExit 后,如果在清理中发生错误(如清除标准流中的缓冲数据时出错),则退出状态码将变为 120。

sys.flags

具名元组 flags 含有命令行标志的状态。这些属性是只读的。

attribute — 属性 标志
debug -d
inspect -i
interactive -i
isolated -I
optimize -O-OO
dont_write_bytecode -B
no_user_site -s
no_site -S
ignore_environment -E
verbose -v
bytes_warning -b
quiet -q
hash_randomization -R
dev_mode -X dev (Python 开发模式)
utf8_mode -X utf8

在 3.2 版更改: 为新的 -q 标志添加了 quiet 属性

3.2.3 新版功能: hash_randomization 属性

在 3.3 版更改: 删除了过时的 division_warning 属性

在 3.4 版更改: 为 -I isolated 标志添加了 isolated 属性。

在 3.7 版更改: 为新的 Python 开发模式 添加了 dev_mode 属性,为新的 -X utf8 标志添加了 utf8_mode 属性。

sys.float_info

一个 具名元组,存有浮点型的相关信息。它包含的是关于精度和内部表示的底层信息。这些值与标准头文件 float.h 中为 C 语言定义的各种浮点常量对应,详情请参阅 1999 ISO/IEC C 标准 [C99] 的 5.2.4.2.2 节,’Characteristics of floating types(浮点型的特性)’。

attribute — 属性 float.h 宏 说明
epsilon DBL_EPSILON 大于 1.0 的最小值和 1.0 之间的差,表示为浮点数另请参阅 math.ulp()
dig DBL_DIG 浮点数可以真实表示的最大十进制数字;见下文
mant_dig DBL_MANT_DIG 浮点数精度:radix 基数下的浮点数有效位数
max DBL_MAX 可表示的最大正浮点数(非无穷)
max_exp DBL_MAX_EXP 使得 radix**(e-1)** 是可表示的浮点数(非无穷)的最大整数 *e*
max_10_exp DBL_MAX_10_EXP 使得 10e 在可表示的浮点数(非无穷)范围内的最大整数 e
min DBL_MIN 可表示的最小正 规格化 浮点数使用 math.ulp(0.0) 获取可表示的最小正 非规格化 浮点数
min_exp DBL_MIN_EXP 使得 radix**(e-1)** 是规格化浮点数的最小整数 *e*
min_10_exp DBL_MIN_10_EXP 使得 10e 是规格化浮点数的最小整数 e
radix FLT_RADIX 指数表示法中采用的基数
rounds FLT_ROUNDS 整数常数,表示算术运算中的舍入方式。它反映了解释器启动时系统的 FLT_ROUNDS 宏的值。关于可能的值及其含义的说明,请参阅 C99 标准 5.2.4.2.2 节。

关于 sys.float_info.dig 属性的进一步说明。如果 s 是表示十进制数的字符串,而该数最多有 sys.float_info.dig 位有效数字,则将 s 转换为 float 再转回去将恢复原先相同十进制值的字符串:

>>> import sys
>>> sys.float_info.dig
15
>>> s = '3.14159265358979'    # decimal string with 15 significant digits
>>> format(float(s), '.15g')  # convert to float and back -> same value
'3.14159265358979'

但是对于超过 sys.float_info.dig 位有效数字的字符串,转换前后并非总是相同:

>>> s = '9876543211234567'    # 16 significant digits is too many!
>>> format(float(s), '.16g')  # conversion changes value
'9876543211234568'

一个字符串,反映 repr() 函数在浮点数上的行为。如果该字符串是 'short',那么对于(非无穷的)浮点数 xrepr(x) 将会生成一个短字符串,满足 float(repr(x)) == x 的特性。这是 Python 3.1 及更高版本中的常见行为。否则 float_repr_style 的值将是 'legacy',此时 repr(x) 的行为方式将与 Python 3.1 之前的版本相同。

3.1 新版功能.

sys.getallocatedblocks()

返回解释器当前已分配的内存块数,无论它们大小如何。本函数主要用于跟踪和调试内存泄漏。因为解释器有内部缓存,所以不同调用之间结果会变化。可能需要调用 _clear_type_cache()gc.collect() 使结果更容易预测。

如果当前 Python 构建或实现无法合理地计算此信息,允许 getallocatedblocks() 返回 0。

3.4 新版功能.

sys.getandroidapilevel()

返回一个整数,表示 Android 构建时 API 版本。

可用性:Android。

3.7 新版功能.

sys.getdefaultencoding()

返回当前 Unicode 实现所使用的默认字符串编码名称。

sys.getdlopenflags()

返回当前 dlopen() 调用所使用的标志位的值。标志值对应的符号名称可以在 os 模块中找到(形如 RTLD_xxx 的常量,如 os.RTLD_LAZY )。

可用性: Unix。

sys.getfilesystemencoding()

获取 文件系统编码格式: 与 文件系统错误处理句柄 一起使用以便在 Unicode 文件名和字节文件名之间进行转换。 文件系统错误处理句柄是由 getfilesystemencoding() 来返回的。

为获得最佳兼容性,在任何时候都应使用 str 来表示文件名,尽管使用 bytes 来表示文件名也是受支持的。 接受还返回文件名的函数应当支持 str 或 bytes 并在内部将其转换为系统首选的表示形式。

应使用 os.fsencode()os.fsdecode() 来保证所采用的编码和错误处理方案都是正确的。

filesystem encoding and error handler 是在 Python 启动时通过 PyConfig_Read() 函数来配置的。

在 3.2 版更改: getfilesystemencoding() 的结果将不再有可能是 None

在 3.6 版更改: Windows 不再保证会返回 'mbcs'。详情请参阅 PEP 529_enablelegacywindowsfsencoding()

在 3.7 版更改: 返回 'utf-8',如果启用了 Python UTF-8 模式 的话。

sys.getfilesystemencodeerrors()

获取 文件系统错误处理句柄: 该错误处理句柄与 文件系统编码格式 一起使用以便在 Unicode 文件名和字节文件名之间进程转换。 文件系统编码格式是由 getfilesystemencoding() 来返回的。

应使用 os.fsencode()os.fsdecode() 来保证所采用的编码和错误处理方案都是正确的。

filesystem encoding and error handler 是在 Python 启动时通过 PyConfig_Read() 函数来配置的:

3.6 新版功能.

sys.getrefcount(object)

返回 object 的引用计数。返回的计数通常比预期的多一,因为它包括了作为 getrefcount() 参数的这一次(临时)引用。

sys.getrecursionlimit()

返回当前的递归限制值,即 Python 解释器堆栈的最大深度。此限制可防止无限递归导致的 C 堆栈溢出和 Python 崩溃。该值可以通过 setrecursionlimit() 设置。

sys.getsizeof(object[, default])

返回对象的大小(以字节为单位)。该对象可以是任何类型。所有内建对象返回的结果都是正确的,但对于第三方扩展不一定正确,因为这与具体实现有关。

只计算直接分配给对象的内存消耗,不计算它所引用的对象的内存消耗。

对象不提供计算大小的方法时,如果传入过 default 则返回它,否则抛出 TypeError 异常。

如果对象由垃圾回收器管理,则 getsizeof() 将调用对象的 __sizeof__ 方法,并在上层添加额外的垃圾回收器。

可以参考 recursive sizeof recipe 中的示例,关于递归调用 getsizeof() 来得到各个容器及其所有内容物的大小。

sys.getswitchinterval()

返回解释器的“线程切换间隔时间”,请参阅 setswitchinterval()

3.2 新版功能.

sys._getframe([depth])

返回来自调用栈的一个帧对象。如果传入可选整数 depth,则返回从栈顶往下相应调用层数的帧对象。如果该数比调用栈更深,则抛出 ValueErrordepth 的默认值是 0,返回调用栈顶部的帧。

引发一个 审计事件 sys._getframe,没有附带参数。

CPython implementation detail: 这个函数应该只在内部为了一些特定的目的使用。不保证它在所有 Python 实现中都存在。

sys.getprofile()

返回由 setprofile() 设置的性能分析函数。

sys.gettrace()

返回由 settrace() 设置的跟踪函数。

CPython implementation detail: gettrace() 函数仅用于实现调试器,性能分析器,打包工具等。它的行为是实现平台的一部分,而不是语言定义的一部分,因此并非在所有 Python 实现中都可用。

sys.getwindowsversion()

返回一个具名元组,描述当前正在运行的 Windows 版本。元素名称包括 major, minor, build, platform, service_pack, service_pack_minor, service_pack_major, suite_mask, product_typeplatform_versionservice_pack 包含一个字符串,platform_version 包含一个三元组,其他所有值都是整数。元素也可以通过名称来访问,所以 sys.getwindowsversion()[0]sys.getwindowsversion().major 是等效的。为保持与旧版本的兼容性,只有前 5 个元素可以用索引检索。

platform 将会是 2 (VER_PLATFORM_WIN32_NT)

product_type 可能是以下值之一:

常量 含意
1 (VER_NT_WORKSTATION) 系统是工作站。
2 (VER_NT_DOMAIN_CONTROLLER) 系统是域控制器。
3 (VER_NT_SERVER) 系统是服务器,但不是域控制器。

本函数包装了 Win32 GetVersionEx() 函数,参阅 Microsoft 文档有关 OSVERSIONINFOEX() 的内容可获取这些字段的更多信息。

platform_version 返回当前操作系统的主要版本、次要版本和编译版本号,而不是为该进程所模拟的版本。 它旨在用于日志记录而非特性检测。

注解

platform_version 会从 kernel32.dll 获取版本号,这个版本可能与 OS 版本不同。 请使用 platform 模块来获取准确的 OS 版本号。

可用性: Windows。

在 3.2 版更改: 更改为具名元组,添加 service_pack_minor, service_pack_major, suite_maskproduct_type

在 3.6 版更改: 添加了 platform_version

sys.get_asyncgen_hooks()

返回一个 asyncgen_hooks 对象,该对象类似于 namedtuple,形式为 (firstiter, finalizer),其中 firstiterfinalizerNone 或函数,函数以 异步生成器迭代器 作为参数,并用于在事件循环中干预异步生成器的终结。

3.6 新版功能: 详情请参阅 PEP 525

注解

本函数已添加至暂定软件包(详情请参阅 PEP 411 )。

sys.get_coroutine_origin_tracking_depth()

获取由 set_coroutine_origin_tracking_depth() 设置的协程来源的追踪深度。

3.7 新版功能.

注解

本函数已添加至暂定软件包(详情请参阅 PEP 411 )。仅将其用于调试目的。

sys.hash_info

一个 具名元组,给出数字类型的哈希的实现参数。

attribute — 属性 说明
width 用于哈希值的位宽度
modulus 用于数字散列方案的素数模数P。
inf 为正无穷大返回的哈希值
nan (该属性已不再被使用)
imag 用于复数虚部的乘数
algorithm 字符串、字节和内存视图的哈希算法的名称
hash_bits 哈希算法的内部输出大小。
seed_bits 散列算法的种子密钥的大小

3.2 新版功能.

在 3.4 版更改: 添加了 algorithm, hash_bitsseed_bits

sys.hexversion

编码为单个整数的版本号。该整数会确保每个版本都自增,其中适当包括了未发布版本。举例来说,要测试 Python 解释器的版本不低于 1.5.2,请使用:

if sys.hexversion >= 0x010502F0:
    # use some advanced feature
    ...
else:
    # use an alternative implementation or warn the user
    ...

之所以称它为 hexversion,是因为只有将它传入内置函数 hex() 后,其结果才看起来有意义。也可以使用 具名元组 sys.version_info,它对相同信息有着更人性化的编码。

关于 hexversion 的更多信息可以在 API 和 ABI 版本管理 中找到。

sys.implementation

一个对象,该对象包含当前运行的 Python 解释器的实现信息。所有 Python 实现中都必须存在下列属性。

name 是当前实现的标识符,如 'cpython'。实际的字符串由 Python 实现定义,但保证是小写字母。

version 是一个具名元组,格式与 sys.version_info 相同。它表示 Python 实现 的版本。 另一个(由 sys.version_info 表示)是当前解释器遵循的相应 Python 语言 的版本,两者具有不同的含义。 例如,对于 PyPy 1.8,sys.implementation.version 可能是 sys.version_info(1, 8, 0, 'final', 0),而 sys.version_info 则是 sys.version_info(2, 7, 2, 'final', 0)。对于 CPython 而言两个值是相同的,因为它是参考实现。

hexversion 是十六进制的实现版本,类似于 sys.hexversion

cache_tag 是导入机制使用的标记,用于已缓存模块的文件名。按照惯例,它将由实现的名称和版本组成,如 'cpython-33'。但如果合适,Python 实现可以使用其他值。如果 cache_tag 被置为 None,表示模块缓存已禁用。

sys.implementation 可能包含相应 Python 实现的其他属性。这些非标准属性必须以下划线开头,此处不详细阐述。无论其内容如何,sys.implementation 在解释器运行期间或不同实现版本之间都不会更改。(但是不同 Python 语言版本间可能会不同。)详情请参阅 PEP 421

3.3 新版功能.

注解

新的必要属性的添加必须经过常规的 PEP 过程。详情请参阅 PEP 421

sys.int_info

一个 具名元组,包含 Python 内部整数表示形式的信息。这些属性是只读的。

属性 说明
bits_per_digit 每个数字占有的位数。Python 内部将整数存储在基底 2**int_info.bits_per_digit
sizeof_digit 用于表示数字的C类型的字节大小

3.1 新版功能.

sys.__interactivehook__

当本属性存在,则以 交互模式 启动解释器时,将自动(不带参数地)调用本属性的值。该过程是在读取 PYTHONSTARTUP 文件之后完成的,所以可以在该文件中设置这一钩子。site 模块 设置了这一属性。

引发一个 审计事件 cpython.run_interactivehook,附带参数 hook

3.4 新版功能.

sys.intern(string)

string 插入 “interned” (驻留)字符串表,返回被插入的字符串 — 它是 string 本身或副本。驻留字符串对提高字典查找的性能很有用 — 如果字典中的键已驻留,且所查找的键也已驻留,则键(取散列后)的比较可以用指针代替字符串来比较。通常,Python 程序使用到的名称会被自动驻留,且用于保存模块、类或实例属性的字典的键也已驻留。

驻留字符串不是永久存在的,对 intern() 返回值的引用必须保留下来,才能发挥驻留字符串的优势。

sys.is_finalizing()

如果 Python 解释器 正在关闭 则返回 True,否则返回 False

3.5 新版功能.

sys.last_type
sys.last_value
sys.last_traceback

这三个变量并非总是有定义,仅当有异常未处理,且解释器打印了错误消息和堆栈回溯时,才会给它们赋值。它们的预期用途,是允许交互中的用户导入调试器模块,进行事后调试,而不必重新运行导致错误的命令。(通常使用 import pdb; pdb.pm() 进入事后调试器。)

这些变量的含义与上述 exc_info() 返回值的含义相同。

sys.maxsize

一个整数,表示 Py_ssize_t 类型的变量可以取到的最大值。在 32 位平台上通常为 2**31 - 1,在 64 位平台上通常为 2**63 - 1

sys.maxunicode

一个整数,表示最大的 Unicode 码点值,如 1114111 (十六进制为 0x10FFFF )。

在 3.3 版更改: 在 PEP 393 之前,sys.maxunicode 曾是 0xFFFF0x10FFFF,具体取决于配置选项,该选项指定将 Unicode 字符存储为 UCS-2 还是 UCS-4。

sys.meta_path

一个由 元路径查找器 对象组成的列表,当查找需要导入的模块时,会调用这些对象的 find_spec() 方法,观察这些对象是否能找到所需模块。调用 find_spec() 方法最少需要传入待导入模块的绝对名称。如果待导入模块包含在一个包中,则父包的 __path__ 属性将作为第二个参数被传入。该方法返回 模块规格,找不到模块则返回 None

参见

  • importlib.abc.MetaPathFinder

    抽象基类,定义了 meta_path 内的查找器对象的接口。

    importlib.machinery.+ModuleSpec

    find_spec() 返回的实例所对应的具体类。

在 3.4 版更改: 在 Python 3.4 中通过 PEP 451 引入了 模块规格。早期版本的 Python 会寻找一个称为 find_module() 的方法。如果某个 meta_path 条目没有 find_spec() 方法,就会回退去调用前一种方法。

sys.modules

一个字典,将模块名称映射到已加载的模块。可以操作该字典来强制重新加载模块,或是实现其他技巧。但是,替换的字典不一定会按预期工作,并且从字典中删除必要的项目可能会导致 Python 崩溃。

sys.orig_argv

传给 Python 可执行文件的原始命令行参数列表。

3.10 新版功能.

sys.path

一个由字符串组成的列表,用于指定模块的搜索路径。初始化自环境变量 PYTHONPATH,再加上一条与安装有关的默认路径。

程序启动时将初始化本列表,列表的第一项 path[0] 目录含有调用 Python 解释器的脚本。如果脚本目录不可用(比如以交互方式调用了解释器,或脚本是从标准输入中读取的),则 path[0] 为空字符串,这将导致 Python 优先搜索当前目录中的模块。注意,脚本目录将插入在 PYTHONPATH 的条目之前

程序可以随意修改本列表用于自己的目的。只能向 sys.path 中添加 string 和 bytes 类型,其他数据类型将在导入期间被忽略。

参见

site 模块,该模块描述了如何使用 .pth 文件来扩展 sys.path

sys.path_hooks

一个由可调用对象组成的列表,这些对象接受一个路径作为参数,并尝试为该路径创建一个 查找器。如果成功创建查找器,则可调用对象将返回它,否则将引发 ImportError 异常。

本特性最早在 PEP 302 中被提及。

sys.path_importer_cache

一个字典,作为 查找器 对象的缓存。key 是传入 sys.path_hooks 的路径,value 是相应已找到的查找器。如果路径是有效的文件系统路径,但在 sys.path_hooks 中未找到查找器,则存入 None

本特性最早在 PEP 302 中被提及。

在 3.3 版更改: 未找到查找器时,改为存储 None,而不是 imp.NullImporter

sys.platform

本字符串是一个平台标识符,举例而言,该标识符可用于将特定平台的组件追加到 sys.path 中。

对于 Unix 系统(除 Linux 和 AIX 外),该字符串是 Python 构建时的 uname -s 返回的小写操作系统名称,并附加了 uname -r 返回的系统版本的第一部分,如 'sunos5''freebsd8'。除非需要检测特定版本的系统,否则建议使用以下习惯用法:

if sys.platform.startswith('freebsd'):
    # FreeBSD-specific code here...
elif sys.platform.startswith('linux'):
    # Linux-specific code here...
elif sys.platform.startswith('aix'):
    # AIX-specific code here...

对于其他系统,值是:

系统 平台
AIX ‘aix’
Linux ‘linux’
Windows ‘win32’
Windows/Cygwin ‘cygwin’
macOS ‘darwin’

在 3.3 版更改: 在 Linux 上,sys.platform 将不再包含副版本号。它将总是 'linux' 而不是 'linux2''linux3'。由于旧版本的 Python 会包含该版本号,因此推荐总是使用上述 startswith 习惯用法。

在 3.8 版更改: 在 AIX 上,sys.platform 将不再包含副版本号。它将总是 'aix' 而不是 'aix5''aix7'。由于旧版本的 Python 会包含该版本号,因此推荐总是使用上述 startswith 习惯用法。

参见

os.name 更加简略。os.uname() 提供系统的版本信息。

platform 模块对系统的标识有更详细的检查。

sys.platlibdir

平台专用库目录。用于构建标准库的路径和已安装扩展模块的路径。

在大多数平台上,它等同于 "lib" 。在 Fedora 和 SuSE 上,它等同于给出了以下 sys.path 路径的 64 位平台上的 "lib64" (其中 X.Y 是 Python 的 major.minor 版本)。

  • /usr/lib64/pythonX.Y/:标准库(如 os 模块的 os.py
  • /usr/lib64/pythonX.Y/lib-dynload/:标准库的 C 扩展模块(如 errno 模块,确切的文件名取决于平台)
  • /usr/lib/pythonX.Y/site-packages/ (请使用 lib, 而非 sys.platlibdir): 第三方模块
  • /usr/lib64/pythonX.Y/site-packages/: 第三方包的 C 扩展模块

3.9 新版功能.

sys.prefix

一个字符串,给出特定域的目录前缀,该目录中安装了与平台不相关的 Python 文件,默认为 '/usr/local'。该目录前缀可以在构建时使用 configure 脚本的 --prefix 参数进行设置。Python 库模块的的主要集合安装在目录 *prefix*/lib/python*X.Y* ,而与平台无关的头文件 (除了 pyconfig.h) 保存在 *prefix*/include/python*X.Y*, 其中 X.Y 是 Python 的版本号, 例如 3.2.

注解

如果在一个 虚拟环境 中,那么该值将在 site.py 中被修改,指向虚拟环境。Python 安装位置仍然可以用 base_prefix 来获取。

sys.ps1
sys.ps2

字符串,指定解释器的首要和次要提示符。仅当解释器处于交互模式时,它们才有定义。这种情况下,它们的初值为 '>>> ''... '。如果赋给其中某个变量的是非字符串对象,则每次解释器准备读取新的交互式命令时,都会重新运行该对象的 str(),这可以用来实现动态的提示符。

sys.setdlopenflags(n)

设置解释器在调用 dlopen() 时用到的标志,例如解释器在加载扩展模块时。首先,调用 sys.setdlopenflags(0) 将在导入模块时对符号启用惰性解析。要在扩展模块之间共享符号,请调用 sys.setdlopenflags(os.RTLD_GLOBAL)。标志值的符号名称可以在 os 模块中找到(即 RTLD_xxx 常量,如 os.RTLD_LAZY )。

可用性: Unix。

sys.setprofile(profilefunc)

设置系统的性能分析函数,该函数使得在 Python 中能够实现一个 Python 源代码性能分析器。性能分析函数的调用方式类似于系统的跟踪函数,但它是通过不同的事件调用的,例如,不是每执行一行代码就调用它一次(仅在调用某函数和从某函数返回时才会调用性能分析函数,但即使某函数发生异常也会算作返回事件)。该函数是特定于单个线程的,但是性能分析器无法得知线程之间的上下文切换,因此在存在多个线程的情况下使用它是没有意义的。另外,因为它的返回值不会被用到,所以可以简单地返回 None。性能分析函数中的错误将导致其自身被解除设置。

性能分析函数应接收三个参数:frameeventargframe 是当前的堆栈帧。event 是一个字符串:'call''return''c_call''c_return''c_exception'arg 取决于事件类型。

引发一个 审计事件 sys.setprofile,不附带任何参数。

这些事件具有以下含义:

  • 'call'

    表示调用了某个函数(或进入了其他的代码块)。性能分析函数将被调用,argNone

    'return'

    表示某个函数(或别的代码块)即将返回。性能分析函数将被调用,arg 是即将返回的值,如果此次返回事件是由于抛出异常,argNone

    'c_call'

    表示即将调用某个 C 函数。它可能是扩展函数或是内建函数。arg 是 C 函数对象。

    'c_return'

    表示返回了某个 C 函数。arg 是 C 函数对象。

    'c_exception'

    表示某个 C 函数抛出了异常。arg 是 C 函数对象。

sys.setrecursionlimit(limit)

将 Python 解释器堆栈的最大深度设置为 limit。此限制可防止无限递归导致的 C 堆栈溢出和 Python 崩溃。

不同平台所允许的最高限值不同。当用户有需要深度递归的程序且平台支持更高的限值,可能就需要调高限值。进行该操作需要谨慎,因为过高的限值可能会导致崩溃。

如果新的限值低于当前的递归深度,将抛出 RecursionError 异常。

在 3.5.1 版更改: 如果新的限值低于当前的递归深度,现在将抛出 RecursionError 异常。

sys.setswitchinterval(interval)

设置解释器的线程切换间隔时间(单位为秒)。该浮点数决定了“时间片”的理想持续时间,时间片将分配给同时运行的 Python 线程。请注意,实际值可能更高,尤其是使用了运行时间长的内部函数或方法时。同时,在时间间隔末尾调度哪个线程是操作系统的决定。解释器没有自己的调度程序。

3.2 新版功能.

sys.settrace(tracefunc)

设置系统的跟踪函数,使得用户在 Python 中就可以实现 Python 源代码调试器。该函数是特定于单个线程的,所以要让调试器支持多线程,必须为正在调试的每个线程都用 settrace() 注册一个跟踪函数,或使用 threading.settrace()

跟踪函数应接收三个参数:frameeventargframe 是当前的堆栈帧。event 是一个字符串:'call''line''return''exception''opcode'arg 取决于事件类型。

每次进入 trace 函数的新的局部作用范围,都会调用 trace 函数( event 会被设置为 'call' ),它应该返回一个引用,指向即将用在新作用范围上的局部跟踪函数;如果不需要跟踪当前的作用范围,则返回 None

局部跟踪函数应返回对自身的引用(或对另一个函数的引用,用来在其作用范围内进行进一步的跟踪),或者返回 None 来停止跟踪其作用范围。

如果跟踪函数出错,则该跟踪函数将被取消设置,类似于调用 settrace(None)

这些事件具有以下含义:

  • 'call'

    表示调用了某个函数(或进入了其他的代码块)。全局跟踪函数将被调用,argNone。返回值将指定局部跟踪函数。

    'line'

    表示解释器即将执行新一行代码或重新执行循环条件。局部跟踪函数将被调用,argNone,其返回值将指定新的局部跟踪函数。关于其工作原理的详细说明,请参见 Objects/lnotab_notes.txt。要在该堆栈帧禁用每行触发事件,可以在堆栈帧上将 f_trace_lines 设置为 False

    'return'

    表示某个函数(或别的代码块)即将返回。局部跟踪函数将被调用,arg 是即将返回的值,如果此次返回事件是由于抛出异常,argNone。跟踪函数的返回值将被忽略。

    'exception'

    表示发生了某个异常。局部跟踪函数将被调用,arg 是一个 (exception, value, traceback) 元组,返回值将指定新的局部跟踪函数。

    'opcode'

    表示解释器即将执行一个新的操作码。局部跟踪函数将被调用,argNone,其返回值将指定新的局部跟踪函数。每操作码触发事件默认情况下都不发出:必须在堆栈帧上将 f_trace_opcodes 显式地设置为 True 来请求这些事件。

注意,由于异常是在链式调用中传播的,所以每一级都会产生一个 'exception' 事件。

更细微的用法是,可以显式地通过赋值 frame.f_trace = tracefunc 来设置跟踪函数,而不是用现有跟踪函数的返回值去间接设置它。当前帧上的跟踪函数必须激活,而 settrace() 还没有做这件事。注意,为了使上述设置起效,必须使用 settrace() 来安装全局跟踪函数才能启用运行时跟踪机制,但是它不必与上述是同一个跟踪函数(它可以是一个开销很低的跟踪函数,只返回 None,即在各个帧上立即将其自身禁用)。

引发一个 审计事件 sys.settrace,不附带任何参数。

CPython implementation detail: settrace() 函数仅用于实现调试器,性能分析器,打包工具等。它的行为是实现平台的一部分,而不是语言定义的一部分,因此并非在所有 Python 实现中都可用。

在 3.7 版更改: 添加了 'opcode' 事件类型;为帧对象添加了 f_trace_linesf_trace_opcodes 属性

sys.set_asyncgen_hooks(firstiter, finalizer)

接受两个可选的关键字参数,要求它们是可调用对象,且接受一个 异步生成器迭代器 作为参数。firstiter 对象将在异步生成器第一次迭代时调用。finalizer 将在异步生成器即将被销毁时调用。

引发一个 审计事件 sys.set_asyncgen_hooks_firstiter,不附带任何参数。

引发一个 审计事件 sys.set_asyncgen_hooks_finalizer,不附带任何参数。

之所以会引发两个审计事件,是因为底层的 API 由两个调用组成,每个调用都须要引发自己的事件。

3.6 新版功能: 更多详情请参阅 PEP 525finalizer 方法的参考示例可参阅 Lib/asyncio/base_events.pyasyncio.Loop.shutdown_asyncgens 的实现。

注解

本函数已添加至暂定软件包(详情请参阅 PEP 411 )。

sys.set_coroutine_origin_tracking_depth(depth)

用于启用或禁用协程溯源。启用后,协程对象上的 cr_origin 属性将包含一个元组,它由多个(文件名 filename,行号 line number,函数名 function name)元组组成,整个元组描述出了协程对象创建过程的回溯,元组首端是最近一次的调用。禁用后,cr_origin 将为 None。

要启用,请向 depth 传递一个大于零的值,它指定了有多少帧将被捕获信息。要禁用,请将 depth 置为零。

该设置是特定于单个线程的。

3.7 新版功能.

注解

本函数已添加至暂定软件包(详情请参阅 PEP 411 )。仅将其用于调试目的。

sys._enablelegacywindowsfsencoding()

将 filesystem encoding and error handler 分别修改为 ‘mbcs’ 和 ‘replace’,以便与 3.6 之前版本的 Python 保持一致。

这等同于在启动 Python 前先定义好 PYTHONLEGACYWINDOWSFSENCODING 环境变量。

另请参阅 sys.getfilesystemencoding()sys.getfilesystemencodeerrors()

可用性: Windows。

3.6 新版功能: 更多详情请参阅 PEP 529

sys.stdin
sys.stdout
sys.stderr

解释器用于标准输入、标准输出和标准错误的 文件对象:

  • stdin 用于所有交互式输入(包括对 input() 的调用);
  • stdout 用于 print() 和 expression 语句的输出,以及用于 input() 的提示符;
  • 解释器自身的提示符和它的错误消息都发往 stderr

这些流都是常规 文本文件,与 open() 函数返回的对象一致。它们的参数选择如下:

  • 编码格式和错误处理句柄是由 PyConfig.stdio_encodingPyConfig.stdio_errors 来初始化的。

    在 Windows 上,控制台设备使用 UTF-8。 非字符设备如磁盘文件和管道使用系统语言区域编码格式(例如 ANSI 代码页)。 非控制台字符设备如 NUL(例如当 isatty() 返回 True 时)会在启动时分别让 stdin 和 stdout/stderr 使用控制台输入和输出代码页。 如果进程初始化时没有被附加到控制台则会使用默认的系统 locale encoding。

    要重写控制台的特殊行为,可以在启动 Python 前设置 PYTHONLEGACYWINDOWSSTDIO 环境变量。此时,控制台代码页将用于其他字符设备。

    在所有平台上,都可以通过在 Python 启动前设置 PYTHONIOENCODING 环境变量来重写字符编码,或通过新的 -X utf8 命令行选项和 PYTHONUTF8 环境变量来设置。但是,对 Windows 控制台来说,上述方法仅在设置了 PYTHONLEGACYWINDOWSSTDIO 后才起效。

  • 交互模式下,stdout 流是行缓冲的。其他情况下,它像常规文本文件一样是块缓冲的。两种情况下的 stderr 流都是行缓冲的。要使得两个流都变成无缓冲,可以传入 -u 命令行选项或设置 PYTHONUNBUFFERED 环境变量。

在 3.9 版更改: 非交互模式下,stderr 现在是行缓冲的,而不是全缓冲的。

注解

要从标准流写入或读取二进制数据,请使用底层二进制 buffer 对象。例如,要将字节写入 stdout,请使用 sys.stdout.buffer.write(b'abc')

但是,如果你在写一个库(并且不限制执行库代码时的上下文),那么请注意,标准流可能会被替换为文件类对象,如 io.StringIO,它们是不支持 buffer 属性的。

sys.__stdin__
sys.__stdout__
sys.__stderr__

程序开始时,这些对象存有 stdinstderrstdout 的初始值。它们在程序结束前都可以使用,且在需要向实际的标准流打印内容时很有用,无论 sys.std* 对象是否已重定向。

如果实际文件已经被覆盖成一个损坏的对象了,那它也可用于将实际文件还原成能正常工作的文件对象。但是,本过程的最佳方法应该是,在原来的流被替换之前就显式地保存它,并使用这一保存的对象来还原。

注解

某些情况下的 stdinstdoutstderr 以及初始值 __stdin____stdout____stderr__ 可以是 None。通常发生在未连接到控制台的 Windows GUI app 中,以及在用 pythonw 启动的 Python app 中。

sys.stdlib_module_names

一个包含标准库模组名称字符串的冻结集合。

它在所有平台上都保持一致。 在某些平台上不可用的模块和在 Python 编译时被禁用的模块也会被列出。 所有种类的模块都会被列出:纯 Python 模块、内置模块、冻结模块和扩展模块等。 测试模块则会被排除掉。

对于包来说,仅会列出主包:子包和子模块不会被列出。 例如,email 包会被列出,但 email.mime 子包和 email.message 子模块不会被列出。

3.10 新版功能.

sys.thread_info

一个 具名元组,包含线程实现的信息。

属性 说明
name 线程实现的名称:‘nt’: Windows 线程‘pthread’: POSIX 线程‘solaris’: Solaris 线程
lock 锁实现的名称:‘semaphore’: 锁使用信号量‘mutex+cond’: 锁使用互斥和条件变量None 如果此信息未知
version 线程库的名称和版本。它是一个字符串,如果此信息未知,则为 None

3.3 新版功能.

sys.tracebacklimit

当该变量值设置为整数,在发生未处理的异常时,它将决定打印的回溯信息的最大层级数。默认为 1000。当将其设置为 0 或小于 0,将关闭所有回溯信息,并且只打印异常类型和异常值。

sys.unraisablehook(unraisable, /)

处理一个无法抛出的异常。

它会在发生了一个异常但 Python 没有办法处理时被调用。例如,当一个析构器引发了异常,或在垃圾回收 (gc.collect()) 期间引发了异常。

unraisable 参数具有以下属性:

  • exc_type: 异常类型
  • exc_value: 异常值,可以是 None.
  • exc_traceback: 异常回溯,可以是 None.
  • err_msg: 错误信息,可以是 None.
  • object: 导致异常的对象,可以为 None.

默认的钩子程序会将 err_msgobject 格式化为: f'{err_msg}: {object!r}';如果 err_msgNone 则采用 “Exception ignored in” 错误信息。

要改变无法抛出的异常的处理过程,可以重写 sys.unraisablehook()

使用定制钩子存放 exc_value 可能会创建引用循环。 它应当在不再需要异常时被显式地清空以打破引用循环。

如果一个 object 正在被销毁,那么使用自定义的钩子储存该对象可能会将其复活。请在自定义钩子生效后避免储存 object,以避免对象的复活。

另请参阅 excepthook(),它处理未捕获的异常。

引发一个审计事件 sys.unraisablehook 并附带参数 hook, unraisable

3.8 新版功能.

sys.version

一个包含 Python 解释器版本号加编译版本号以及所用编译器等额外信息的字符串。 此字符串会在交互式解释器启动时显示。 请不要从中提取版本信息,而应当使用 version_info 以及 platform 模块所提供的函数。

sys.api_version

这个解释器的 C API 版本。当你在调试 Python及期扩展模板的版本冲突这个功能非常有用。

sys.version_info

一个包含版本号五部分的元组: major, minor, micro, releaselevelserial*。 除 *releaselevel 外的所有值均为整数;发布级别值则为 'alpha', 'beta', 'candidate''final'。 对应于 Python 版本 2.0 的 version_info 值为 (2, 0, 0, 'final', 0)。 这些部分也可按名称访问,因此 sys.version_info[0] 就等价于 sys.version_info.major,依此类推。

在 3.1 版更改: 增加了以名称表示的各部分属性。

sys.warnoptions

这是警告框架的一个实现细节;请不要修改此值。 有关警告框架的更多信息请参阅 warnings 模块。

sys.winver

用于在 Windows 平台上组成注册表键的版本号。 这在 Python DLL 中存储为 1000 号字符串资源。 其值通常是 version 的头三个字符。 它在 sys 模块中提供是为了信息展示目的;修改此值不会影响 Python 所使用的注册表键。

可用性: Windows。

sys._xoptions

一个字典,包含通过 -X 命令行选项传递的旗标,这些旗标专属于各种具体实现。选项名称将会映射到对应的值(如果显式指定)或者 True。例如:

$ ./python -Xa=b -Xc
Python 3.2a3+ (py3k, Oct 16 2010, 20:14:50)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys._xoptions
{'a': 'b', 'c': True}

CPython implementation detail: 这是 CPython 专属的访问通过 -X 传递的选项的方式。 其他实现可能会通过其他方式导出它们,或者完全不导出。

3.2 新版功能.

sysconfig —- Provide access to Python’s configuration information

3.2 新版功能.

源代码: Lib/sysconfig.py


The sysconfig module provides access to Python’s configuration information like the list of installation paths and the configuration variables relevant for the current platform.

配置变量

A Python distribution contains a Makefile and a pyconfig.h header file that are necessary to build both the Python binary itself and third-party C extensions compiled using distutils.

sysconfig puts all variables found in these files in a dictionary that can be accessed using get_config_vars() or get_config_var().

Notice that on Windows, it’s a much smaller set.

sysconfig.get_config_vars(\args*)

With no arguments, return a dictionary of all configuration variables relevant for the current platform.

With arguments, return a list of values that result from looking up each argument in the configuration variable dictionary.

For each argument, if the value is not found, return None.

sysconfig.get_config_var(name)

Return the value of a single variable name. Equivalent to get_config_vars().get(name).

If name is not found, return None.

用法示例:

>>> import sysconfig
>>> sysconfig.get_config_var('Py_ENABLE_SHARED')
0
>>> sysconfig.get_config_var('LIBDIR')
'/usr/local/lib'
>>> sysconfig.get_config_vars('AR', 'CXX')
['ar', 'g++']

安装路径

Python uses an installation scheme that differs depending on the platform and on the installation options. These schemes are stored in sysconfig under unique identifiers based on the value returned by os.name.

Every new component that is installed using distutils or a Distutils-based system will follow the same scheme to copy its file in the right places.

Python currently supports seven schemes:

  • posix_prefix: scheme for POSIX platforms like Linux or macOS. This is the default scheme used when Python or a component is installed.
  • posix_home: scheme for POSIX platforms used when a home option is used upon installation. This scheme is used when a component is installed through Distutils with a specific home prefix.
  • posix_user: scheme for POSIX platforms used when a component is installed through Distutils and the user option is used. This scheme defines paths located under the user home directory.
  • nt: scheme for NT platforms like Windows.
  • nt_user: scheme for NT platforms, when the user option is used.

Each scheme is itself composed of a series of paths and each path has a unique identifier. Python currently uses eight paths:

  • stdlib: directory containing the standard Python library files that are not platform-specific.
  • platstdlib: directory containing the standard Python library files that are platform-specific.
  • platlib: directory for site-specific, platform-specific files.
  • purelib: directory for site-specific, non-platform-specific files.
  • include: directory for non-platform-specific header files.
  • platinclude: directory for platform-specific header files.
  • scripts: directory for script files.
  • data: directory for data files.

sysconfig provides some functions to determine these paths.

sysconfig.get_scheme_names()

Return a tuple containing all schemes currently supported in sysconfig.

sysconfig.get_default_scheme()

Return the default scheme name for the current platform.

在 3.10 版更改: This function was previously named _get_default_scheme() and considered an implementation detail.

sysconfig.get_preferred_scheme(key)

Return a preferred scheme name for an installation layout specified by key.

key must be either "prefix", "home", or "user".

The return value is a scheme name listed in get_scheme_names(). It can be passed to sysconfig functions that take a scheme argument, such as get_paths().

3.10 新版功能.

sysconfig._get_preferred_schemes()

Return a dict containing preferred scheme names on the current platform. Python implementers and redistributors may add their preferred schemes to the _INSTALL_SCHEMES module-level global value, and modify this function to return those scheme names, to e.g. provide different schemes for system and language package managers to use, so packages installed by either do not mix with those by the other.

End users should not use this function, but get_default_scheme() and get_preferred_scheme() instead.

3.10 新版功能.

sysconfig.get_path_names()

Return a tuple containing all path names currently supported in sysconfig.

sysconfig.get_path(name[, scheme[, vars[, expand]]])

Return an installation path corresponding to the path name, from the install scheme named scheme.

name has to be a value from the list returned by get_path_names().

sysconfig stores installation paths corresponding to each path name, for each platform, with variables to be expanded. For instance the stdlib path for the nt scheme is: {base}/Lib.

get_path() will use the variables returned by get_config_vars() to expand the path. All variables have default values for each platform so one may call this function and get the default value.

If scheme is provided, it must be a value from the list returned by get_scheme_names(). Otherwise, the default scheme for the current platform is used.

If vars is provided, it must be a dictionary of variables that will update the dictionary return by get_config_vars().

If expand is set to False, the path will not be expanded using the variables.

If name is not found, raise a KeyError.

sysconfig.get_paths([scheme[, vars[, expand]]])

Return a dictionary containing all installation paths corresponding to an installation scheme. See get_path() for more information.

If scheme is not provided, will use the default scheme for the current platform.

If vars is provided, it must be a dictionary of variables that will update the dictionary used to expand the paths.

If expand is set to false, the paths will not be expanded.

If scheme is not an existing scheme, get_paths() will raise a KeyError.

其他功能

sysconfig.get_python_version()

Return the MAJOR.MINOR Python version number as a string. Similar to '%d.%d' % sys.version_info[:2].

sysconfig.get_platform()

Return a string that identifies the current platform.

This is used mainly to distinguish platform-specific build directories and platform-specific built distributions. Typically includes the OS name and version and the architecture (as supplied by ‘os.uname()’), although the exact information included depends on the OS; e.g., on Linux, the kernel version isn’t particularly important.

返回值的示例:

  • linux-i586
  • linux-alpha (?)
  • solaris-2.6-sun4u

Windows将返回以下之一:

  • win-amd64 (在 AMD64, aka x86_64, Intel64, 和 EM64T上的64位 Windows )
  • win32 (all others - specifically, sys.platform is returned)

macOS can return:

  • macosx-10.6-ppc
  • macosx-10.4-ppc64
  • macosx-10.3-i386
  • macosx-10.4-fat

对于其他非-POSIX 平台, 目前只是返回 sys.platform

sysconfig.is_python_build()

Return True if the running Python interpreter was built from source and is being run from its built location, and not from a location resulting from e.g. running make install or installing via a binary installer.

sysconfig.parse_config_h(fp[, vars])

Parse a config.h-style file.

fp is a file-like object pointing to the config.h-like file.

A dictionary containing name/value pairs is returned. If an optional dictionary is passed in as the second argument, it is used instead of a new dictionary, and updated with the values read in the file.

sysconfig.get_config_h_filename()

返回 pyconfig.h 的目录

sysconfig.get_makefile_filename()

返回 Makefile 的目录

Using sysconfig as a script

You can use sysconfig as a script with Python’s -m option:

$ python -m sysconfig
Platform: "macosx-10.4-i386"
Python version: "3.2"
Current installation scheme: "posix_prefix"
Paths:
        data = "/usr/local"
        include = "/Users/tarek/Dev/svn.python.org/py3k/Include"
        platinclude = "."
        platlib = "/usr/local/lib/python3.2/site-packages"
        platstdlib = "/usr/local/lib/python3.2"
        purelib = "/usr/local/lib/python3.2/site-packages"
        scripts = "/usr/local/bin"
        stdlib = "/usr/local/lib/python3.2"
Variables:
        AC_APPLE_UNIVERSAL_BUILD = "0"
        AIX_GENUINE_CPLUSPLUS = "0"
        AR = "ar"
        ARFLAGS = "rc"
        ...

This call will print in the standard output the information returned by get_platform(), get_python_version(), get_path() and get_config_vars().

builtins —- 内建对象

该模块提供对Python的所有“内置”标识符的直接访问;例如,builtins.open 是内置函数的全名 open()

大多数应用程序通常不会显式访问此模块,但在提供与内置值同名的对象的模块中可能很有用,但其中还需要内置该名称。例如,在一个想要实现 open() 函数的模块中,它包装了内置的 open() ,这个模块可以直接使用:

import builtins
def open(path):
    f = builtins.open(path, 'r')
    return UpperCaser(f)
class UpperCaser:
    '''Wrapper around a file that converts output to upper-case.'''
    def __init__(self, f):
        self._f = f
    def read(self, count=-1):
        return self._f.read(count).upper()
    # ...

作为一个实现细节,大多数模块都将名称 __builtins__ 作为其全局变量的一部分提供。 __builtins__ 的值通常是这个模块或者这个模块的值 __dict__ 属性。由于这是一个实现细节,因此 Python 的替代实现可能不会使用它。

__main__ —- Top-level code environment

In Python, the special name __main__ is used for two important constructs:

  1. the name of the top-level environment of the program, which can be checked using the __name__ == '__main__' expression; and
  2. the __main__.py file in Python packages.

Both of these mechanisms are related to Python modules; how users interact with them and how they interact with each other. They are explained in detail below. If you’re new to Python modules, see the tutorial section 模块 for an introduction.

__name__ == '__main__'

When a Python module or package is imported, __name__ is set to the module’s name. Usually, this is the name of the Python file itself without the .py extension:

>>> import configparser
>>> configparser.__name__
'configparser'

If the file is part of a package, __name__ will also include the parent package’s path:

>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'

However, if the module is executed in the top-level code environment, its __name__ is set to the string '__main__'.

What is the “top-level code environment”?

__main__ is the name of the environment where top-level code is run. “Top-level code” is the first user-specified Python module that starts running. It’s “top-level” because it imports all other modules that the program needs. Sometimes “top-level code” is called an entry point to the application.

The top-level code environment can be:

  • the scope of an interactive prompt:

    >>> __name__
    '__main__'
  • the Python module passed to the Python interpreter as a file argument:

    $ python3 helloworld.py
    Hello, world!
  • the Python module or package passed to the Python interpreter with the -m argument:

    $ python3 -m tarfile
    usage: tarfile.py [-h] [-v] (...)
  • Python code read by the Python interpreter from standard input:

    $ echo "import this" | python3
    The Zen of Python, by Tim Peters
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...
  • Python code passed to the Python interpreter with the -c argument:

    $ python3 -c "import this"
    The Zen of Python, by Tim Peters
    Beautiful is better than ugly.
    Explicit is better than implicit.
    ...

In each of these situations, the top-level module’s __name__ is set to '__main__'.

As a result, a module can discover whether or not it is running in the top-level environment by checking its own __name__, which allows a common idiom for conditionally executing code when the module is not initialized from an import statement:

if __name__ == '__mainif __name__ == '__main__':
    # Execute when the module is not initialized from an import statement.
    ...__':    # Execute when the module is not initialized from an import statement.    ...

参见

For a more detailed look at how __name__ is set in all situations, see the tutorial section 模块.

Idiomatic Usage

Some modules contain code that is intended for script use only, like parsing command-line arguments or fetching data from standard input. When a module like this were to be imported from a different module, for example to unit test it, the script code would unintentionally execute as well.

This is where using the if __name__ == '__main__' code block comes in handy. Code within this block won’t run unless the module is executed in the top-level environment.

Putting as few statements as possible in the block below if __name___ == '__main__' can improve code clarity and correctness. Most often, a function named main encapsulates the program’s primary behavior:

# echo.py
import shlex
import sys
def echo(phrase: str) -> None:
   """A dummy wrapper around print."""
   # for demonstration purposes, you can imagine that there is some
   # valuable and reusable logic inside this function
   print(phrase)
def main() -> int:
    """Echo the input arguments to standard output"""
    phrase = shlex.join(sys.argv)
    echo(phrase)
    return 0
if __name__ == '__main__':
    sys.exit(main())  # next section explains the use of sys.exit

Note that if the module didn’t encapsulate code inside the main function but instead put it directly within the if __name__ == '__main__' block, the phrase variable would be global to the entire module. This is error-prone as other functions within the module could be unintentionally using the global variable instead of a local name. A main function solves this problem.

Using a main function has the added benefit of the echo function itself being isolated and importable elsewhere. When echo.py is imported, the echo and main functions will be defined, but neither of them will be called, because __name__ != '__main__'.

Packaging Considerations

main functions are often used to create command-line tools by specifying them as entry points for console scripts. When this is done, pip inserts the function call into a template script, where the return value of main is passed into sys.exit(). For example:

sys.exit(main())

Since the call to main is wrapped in sys.exit(), the expectation is that your function will return some value acceptable as an input to sys.exit(); typically, an integer or None (which is implicitly returned if your function does not have a return statement).

By proactively following this convention ourselves, our module will have the same behavior when run directly (i.e. python3 echo.py) as it will have if we later package it as a console script entry-point in a pip-installable package.

In particular, be careful about returning strings from your main function. sys.exit() will interpret a string argument as a failure message, so your program will have an exit code of 1, indicating failure, and the string will be written to sys.stderr. The echo.py example from earlier exemplifies using the sys.exit(main()) convention.

参见

Python Packaging User Guide contains a collection of tutorials and references on how to distribute and install Python packages with modern tools.

__main__.py in Python Packages

If you are not familiar with Python packages, see section 包 of the tutorial. Most commonly, the __main__.py file is used to provide a command-line interface for a package. Consider the following hypothetical package, “bandclass”:

bandclass
  ├── __init__.py
  ├── __main__.py
  └── student.py

__main__.py will be executed when the package itself is invoked directly from the command line using the -m flag. For example:

$ python3 -m bandclass

This command will cause __main__.py to run. How you utilize this mechanism will depend on the nature of the package you are writing, but in this hypothetical case, it might make sense to allow the teacher to search for students:

# bandclass/__main__.py
import sys
from .student import search_students
student_name = sys.argv[2] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')

Note that from .student import search_students is an example of a relative import. This import style must be used when referencing modules within a package. For more details, see 子包参考 in the 模块 section of the tutorial.

Idiomatic Usage

The contents of __main__.py typically isn’t fenced with if __name__ == '__main__' blocks. Instead, those files are kept short, functions to execute from other modules. Those other modules can then be easily unit-tested and are properly reusable.

If used, an if __name__ == '__main__' block will still work as expected for a __main__.py file within a package, because its __name__ attribute will include the package’s path if imported:

>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'

This won’t work for __main__.py files in the root directory of a .zip file though. Hence, for consistency, minimal __main__.py like the venv one mentioned above are preferred.

参见

See venv for an example of a package with a minimal __main__.py in the standard library. It doesn’t contain a if __name__ == '__main__' block. You can invoke it with python3 -m venv [directory].

See runpy for more details on the -m flag to the interpreter executable.

See zipapp for how to run applications packaged as .zip files. In this case Python looks for a __main__.py file in the root directory of the archive.

import __main__

Regardless of which module a Python program was started with, other modules running within that same program can import the top-level environment’s scope (namespace) by importing the __main__ module. This doesn’t import a __main__.py file but rather whichever module that received the special name '__main__'.

Here is an example module that consumes the __main__ namespace:

# namely.py
import __main__
def did_user_define_their_name():
    return 'my_name' in dir(__main__)
def print_user_name():
    if not did_user_define_their_name():
        raise ValueError('Define the variable `my_name`!')
    if '__file__' in dir(__main__):
        print(__main__.my_name, "found in file", __main__.__file__)
    else:
        print(__main__.my_name)

Example usage of this module could be as follows:

# start.py
import sys
from namely import print_user_name
# my_name = "Dinsdale"
def main():
    try:
        print_user_name()
    except ValueError as ve:
        return str(ve)
if __name__ == "__main__":
    sys.exit(main())

Now, if we started our program, the result would look like this:

$ python3 start.py
Define the variable `my_name`!

The exit code of the program would be 1, indicating an error. Uncommenting the line with my_name = "Dinsdale" fixes the program and now it exits with status code 0, indicating success:

$ python3 start.py
Dinsdale found in file /path/to/start.py

Note that importing __main__ doesn’t cause any issues with unintentionally running top-level code meant for script use which is put in the if __name__ == "__main__" block of the start module. Why does this work?

Python inserts an empty __main__ module in sys.modules at interpreter startup, and populates it by running top-level code. In our example this is the start module which runs line by line and imports namely. In turn, namely imports __main__ (which is really start). That’s an import cycle! Fortunately, since the partially populated __main__ module is present in sys.modules, Python passes that to namely. See Special considerations for main in the import system’s reference for details on how this works.

The Python REPL is another example of a “top-level environment”, so anything defined in the REPL becomes part of the __main__ scope:

>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
...
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
True
>>> namely.print_user_name()
Jabberwocky

Note that in this case the __main__ scope doesn’t contain a __file__ attribute as it’s interactive.

The __main__ scope is used in the implementation of pdb and rlcompleter.

warnings —— 警告信息的控制

源代码: Lib/warnings.py


通常以下情况会引发警告:提醒用户注意程序中的某些情况,而这些情况(通常)还不值得触发异常并终止程序。例如,当程序用到了某个过时的模块时,就可能需要发出一条警告。

Python 程序员可调用本模块中定义的 warn() 函数来发布警告。(C 语言程序员则用 PyErr_WarnEx() )。

警告信息通常会写入 sys.stderr ,但可以灵活改变,从忽略所有警告到变成异常都可以。警告的处理方式可以依据 警告类型 、警告信息的文本和发出警告的源位置而进行变化。同一源位置重复出现的警告通常会被抑制。

控制警告信息有两个阶段:首先,每次引发警告时,决定信息是否要发出;然后,如果要发出信息,就用可由用户设置的钩子进行格式化并打印输出。

警告过滤器 控制着是否发出警告信息,也即一系列的匹配规则和动作。调用 filterwarnings() 可将规则加入过滤器,调用 resetwarnings() 则可重置为默认状态。

警告信息的打印输出是通过调用 showwarning() 完成的,该函数可被重写;默认的实现代码是调用 formatwarning() 进行格式化,自己编写的代码也可以调用此格式化函数。

参见

利用 logging.captureWarnings() 可以采用标准的日志架构处理所有警告。

警告类别

警告的类别由一些内置的异常表示。这种分类有助于对警告信息进行分组过滤。

虽然在技术上警告类别属于 内置异常,但也只是在此记录一下而已,因为在概念上他们属于警告机制的一部分。

通过对某个标准的警告类别进行派生,用户代码可以定义其他的警告类别。 警告类别必须是 Warning 类的子类。

目前已定义了以下警告类别的类:

描述
Warning 这是所有警告类别的基类。它是 Exception 的子类。
UserWarning The default category for warn().
DeprecationWarning 已废弃特性警告的基类,这些警告是为其他 Python 开发者准备的(默认会忽略,除非在 **main** 中用代码触发)。
SyntaxWarning 用于警告可疑语法的基类。
RuntimeWarning 用于警告可疑运行时特性的基类。
FutureWarning 用于警告已废弃特性的基类,这些警告是为 Python 应用程序的最终用户准备的。
PendingDeprecationWarning 用于警告即将废弃功能的基类(默认忽略)。
ImportWarning 导入模块时触发的警告的基类(默认忽略)。
UnicodeWarning 用于 Unicode 相关警告的基类。
BytesWarning bytesbytearray 相关警告的基类。
ResourceWarning 资源利用相关警告的基类。

在 3.7 版更改: 以前 DeprecationWarningFutureWarning 是根据某个功能是否完全删除或改变其行为来区分的。现在是根据受众和默认警告过滤器的处理方式来区分的。

警告过滤器

警告过滤器控制着警告是否被忽略、显示或转为错误(触发异常)。

从概念上讲,警告过滤器维护着一个经过排序的过滤器类别列表;任何具体的警告都会依次与列表中的每种过滤器进行匹配,直到找到一个匹配项;过滤器决定了匹配项的处理方式。每个列表项均为 ( action , message , category , module , lineno ) 格式的元组,其中:

  • action 是以下字符串之一:

    处置
    “default” 为发出警告的每个位置(模块+行号)打印第一个匹配警告
    “error” 将匹配警告转换为异常
    “ignore” 从不打印匹配的警告
    “always” 总是打印匹配的警告
    “module” 为发出警告的每个模块打印第一次匹配警告(无论行号如何)
    “once” 无论位置如何,仅打印第一次出现的匹配警告
  • message 是包含正则表达式的字符串,警告信息的开头必须与之匹配。该表达式编译时不区分大小写。

  • category 是警告类别的类(Warning 的子类),警告类别必须是其子类,才能匹配。

  • module 是个字符串,包含了模块名称必须匹配的正则表达式。该表达式编译时大小写敏感。

  • lineno 是个整数,发生警告的行号必须与之匹配,或为 0 表示与所有行号匹配。

由于 Warning 类是由内置类 Exception 派生出来的,要把某个警告变成错误,只要触发category(message) 即可。

如果警告不匹配所有已注册的过滤器,那就会应用 “default” 动作(正如其名)。

警告过滤器的介绍

警告过滤器由传给 Python 解释器的命令行 -W 选项和 PYTHONWARNINGS 环境变量初始化。解释器在 sys.warningoptions 中保存了所有给出的参数,但不作解释;warnings 模块在第一次导入时会解析这些参数(无效的选项被忽略,并会先向 sys.stderr 打印一条信息)。

每个警告过滤器的设定格式为冒号分隔的字段序列:

action:message:category:module:line

这些字段的含义在 警告过滤器 中描述。当一行中列出多个过滤器时(如 PYTHONWARNINGS),过滤器间用逗号隔开,后面的优先于前面的(因为是从左到右应用的,最近应用的过滤器优先于前面的)。

常用的警告过滤器适用于所有的警告、特定类别的警告、由特定模块和包引发的警告。下面是一些例子:

default                      # Show all warnings (even those ignored by default)
ignore                       # Ignore all warnings
error                        # Convert all warnings to errors
error::ResourceWarning       # Treat ResourceWarning messages as errors
default::DeprecationWarning  # Show DeprecationWarning messages
ignore,default:::mymodule    # Only report warnings triggered by "mymodule"
error:::mymodule[.*]         # Convert warnings to errors in "mymodule"
                             # and any subpackages of "mymodule"

默认警告过滤器

Python 默认安装了几个警告过滤器,可以通过 -W 命令行参数、 PYTHONWARNINGS 环境变量及调用 filterwarnings() 进行覆盖。

在常规发布的版本中,默认的警告过滤器包括(按优先顺序排列):

default::DeprecationWarning:__main__
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::ResourceWarning

在 调试版本 中,默认警告过滤器的列表是空的。

在 3.2 版更改: 除了 PendingDeprecationWarning 之外,DeprecationWarning 现在默认会被忽略。

在 3.7 版更改: DeprecationWarning 在被 __main__ 中的代码直接触发时,默认会再次显示。

在 3.7 版更改: 如果指定两次 -b,则 BytesWarning 不再出现在默认的过滤器列表中,而是通过 sys.warningoptions 进行配置。

重写默认的过滤器

Python 应用程序的开发人员可能希望在默认情况下向用户隐藏 所有 Python级别的警告,而只在运行测试或其他调试时显示这些警告。用于向解释器传递过滤器配置的 sys.warningoptions 属性可以作为一个标记,表示是否应该禁用警告:

import sys
if not sys.warnoptions:
    import warnings
    warnings.simplefilter("ignore")

建议 Python 代码测试的开发者使用如下代码,以确保被测代码默认显示 所有 警告:

import sys
if not sys.warnoptions:
    import os, warnings
    warnings.simplefilter("default") # Change the filter in this process
    os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses

最后,建议在 __main__ 以外的命名空间运行用户代码的交互式开发者,请确保 DeprecationWarning 在默认情况下是可见的,可采用如下代码(这里 user_ns 是用于执行交互式输入代码的模块):

import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
                                   module=user_ns.get("__name__"))

暂时禁止警告

如果明知正在使用会引起警告的代码,比如某个废弃函数,但不想看到警告(即便警告已经通过命令行作了显式配置),那么可以使用 catch_warnings 上下文管理器来抑制警告。

import warnings
def fxn():
    warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    fxn()

在上下文管理器中,所有的警告将被简单地忽略。这样就能使用已知的过时代码而又不必看到警告,同时也不会限制警告其他可能不知过时的代码。注意:只能保证在单线程应用程序中生效。如果两个以上的线程同时使用 catch_warnings 上下文管理器,行为不可预知。

测试警告

要测试由代码引发的警告,请采用 catch_warnings 上下文管理器。有了它,就可以临时改变警告过滤器以方便测试。例如,以下代码可捕获所有的警告以便查看:

import warnings
def fxn():
    warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

也可以用 error 取代 always ,让所有的警告都成为异常。需要注意的是,如果某条警告已经因为 once / default 规则而被引发,那么无论设置什么过滤器,该条警告都不会再出现,除非该警告有关的注册数据被清除。

一旦上下文管理器退出,警告过滤器将恢复到刚进此上下文时的状态。这样在多次测试时可防止意外改变警告过滤器,从而导致不确定的测试结果。模块中的 showwarning() 函数也被恢复到初始值。注意:这只能在单线程应用程序中得到保证。如果两个以上的线程同时使用 catch_warnings 上下文管理器,行为未定义。

当测试多项操作会引发同类警告时,重点是要确保每次操作都会触发新的警告(比如,将警告设置为异常并检查操作是否触发异常,检查每次操作后警告列表的长度是否有增加,否则就在每次新操作前将以前的警告列表项删除)。

为新版本的依赖关系更新代码

在默认情况下,主要针对 Python 开发者(而不是 Python 应用程序的最终用户)的警告类别,会被忽略。

值得注意的是,这个“默认忽略”的列表包含 DeprecationWarning (适用于每个模块,除了 __main__),这意味着开发人员应该确保在测试代码时应将通常忽略的警告显示出来,以便未来破坏性 API 变化时及时收到通知(无论是在标准库还是第三方包)。

理想情况下,代码会有一个合适的测试套件,在运行测试时会隐含地启用所有警告(由 unittest 模块提供的测试运行程序就是如此)。

在不太理想的情况下,可以通过向 Python 解释器传入 -Wd (这是 -W default 的简写) 或设置环境变量 PYTHONWARNINGS=default 来检查应用程序是否用到了已弃用的接口。 这样可以启用对所有警告的默认处理操作,包括那些默认忽略的警告。 要改变遇到警告后执行的动作,可以改变传给 -W 的参数 (例如 -W error)。

可用的函数

warnings.warn(message, category=None, stacklevel=1, source=None)

引发警告、忽略或者触发异常。 如果给出 category 参数,则必须是 警告类别类 ;默认为 UserWarning。 或者 message 可为 Warning 的实例,这时 category 将被忽略,转而采用 message.__class__。 在这种情况下,错误信息文本将是 str(message)。 如果某条警告被 警告过滤器 改成了错误,本函数将触发一条异常。 参数 stacklevel 可供 Python 包装函数使用,比如:

def deprecation(message):    
    warnings.warn(message, DeprecationWarning, stacklevel=2)

这会让警告指向 deprecation() 的调用者,而不是 deprecation() 本身的来源(因为后者会破坏引发警告的目的)。

source 是发出 ResourceWarning 的被销毁对象。

在 3.6 版更改: 加入 source 参数。

warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)

这是 warn() 函数的底层接口,显式传入消息、类别、文件名和行号,以及可选的模块名和注册表(应为模块的 __warningregistry__ 字典)。 模块名称默认为去除了 .py 的文件名;如果未传递注册表,警告就不会被抑制。 message 必须是个字符串,categoryWarning 的子类;或者message 可为 Warning 的实例,且 category 将被忽略。

module_globals 应为发出警告的代码所用的全局命名空间。(该参数用于从 zip 文件或其他非文件系统导入模块时显式源码)。

source 是发出 ResourceWarning 的被销毁对象。

在 3.6 版更改: 加入 source 参数。

warnings.showwarning(message, category, filename, lineno, file=None, line=None)

将警告信息写入文件。默认的实现代码是调用formatwarning(message, category, filename, lineno, line) 并将结果字符串写入 file ,默认文件为 sys.stderr。通过将任何可调用对象赋给 warnings.showwarning 可替换掉该函数。line 是要包含在警告信息中的一行源代码;如果未提供 lineshowwarning() 将尝试读取由filenamelineno 指定的行。

warnings.formatwarning(message, category, filename, lineno, line=None)

以标准方式格式化一条警告信息。将返回一个字符串,可能包含内嵌的换行符,并以换行符结束。如果未提供 line*,formatwarning() 将尝试读取由 *filenamelineno 指定的行。

warnings.filterwarnings(action, message=’’, category=Warning, module=’’, lineno=0, append=False)

在 警告过滤器种类 列表中插入一条数据项。默认情况下,该数据项将被插到前面;如果 append 为 True,则会插到后面。这里会检查参数的类型,编译 messagemodule 正则表达式,并将他们作为一个元组插入警告过滤器的列表中。如果两者都与某种警告匹配,那么靠近列表前面的数据项就会覆盖后面的项。省略的参数默认匹配任意值。

warnings.simplefilter(action, category=Warning, lineno=0, append=False)

在 警告过滤器种类 列表中插入一条简单数据项。函数参数的含义与 filterwarnings() 相同,但不需要正则表达式,因为插入的过滤器总是匹配任何模块中的任何信息,只要类别和行号匹配即可。

warnings.resetwarnings()

重置警告过滤器。这将丢弃之前对 filterwarnings() 的所有调用,包括 -W 命令行选项和对 simplefilter() 的调用效果。

可用的上下文管理器

class warnings.catch_warnings(**, record=False, module=None*)

该上下文管理器会复制警告过滤器和 showwarning() 函数,并在退出时恢复。 如果 record 参数是 False (默认),则在进入时会返回 None。 如果 recordTrue,则返回一个列表,列表由自定义 showwarning() 函数所用对象逐步填充(该函数还会抑制 sys.stdout 的输出)。 列表中每个对象的属性与 showwarning() 的参数名称相同。

module 参数代表一个模块,当导入 warnings 时,将被用于代替返回的模块,其过滤器将被保护。该参数主要是为了测试 warnings 模块自身。

注解

catch_warnings 管理器的工作方式,是替换并随后恢复模块的 showwarning() 函数和内部的过滤器种类列表。这意味着上下文管理器将会修改全局状态,因此不是线程安全的。

dataclasses —- 数据类

源码: Lib/dataclasses.py


这个模块提供了一个装饰器和一些函数,用于自动添加生成的 special method,例如 __init__()__repr__() 到用户定义的类。 它最初描述于 PEP 557

在这些生成的方法中使用的成员变量是使用 PEP 526 类型标注来定义的。 例如以下代码:

from dataclasses import dataclass
@dataclass
class InventoryItem:
    """Class for keeping track of an item in inventory."""
    name: str
    unit_price: float
    quantity_on_hand: int = 0
    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

将在添加的内容中包括如下所示的 __init__():

def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
    self.name = name
    self.unit_price = unit_price
    self.quantity_on_hand = quantity_on_hand

请注意,此方法会自动添加到类中:它不会在上面显示的 InventoryItem 定义中直接指定。

3.7 新版功能.

模块内容

@``dataclasses.dataclass(**, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False*)

这个函数是 decorator ,用于将生成的 special method 添加到类中,如下所述。

dataclass() 装饰器会检查类以查找 fieldfield 被定义为具有 类型标注 的类变量。 除了下面描述的两个例外,在 dataclass() 中没有什么东西会去检查在变量标注中所指定的类型。

所有生成的方法中的字段顺序是它们在类定义中出现的顺序。

dataclass() 装饰器将向类中添加各种“dunder”方法,如下所述。 如果所添加的方法已存在于类中,则行为将取决于下面所列出的参数。 装饰器会返回调用它的类本身;不会创建新的类。

如果 dataclass() 仅用作没有参数的简单装饰器,它就像它具有此签名中记录的默认值一样。也就是说,这三种 dataclass() 用法是等价的:

@dataclass
class C:
    ...
@dataclass()
class C:
    ...
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False)
class C:
   ...

dataclass() 的参数有:

  • init: 如果为真值(默认),将生成一个 __init__() 方法。

    如果类已定义 __init__() ,则忽略此参数。

  • repr :如果为真值(默认),将生成一个 __repr__() 方法。 生成的 repr 字符串将具有类名以及每个字段的名称和 repr ,按照它们在类中定义的顺序。不包括标记为从 repr 中排除的字段。 例如:InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)

    如果类已定义 __repr__() ,则忽略此参数。

  • eq :如果为true(默认值),将生成 __eq__() 方法。此方法将类作为其字段的元组按顺序比较。比较中的两个实例必须是相同的类型。

    如果类已定义 __eq__() ,则忽略此参数。

  • order :如果为真值(默认为 False ),则 __lt__()__le__()__gt__()__ge__() 方法将生成。 这将类作为其字段的元组按顺序比较。比较中的两个实例必须是相同的类型。如果 order 为真值并且 eq 为假值 ,则引发 ValueError

    如果类已经定义了 __lt__()__le__()__gt__() 或者 __ge__() 中的任意一个,将引发 TypeError

  • unsafe_hash :如果为 False (默认值),则根据 eqfrozen 的设置方式生成 __hash__() 方法。

    __hash__() 由内置的 hash() 使用,当对象被添加到散列集合(如字典和集合)时。有一个 __hash__() 意味着类的实例是不可变的。可变性是一个复杂的属性,取决于程序员的意图, __eq__() 的存在性和行为,以及 dataclass() 装饰器中 eqfrozen 标志的值。

    默认情况下, dataclass() 不会隐式添加 __hash__() 方法,除非这样做是安全的。 它也不会添加或更改现有的明确定义的 __hash__() 方法。 设置类属性 __hash__ = None 对 Python 具有特定含义,如 __hash__() 文档中所述。

    如果 __hash__() 没有显式定义,或者它被设为 None,则 dataclass() 可能 会添加一个隐式 __hash__() 方法。 虽然并不推荐,但你可以用 unsafe_hash=True 来强制 dataclass() 创建一个 __hash__() 方法。 如果你的类在逻辑上不可变但却仍然可被修改那么可能就是这种情况。 这是一个特殊用例并且应当被仔细地考虑。

    以下是隐式创建 __hash__() 方法的规则。请注意,你不能在数据类中都使用显式的 __hash__() 方法并设置 unsafe_hash=True ;这将导致 TypeError

    如果 eqfrozen 都是 true,默认情况下 dataclass() 将为你生成一个 __hash__() 方法。如果 eq 为 true 且 frozen 为 false ,则 __hash__() 将被设置为 None ,标记它不可用(因为它是可变的)。如果 eq 为 false ,则 __hash__() 将保持不变,这意味着将使用超类的 __hash__() 方法(如果超类是 object ,这意味着它将回到基于id的hash)。

  • frozen: 如为真值 (默认值为 False),则对字段赋值将会产生异常。 这模拟了只读的冻结实例。 如果在类中定义了 __setattr__()__delattr__() 则将会引发 TypeError。 参见下文的讨论。

  • match_args: 如果为真值 (默认值为 True),则将根据传给生成的 __init__() 方法的形参列表来创建 __match_args__ 元组 (即使没有生成 __init__() 也会创建,见上文)。 如果为假值,或者如果 __match_args__ 已在类中定义,则将不生成 __match_args__

3.10 新版功能.

  • kw_only: 如果为真值 (默认值为 False),则所有字段都将被标记为仅限关键字。 如果一个字段被标记为仅限关键字,则其唯一的影响是根据仅限关键字的字段生成的 __init__() 形参必须使用调用 __init__() 时传入的关键字来指定。 对于 dataclass 的任何其它方面都没有影响。

3.10 新版功能.

  • slots: 如果为真值 (默认值为 False),则将生成 __slots__ 属性并将返回一个新类而非原来的类。 如果 __slots__ 已在类中定义,则会引发 TypeError

3.10 新版功能.

fields 可以选择使用普通的 Python 语法指定默认值:

@dataclass
class C:
    a: int       # 'a' has no default value
    b: int = 0   # assign a default value for 'b'

在这个例子中, ab 都将包含在添加的 __init__() 方法中,它们将被定义为:

def __init__(self, a: int, b: int = 0):

如果具有默认值的字段之后存在没有默认值的字段,将会引发 TypeError。 无论此情况是发生在单个类中还是作为类继承的结果,都是如此。

dataclasses.field(**, default=MISSING, default_factory=MISSING, init=True, repr=True, hash=None, compare=True, metadata=None, kw_only=MISSING*)

对于常见和简单的用例,不需要其他功能。但是,有些数据类功能需要额外的每字段信息。为了满足这种对附加信息的需求,你可以通过调用提供的 field() 函数来替换默认字段值。例如:

@dataclass
class C:
    mylist: list[int] = field(default_factory=list)
c = C()
c.mylist += [1, 2, 3]

As shown above, the MISSING value is a sentinel object used to detect if some parameters are provided by the user. This sentinel is used because None is a valid value for some parameters with a distinct meaning. No code should directly use the MISSING value.

field() 参数有:

  • default :如果提供,这将是该字段的默认值。这是必需的,因为 field() 调用本身会替换一般的默认值。

  • default_factory :如果提供,它必须是一个零参数可调用对象,当该字段需要一个默认值时,它将被调用。除了其他目的之外,这可以用于指定具有可变默认值的字段,如下所述。 同时指定 defaultdefault_factory 将产生错误。

  • init :如果为true(默认值),则该字段作为参数包含在生成的 __init__() 方法中。

  • repr :如果为true(默认值),则该字段包含在生成的 __repr__() 方法返回的字符串中。

  • hash :这可以是布尔值或 None 。如果为true,则此字段包含在生成的 __hash__() 方法中。如果为 None (默认值),请使用 compare 的值,这通常是预期的行为。如果字段用于比较,则应在 hash 中考虑该字段。不鼓励将此值设置为 None 以外的任何值。

    设置 hash=Falsecompare=True 的一个可能原因是,如果一个计算 hash 的代价很高的字段是检验等价性需要的,但还有其他字段可以计算类型的 hash 。 即使从 hash 中排除某个字段,它仍将用于比较。

  • compare :如果为true(默认值),则该字段包含在生成的相等性和比较方法中( __eq__()__gt__() 等等)。

  • metadata :这可以是映射或 None 。 None 被视为一个空的字典。这个值包含在 MappingProxyType() 中,使其成为只读,并暴露在 Field 对象上。数据类根本不使用它,它是作为第三方扩展机制提供的。多个第三方可以各自拥有自己的键值,以用作元数据中的命名空间。

  • kw_only: 如果为真值,则此字段将被标记为仅限关键字。 这将在当计算出所生成的 __init__() 方法的形参时被使用。

3.10 新版功能.

如果通过调用 field() 指定字段的默认值,则该字段的类属性将替换为指定的 default 值。如果没有提供 default ,那么将删除类属性。目的是在 dataclass() 装饰器运行之后,类属性将包含字段的默认值,就像指定了默认值一样。例如,之后:

@dataclass
class C:
    x: int
    y: int = field(repr=False)
    z: int = field(repr=False, default=10)
    t: int = 20

类属性 C.z 将是 10 ,类属性 C.t 将是 20,类属性 C.xC.y 将不设置。

class dataclasses.Field

Field 对象描述每个定义的字段。这些对象在内部创建,并由 fields() 模块级方法返回(见下文)。用户永远不应该直接实例化 Field 对象。 其有文档的属性是:

  • name :字段的名字。
  • type :字段的类型。
  • default, default_factory, init, repr, hash, compare, metadatakw_only 具有与 field() 函数中对应参数相同的含义和值。

可能存在其他属性,但它们是私有的,不能被审查或依赖。

dataclasses.fields(class_or_instance)

返回 Field 对象的元组,用于定义此数据类的字段。 接受数据类或数据类的实例。如果没有传递一个数据类或实例将引发 TypeError 。 不返回 ClassVarInitVar 的伪字段。

dataclasses.asdict(instance, **, dict_factory=dict*)

将数据类 instance 转换为字典(使用工厂函数 dict_factory )。每个数据类都转换为其字段的字典,如 name: value 对。数据类、字典、列表和元组被递归。例如:

@dataclass
class Point:
     x: int
     y: int
@dataclass
class C:
     mylist: list[Point]
p = Point(10, 20)
assert asdict(p) == {'x': 10, 'y': 20}
c = C([Point(0, 0), Point(10, 4)])
assert asdict(c) == {'mylist': [{'x': 0, 'y': 0}, {'x': 10, 'y': 4}]}

引发 TypeError 如果 instance 不是数据类实例。

dataclasses.astuple(instance, **, tuple_factory=tuple*)

将数据类 instance 转换为元组(通过使用工厂函数 tuple_factory )。每个数据类都转换为其字段值的元组。数据类、字典、列表和元组被递归。

继续前一个例子:

assert astuple(p) == (10, 20)
assert astuple(c) == ([(0, 0), (10, 4)],)

引发 TypeError 如果 instance 不是数据类实例。

dataclasses.make_dataclass(cls_name, fields, **, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False*)

新建一个名为 cls_name 的数据库,其字段在 fields 中定义,基类在 bases 中给出,并使用在 namespace 中给出的命名空间进行初始化。 fields 是一个可迭代对象,其中的每个元素均为 name, (name, type)(name, type, Field)。 如果只提供了 name,则 typing.Any 会被用作 typeinit, repr, eq, order, unsafe_hash, frozen, match_args, kw_onlyslots 等值与它们在 dataclass() 中的含义相同。

此函数不是严格要求的,因为用于任何创建带有 __annotations__ 的新类的 Python 机制都可以应用 dataclass() 函数将该类转换为数据类。提供此功能是为了方便。例如:

C = make_dataclass('C',
                   [('x', int),
                     'y',
                    ('z', int, field(default=5))],
                   namespace={'add_one': lambda self: self.x + 1})

等价于

@dataclass
class C:
    x: int
    y: 'typing.Any'
    z: int = 5
    def add_one(self):
        return self.x + 1

dataclasses.replace(instance, /, **changes)

创建一个与 instance 的类型相同的新对象,用来自 changes 的值替换各个字段。 如果 instance 不是数据类,则会引发 TypeError。 如果 changes 中的值没有指定字段,则会引发 TypeError

新返回的对象通过调用数据类的 __init__() 方法创建。这确保了如果存在 __post_init__() ,其也被调用。

如果存在没有默认值的仅初始化变量,必须在调用 replace() 时指定,以便它们可以传递给 __init__()__post_init__()

changes 包含任何定义为 init=False 的字段是错误的。在这种情况下会引发 ValueError

提前提醒 init=False 字段在调用 replace() 时的工作方式。如果它们完全被初始化的话,它们不是从源对象复制的,而是在 __post_init__() 中初始化。估计 init=False 字段很少能被正确地使用。如果使用它们,那么使用备用类构造函数或者可能是处理实例复制的自定义 replace() (或类似命名的)方法可能是明智的。

dataclasses.is_dataclass(class_or_instance)

如果其形参为 dataclass 或其实例则返回 True,否则返回 False

如果你需要知道一个类是否是一个数据类的实例(而不是一个数据类本身),那么再添加一个 not isinstance(obj, type) 检查:

def is_dataclass_instance(obj):
    return is_dataclass(obj) and not isinstance(obj, type)

dataclasses.MISSING

一个表示缺失 default 或 default_factory 的监视值。

dataclasses.KW_ONLY

一个用作类型标注的监视值。 任何在伪字段之后的类型为 KW_ONLY 的字段会被标记为仅限关键字字段。 请注意在其他情况下 KW_ONLY 类型的伪字段会被完全忽略。 这包括此类字段的名称。 根据惯例,名称 _ 会被用作 KW_ONLY 字段。 仅限关键字字段指明当类被实例化时 __init__() 形参必须以关键字形式来指定。

在这个例子中,字段 yz 将被标记为仅限关键字字段:

@dataclass
class Point:
  x: float
  _: KW_ONLY
  y: float
  z: float
p = Point(0, y=1.5, z=2.0)

在单个数据类中,指定一个以上 KW_ONLY 类型的字段将导致错误。

exception dataclasses.FrozenInstanceError

在使用 frozen=True 定义的数据类上调用隐式定义的 __setattr__()__delattr__() 时引发。 这是 AttributeError 的一个子类。

初始化后处理

生成的 __init__() 代码将调用一个名为 __post_init__() 的方法,如果在类上已经定义了 __post_init__() 。它通常被称为 self.__post_init__() 。但是,如果定义了任何 InitVar 字段,它们也将按照它们在类中定义的顺序传递给 __post_init__() 。 如果没有 __init__() 方法生成,那么 __post_init__() 将不会被自动调用。

在其他用途中,这允许初始化依赖于一个或多个其他字段的字段值。例如:

@dataclass
class C:
    a: float
    b: float
    c: float = field(init=False)
    def __post_init__(self):
        self.c = self.a + self.b

dataclass() 所生成的 __init__() 方法不会调用基类的 __init__() 方法。 如果基类有需要被调用的 __init__() 方法,通常是在 __post_init__() 方法中调用此方法:

@dataclass
class Rectangle:
    height: float
    width: float
@dataclass
class Square(Rectangle):
    side: float
    def __post_init__(self):
        super().__init__(self.side, self.side)

但是请注意,一般来说 dataclass 生成的 __init__() 方法不需要被调用,因为派生的 dataclass 将负责初始化任何自身为 dataclass 的基类的所有字段。

有关将参数传递给 __post_init__() 的方法,请参阅下面有关仅初始化变量的段落。

类变量

两个地方 dataclass() 实际检查字段类型的之一是确定字段是否是如 PEP 526 所定义的类变量。它通过检查字段的类型是否为 typing.ClassVar 来完成此操作。如果一个字段是一个 ClassVar ,它将被排除在考虑范围之外,并被数据类机制忽略。这样的 ClassVar 伪字段不会由模块级的 fields() 函数返回。

仅初始化变量

另一个 dataclass() 检查类型注解地方是为了确定一个字段是否是一个仅初始化变量。它通过查看字段的类型是否为 dataclasses.InitVar 类型来实现。如果一个字段是一个 InitVar ,它被认为是一个称为仅初始化字段的伪字段。因为它不是一个真正的字段,所以它不会被模块级的 fields() 函数返回。仅初始化字段作为参数添加到生成的 __init__() 方法中,并传递给可选的 __post_init__() 方法。数据类不会使用它们。

例如,假设一个字段将从数据库初始化,如果在创建类时未提供其值:

@dataclass
class C:
    i: int
    j: int = None
    database: InitVar[DatabaseType] = None
    def __post_init__(self, database):
        if self.j is None and database is not None:
            self.j = database.lookup('j')
c = C(10, database=my_database)

在这种情况下, fields() 将返回 ijField 对象,但不包括 database

冻结的实例

无法创建真正不可变的 Python 对象。但是,通过将 frozen=True 传递给 dataclass() 装饰器,你可以模拟不变性。在这种情况下,数据类将向类添加 __setattr__()__delattr__() 方法。 些方法在调用时会引发 FrozenInstanceError

使用 frozen=True 时会有很小的性能损失: __ init__() 不能使用简单的赋值来初始化字段,并必须使用 object.__setattr__()

继承

当数组由 dataclass() 装饰器创建时,它会查看反向 MRO 中的所有类的基类(即从 object 开始 ),并且对于它找到的每个数据类, 将该基类中的字段添加到字段的有序映射中。添加完所有基类字段后,它会将自己的字段添加到有序映射中。所有生成的方法都将使用这种组合的,计算的有序字段映射。由于字段是按插入顺序排列的,因此派生类会重载基类。一个例子:

@dataclass
class Base:
    x: Any = 15.0
    y: int = 0
@dataclass
class C(Base):
    z: int = 10
    x: int = 15

最后的字段列表依次是 xyzx 的最终类型是 int ,如类 C 中所指定的那样。

C 生成的 __init__() 方法看起来像:

def __init__(self, x: int = 15, y: int = 0, z: int = 10):

__init__() 中仅限关键字字段的重新排序

在计算出 __init__() 所需要的形参之后,任何仅限关键字形参会被移至所有常规(非仅限关键字)形参的后面。 这是This is a requirement of how keyword-only parameters are implemented in Python 中实现仅限关键字形参所要求的:它们必须位于非仅限关键字形参之后。

在这个例子中,Base.y, Base.w, and D.t 是仅限关键字字段,而 Base.xD.z 是常规字段:

@dataclass
class Base:
    x: Any = 15.0
    _: KW_ONLY
    y: int = 0
    w: int = 1
@dataclass
class D(Base):
    z: int = 10
    t: int = field(kw_only=True, default=0)

D 生成的 __init__() 方法看起来像是这样:

def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: int = 0):

请注意形参原来在字段列表中出现的位置已被重新排序:前面是来自常规字段的形参而后面是来自仅限关键字字段的形参。

仅限关键字形参的相对顺序会在重新排序的 __init__() 形参列表中保持原样。

默认工厂函数

如果一个 field() 指定了一个 default_factory ,当需要该字段的默认值时,将使用零参数调用它。例如,要创建列表的新实例,请使用:

mylist: list = field(default_factory=list)

如果一个字段被排除在 __init__() 之外(使用 init=False )并且字段也指定 default_factory ,则默认的工厂函数将始终从生成的 __init__() 函数调用。发生这种情况是因为没有其他方法可以为字段提供初始值。

可变的默认值

Python 在类属性中存储默认成员变量值。思考这个例子,不使用数据类:

class C:
    x = []
    def add(self, element):
        self.x.append(element)
o1 = C()
o2 = C()
o1.add(1)
o2.add(2)
assert o1.x == [1, 2]
assert o1.x is o2.x

请注意,类 C 的两个实例共享相同的类变量 x ,如预期的那样。

使用数据类, 如果 此代码有效:

@dataclass
class D:
    x: List = []
    def add(self, element):
        self.x += element

它生成的代码类似于:

class D:
    x = []
    def __init__(self, x=x):
        self.x = x
    def add(self, element):
        self.x += element
assert D().x is D().x

这与使用 C 类的原始示例具有相同的问题。 也就是说,当在创建类实例的时候 D 类的两个实例没有为 x 指定值则将共享同一个 x 的副本。 因为数据类只是使用普通的 Python 类创建方式所以它们也会共享此行为。 数据类没有任何通用方式来检测这种情况。 相反地,dataclass() 装饰器在检测到类型为 list, dictset 的默认形参时将会引发 TypeError。 这是一个部分解决方案,但它确实能防止许多常见错误。

使用默认工厂函数是一种创建可变类型新实例的方法,并将其作为字段的默认值:

@dataclass
class D:
    x: list = field(default_factory=list)
assert D().x is not D().x

contextlib —- 为 with语句上下文提供的工具

源代码 Lib/contextlib.py


此模块为涉及 with 语句的常见任务提供了实用的工具。

工具

提供的函数和类:

class contextlib.AbstractContextManager

一个为实现了 object.__aenter__()object.__aexit__() 的类提供的 abstract base class。 为 object.__aenter__() 提供的一个默认实现是返回 selfobject.__aexit__() 是一个默认返回 None 的抽象方法。

3.6 新版功能.

class contextlib.AbstractAsyncContextManager

一个为实现了 object.__aenter__()object.__aexit__() 的类提供的 abstract base class。 为 object.__aenter__() 提供的一个默认实现是返回 selfobject.__aexit__() 是一个默认返回 None 的抽象方法。

3.7 新版功能.

@``contextlib.contextmanager

这个函数是一个 decorator ,它可以定义一个支持 with 语句上下文管理器的工厂函数, 而不需要创建一个类或区 __enter__()__exit__() 方法。

尽管许多对象原生支持使用 with 语句,但有些需要被管理的资源并不是上下文管理器,并且没有实现 close() 方法而不能使用 contextlib.closing

下面是一个抽象的示例,展示如何确保正确的资源管理:

from contextlib import contextmanager
@contextmanager
def managed_resource(*args, **kwds):
    # Code to acquire resource, e.g.:
    resource = acquire_resource(*args, **kwds)
    try:
        yield resource
    finally:
        # Code to release resource, e.g.:
        release_resource(resource)
>>> with managed_resource(timeout=3600) as resource:
...     # Resource is released at the end of this block,
...     # even if code in the block raises an exception

被装饰的函数在被调用时,必须返回一个 generator 迭代器。 这个迭代器必须只 yield 一个值出来,这个值会被用在 with 语句中,绑定到 as 后面的变量,如果给定了的话。

当生成器发生 yield 时,嵌套在 with 语句中的语句体会被执行。 语句体执行完毕离开之后,该生成器将被恢复执行。 如果在该语句体中发生了未处理的异常,则该异常会在生成器发生 yield 时重新被引发。 因此,你可以使用 tryexceptfinally 语句来捕获该异常(如果有的话),或确保进行了一些清理。 如果仅出于记录日志或执行某些操作(而非完全抑制异常)的目的捕获了异常,生成器必须重新引发该异常。 否则生成器的上下文管理器将向 with 语句指示该异常已经被处理,程序将立即在 with 语句之后恢复并继续执行。

contextmanager() 使用 ContextDecorator 因此它创建的上下文管理器不仅可以用在 with 语句中,还可以用作一个装饰器。当它用作一个装饰器时,每一次函数调用时都会隐式创建一个新的生成器实例(这使得 contextmanager() 创建的上下文管理器满足了支持多次调用以用作装饰器的需求,而非“一次性”的上下文管理器)。

在 3.2 版更改: ContextDecorator 的使用。

@``contextlib.asynccontextmanager

contextmanager() 类似,但创建的是 asynchronous context manager 。

这个函数是一个 decorator ,它可以定义一个支持 async with 语句的异步上下文管理器的工厂函数, 而不需要创建一个类或区分 __aenter__()__aexit__() 方法。它必须被作用在一个 asynchronous generator 函数上

一个简单的示例:

from contextlib import asynccontextmanager
@asynccontextmanager
async def get_connection():
    conn = await acquire_db_connection()
    try:
        yield conn
    finally:
        await release_db_connection(conn)
async def get_all_users():
    async with get_connection() as conn:
        return conn.query('SELECT ...')

3.7 新版功能.

Context managers defined with asynccontextmanager() can be used either as decorators or with async with statements:

import time
async def timeit():
    now = time.monotonic()
    try:
        yield
    finally:
        print(f'it took {time.monotonic() - now}s to run')
 @timeit()
 async def main():
     # ... async code ...

When used as a decorator, a new generator instance is implicitly created on each function call. This allows the otherwise “one-shot” context managers created by asynccontextmanager() to meet the requirement that context managers support multiple invocations in order to be used as decorators.

在 3.10 版更改: Async context managers created with asynccontextmanager() can be used as decorators.

contextlib.closing(thing)

返回一个在语句块执行完成时关闭 things 的上下文管理器。这基本上等价于:

from contextlib import contextmanager
@contextmanager
def closing(thing):
    try:
        yield thing
    finally:
        thing.close()

并允许你编写这样的代码:

from contextlib import closing
from urllib.request import urlopen
with closing(urlopen('https://www.python.org')) as page:
    for line in page:
        print(line)

而无需显式地关闭 page 。 即使发生错误,在退出 with 语句块时, page.close() 也同样会被调用。

class contextlib.aclosing(thing)

Return an async context manager that calls the aclose() method of thing upon completion of the block. This is basically equivalent to:

from contextlib import asynccontextmanager
@asynccontextmanager
async def aclosing(thing):
    try:
        yield thing
    finally:
        await thing.aclose()

Significantly, aclosing() supports deterministic cleanup of async generators when they happen to exit early by break or an exception. For example:

from contextlib import aclosing
async with aclosing(my_generator()) as values:
    async for value in values:
        if value == 42:
            break

This pattern ensures that the generator’s async exit code is executed in the same context as its iterations (so that exceptions and context variables work as expected, and the exit code isn’t run after the lifetime of some task it depends on).

3.10 新版功能.

contextlib.nullcontext(enter_result=None)

返回一个从 __enter__ 返回 enter_result 的上下文管理器,除此之外不执行任何操作。它旨在用于可选上下文管理器的一种替代,例如:

def myfunction(arg, ignore_exceptions=False):
    if ignore_exceptions:
        # Use suppress to ignore all exceptions.
        cm = contextlib.suppress(Exception)
    else:
        # Do not ignore any exceptions, cm has no effect.
        cm = contextlib.nullcontext()
    with cm:
        # Do something

一个使用 enter_result 的例子:

def process_file(file_or_path):
    if isinstance(file_or_path, str):
        # If string, open file
        cm = open(file_or_path)
    else:
        # Caller is responsible for closing file
        cm = nullcontext(file_or_path)
    with cm as file:
        # Perform processing on the file

It can also be used as a stand-in for asynchronous context managers:

async def send_http(session=None):
   if not session:
       # If no http session, create it with aiohttp
       cm = aiohttp.ClientSession()
   else:
       # Caller is responsible for closing the session
       cm = nullcontext(session)
   async with cm as session:
       # Send http requests with session

3.7 新版功能.

在 3.10 版更改: asynchronous context manager support was added.

contextlib.suppress(\exceptions*)

Return a context manager that suppresses any of the specified exceptions if they occur in the body of a with statement and then resumes execution with the first statement following the end of the with statement.

与完全抑制异常的任何其他机制一样,该上下文管理器应当只用来抑制非常具体的错误,并确保该场景下静默地继续执行程序是通用的正确做法。

例如:

from contextlib import suppress
with suppress(FileNotFoundError):
    os.remove('somefile.tmp')
with suppress(FileNotFoundError):
    os.remove('someotherfile.tmp')

这段代码等价于:

try:
    os.remove('somefile.tmp')
except FileNotFoundError:
    pass
try:
    os.remove('someotherfile.tmp')
except FileNotFoundError:
    pass

该上下文管理器是 reentrant 。

3.4 新版功能.

contextlib.redirect_stdout(new_target)

用于将 sys.stdout 临时重定向到一个文件或类文件对象的上下文管理器。

该工具给已有的将输出硬编码写到 stdout 的函数或类提供了额外的灵活性。

For example, the output of help() normally is sent to sys.stdout. You can capture that output in a string by redirecting the output to an io.StringIO object. The replacement stream is returned from the __enter__ method and so is available as the target of the with statement:

with redirect_stdout(io.StringIO()) as f:
    help(pow)
s = f.getvalue()

如果要把 help() 的输出写到磁盘上的一个文件,重定向该输出到一个常规文件:

with open('help.txt', 'w') as f:
    with redirect_stdout(f):
        help(pow)

如果要把 help() 的输出写到 sys.stderr

with redirect_stdout(sys.stderr):
    help(pow)

需要注意的点在于, sys.stdout 的全局副作用意味着此上下文管理器不适合在库代码和大多数多线程应用程序中使用。它对子进程的输出没有影响。不过对于许多工具脚本而言,它仍然是一个有用的方法。

该上下文管理器是 reentrant 。

3.4 新版功能.

contextlib.redirect_stderr(new_target)

redirect_stdout() 类似,不过是将 sys.stderr 重定向到一个文件或类文件对象。

该上下文管理器是 reentrant 。

3.5 新版功能.

class contextlib.ContextDecorator

一个使上下文管理器能用作装饰器的基类。

与往常一样,继承自 ContextDecorator 的上下文管理器必须实现 __enter____exit__ 。即使用作装饰器, __exit__ 依旧会保持可能的异常处理。

ContextDecorator 被用在 contextmanager() 中,因此你自然获得了这项功能。

ContextDecorator 的示例:

from contextlib import ContextDecorator
class mycontext(ContextDecorator):
    def __enter__(self):
        print('Starting')
        return self
    def __exit__(self, *exc):
        print('Finishing')
        return False
>>> @mycontext()
... def function():
...     print('The bit in the middle')
...
>>> function()
Starting
The bit in the middle
Finishing
>>> with mycontext():
...     print('The bit in the middle')
...
Starting
The bit in the middle
Finishing

这个改动只是针对如下形式的一个语法糖:

def f():
    with cm():
        # Do stuff

ContextDecorator 使得你可以这样改写:

@cm()
def f():
    # Do stuff

这能清楚地表明, cm 作用于整个函数,而不仅仅是函数的一部分(同时也能保持不错的缩进层级)。

现有的上下文管理器即使已经有基类,也可以使用 ContextDecorator 作为混合类进行扩展:

from contextlib import ContextDecorator
class mycontext(ContextBaseClass, ContextDecorator):
    def __enter__(self):
        return self
    def __exit__(self, *exc):
        return False

注解

由于被装饰的函数必须能够被多次调用,因此对应的上下文管理器必须支持在多个 with 语句中使用。如果不是这样,则应当使用原来的具有显式 with 语句的形式使用该上下文管理器。

3.2 新版功能.

class contextlib.AsyncContextDecorator

Similar to ContextDecorator but only for asynchronous functions.

Example of AsyncContextDecorator:

from asyncio import run
from contextlib import AsyncContextDecorator
class mycontext(AsyncContextDecorator):
    async def __aenter__(self):
        print('Starting')
        return self
    async def __aexit__(self, *exc):
        print('Finishing')
        return False
>>> @mycontext()
... async def function():
...     print('The bit in the middle')
...
>>> run(function())
Starting
The bit in the middle
Finishing
>>> async def function():
...    async with mycontext():
...         print('The bit in the middle')
...
>>> run(function())
Starting
The bit in the middle
Finishing

3.10 新版功能.

class contextlib.ExitStack

该上下文管理器的设计目标是使得在编码中组合其他上下文管理器和清理函数更加容易,尤其是那些可选的或由输入数据驱动的上下文管理器。

例如,通过一个如下的 with 语句可以很容易处理一组文件:

with ExitStack() as stack:
    files = [stack.enter_context(open(fname)) for fname in filenames]
    # All opened files will automatically be closed at the end of
    # the with statement, even if attempts to open files later
    # in the list raise an exception

每个实例维护一个注册了一组回调的栈,这些回调在实例关闭时以相反的顺序被调用(显式或隐式地在 with 语句的末尾)。请注意,当一个栈实例被垃圾回收时,这些回调将 不会 被隐式调用。

通过使用这个基于栈的模型,那些通过 __init__ 方法获取资源的上下文管理器(如文件对象)能够被正确处理。

由于注册的回调函数是按照与注册相反的顺序调用的,因此最终的行为就像多个嵌套的 with 语句用在这些注册的回调函数上。这个行为甚至扩展到了异常处理:如果内部的回调函数抑制或替换了异常,则外部回调收到的参数是基于该更新后的状态得到的。

这是一个相对底层的 API,它负责正确处理栈里回调退出时依次展开的细节。它为相对高层的上下文管理器提供了一个合适的基础,使得它能根据应用程序的需求使用特定方式操作栈。

3.3 新版功能.

  • enter_context(cm)

    Enters a new context manager and adds its __exit__() method to the callback stack. The return value is the result of the context manager’s own __enter__() method.

    These context managers may suppress exceptions just as they normally would if used directly as part of a with statement.

  • push(exit)

    Adds a context manager’s __exit__() method to the callback stack.

    As __enter__ is not invoked, this method can be used to cover part of an __enter__() implementation with a context manager’s own __exit__() method.

    If passed an object that is not a context manager, this method assumes it is a callback with the same signature as a context manager’s __exit__() method and adds it directly to the callback stack.

    By returning true values, these callbacks can suppress exceptions the same way context manager __exit__() methods can.

    The passed in object is returned from the function, allowing this method to be used as a function decorator.

  • callback(callback, /, \args, *kwds)

    Accepts an arbitrary callback function and arguments and adds it to the callback stack.

    Unlike the other methods, callbacks added this way cannot suppress exceptions (as they are never passed the exception details).

    The passed in callback is returned from the function, allowing this method to be used as a function decorator.

  • pop_all()

    Transfers the callback stack to a fresh ExitStack instance and returns it. No callbacks are invoked by this operation - instead, they will now be invoked when the new stack is closed (either explicitly or implicitly at the end of a with statement).

    For example, a group of files can be opened as an “all or nothing” operation as follows:

    with ExitStack() as stack:
        files = [stack.enter_context(open(fname)) for fname in filenames]
        # Hold onto the close method, but don't call it yet.
        close_files = stack.pop_all().close
        # If opening any file fails, all previously opened files will be
        # closed automatically. If all files are opened successfully,
        # they will remain open even after the with statement ends.
        # close_files() can then be invoked explicitly to close them all.
  • close()

    Immediately unwinds the callback stack, invoking callbacks in the reverse order of registration. For any context managers and exit callbacks registered, the arguments passed in will indicate that no exception occurred.

class contextlib.AsyncExitStack

An asynchronous context manager, similar to ExitStack, that supports combining both synchronous and asynchronous context managers, as well as having coroutines for cleanup logic.

The close() method is not implemented, aclose() must be used instead.

  • coroutine enter_async_context(cm)

    Similar to enter_context() but expects an asynchronous context manager.

  • push_async_exit(exit)

    Similar to push() but expects either an asynchronous context manager or a coroutine function.

  • push_async_callback(callback, /, \args, *kwds)

    Similar to callback() but expects a coroutine function.

  • coroutine aclose()

    Similar to close() but properly handles awaitables.

Continuing the example for asynccontextmanager():

async with AsyncExitStack() as stack:
    connections = [await stack.enter_async_context(get_connection())
        for i in range(5)]
    # All opened connections will automatically be released at the end of
    # the async with statement, even if attempts to open a connection
    # later in the list raise an exception.

3.7 新版功能.

例子和配方

This section describes some examples and recipes for making effective use of the tools provided by contextlib.

Supporting a variable number of context managers

The primary use case for ExitStack is the one given in the class documentation: supporting a variable number of context managers and other cleanup operations in a single with statement. The variability may come from the number of context managers needed being driven by user input (such as opening a user specified collection of files), or from some of the context managers being optional:

with ExitStack() as stack:
    for resource in resources:
        stack.enter_context(resource)
    if need_special_resource():
        special = acquire_special_resource()
        stack.callback(release_special_resource, special)
    # Perform operations that use the acquired resources

As shown, ExitStack also makes it quite easy to use with statements to manage arbitrary resources that don’t natively support the context management protocol.

Catching exceptions from __enter__ methods

It is occasionally desirable to catch exceptions from an __enter__ method implementation, without inadvertently catching exceptions from the with statement body or the context manager’s __exit__ method. By using ExitStack the steps in the context management protocol can be separated slightly in order to allow this:

stack = ExitStack()
try:
    x = stack.enter_context(cm)
except Exception:
    # handle __enter__ exception
else:
    with stack:
        # Handle normal case

Actually needing to do this is likely to indicate that the underlying API should be providing a direct resource management interface for use with try/except/finally statements, but not all APIs are well designed in that regard. When a context manager is the only resource management API provided, then ExitStack can make it easier to handle various situations that can’t be handled directly in a with statement.

Cleaning up in an __enter__ implementation

As noted in the documentation of ExitStack.push(), this method can be useful in cleaning up an already allocated resource if later steps in the __enter__() implementation fail.

Here’s an example of doing this for a context manager that accepts resource acquisition and release functions, along with an optional validation function, and maps them to the context management protocol:

from contextlib import contextmanager, AbstractContextManager, ExitStack
class ResourceManager(AbstractContextManager):
    def __init__(self, acquire_resource, release_resource, check_resource_ok=None):
        self.acquire_resource = acquire_resource
        self.release_resource = release_resource
        if check_resource_ok is None:
            def check_resource_ok(resource):
                return True
        self.check_resource_ok = check_resource_ok
    @contextmanager
    def _cleanup_on_error(self):
        with ExitStack() as stack:
            stack.push(self)
            yield
            # The validation check passed and didn't raise an exception
            # Accordingly, we want to keep the resource, and pass it
            # back to our caller
            stack.pop_all()
    def __enter__(self):
        resource = self.acquire_resource()
        with self._cleanup_on_error():
            if not self.check_resource_ok(resource):
                msg = "Failed validation for {!r}"
                raise RuntimeError(msg.format(resource))
        return resource
    def __exit__(self, *exc_details):
        # We don't need to duplicate any of our resource release logic
        self.release_resource()

Replacing any use of try-finally and flag variables

A pattern you will sometimes see is a try-finally statement with a flag variable to indicate whether or not the body of the finally clause should be executed. In its simplest form (that can’t already be handled just by using an except clause instead), it looks something like this:

cleanup_needed = True
try:
    result = perform_operation()
    if result:
        cleanup_needed = False
finally:
    if cleanup_needed:
        cleanup_resources()

As with any try statement based code, this can cause problems for development and review, because the setup code and the cleanup code can end up being separated by arbitrarily long sections of code.

ExitStack makes it possible to instead register a callback for execution at the end of a with statement, and then later decide to skip executing that callback:

from contextlib import ExitStack
with ExitStack() as stack:
    stack.callback(cleanup_resources)
    result = perform_operation()
    if result:
        stack.pop_all()

This allows the intended cleanup up behaviour to be made explicit up front, rather than requiring a separate flag variable.

If a particular application uses this pattern a lot, it can be simplified even further by means of a small helper class:

from contextlib import ExitStack
class Callback(ExitStack):
    def __init__(self, callback, /, *args, **kwds):
        super().__init__()
        self.callback(callback, *args, **kwds)
    def cancel(self):
        self.pop_all()
with Callback(cleanup_resources) as cb:
    result = perform_operation()
    if result:
        cb.cancel()

If the resource cleanup isn’t already neatly bundled into a standalone function, then it is still possible to use the decorator form of ExitStack.callback() to declare the resource cleanup in advance:

from contextlib import ExitStack
with ExitStack() as stack:
    @stack.callback
    def cleanup_resources():
        ...
    result = perform_operation()
    if result:
        stack.pop_all()

Due to the way the decorator protocol works, a callback function declared this way cannot take any parameters. Instead, any resources to be released must be accessed as closure variables.

Using a context manager as a function decorator

ContextDecorator makes it possible to use a context manager in both an ordinary with statement and also as a function decorator.

For example, it is sometimes useful to wrap functions or groups of statements with a logger that can track the time of entry and time of exit. Rather than writing both a function decorator and a context manager for the task, inheriting from ContextDecorator provides both capabilities in a single definition:

from contextlib import ContextDecorator
import logging
logging.basicConfig(level=logging.INFO)
class track_entry_and_exit(ContextDecorator):
    def __init__(self, name):
        self.name = name
    def __enter__(self):
        logging.info('Entering: %s', self.name)
    def __exit__(self, exc_type, exc, exc_tb):
        logging.info('Exiting: %s', self.name)

Instances of this class can be used as both a context manager:

with track_entry_and_exit('widget loader'):
    print('Some time consuming activity goes here')
    load_widget()

And also as a function decorator:

@track_entry_and_exit('widget loader')
def activity():
    print('Some time consuming activity goes here')
    load_widget()

Note that there is one additional limitation when using context managers as function decorators: there’s no way to access the return value of __enter__(). If that value is needed, then it is still necessary to use an explicit with statement.

参见

PEP 343 - “with” 语句

Python with 语句的规范描述、背景和示例。

Single use, reusable and reentrant context managers

Most context managers are written in a way that means they can only be used effectively in a with statement once. These single use context managers must be created afresh each time they’re used - attempting to use them a second time will trigger an exception or otherwise not work correctly.

This common limitation means that it is generally advisable to create context managers directly in the header of the with statement where they are used (as shown in all of the usage examples above).

Files are an example of effectively single use context managers, since the first with statement will close the file, preventing any further IO operations using that file object.

Context managers created using contextmanager() are also single use context managers, and will complain about the underlying generator failing to yield if an attempt is made to use them a second time:

>>> from contextlib import contextmanager
>>> @contextmanager
... def singleuse():
...     print("Before")
...     yield
...     print("After")
...
>>> cm = singleuse()
>>> with cm:
...     pass
...
Before
After
>>> with cm:
...     pass
...
Traceback (most recent call last):
    ...
RuntimeError: generator didn't yield

Reentrant context managers

More sophisticated context managers may be “reentrant”. These context managers can not only be used in multiple with statements, but may also be used inside a with statement that is already using the same context manager.

threading.RLock is an example of a reentrant context manager, as are suppress() and redirect_stdout(). Here’s a very simple example of reentrant use:

>>> from contextlib import redirect_stdout
>>> from io import StringIO
>>> stream = StringIO()
>>> write_to_stream = redirect_stdout(stream)
>>> with write_to_stream:
...     print("This is written to the stream rather than stdout")
...     with write_to_stream:
...         print("This is also written to the stream")
...
>>> print("This is written directly to stdout")
This is written directly to stdout
>>> print(stream.getvalue())
This is written to the stream rather than stdout
This is also written to the stream

Real world examples of reentrancy are more likely to involve multiple functions calling each other and hence be far more complicated than this example.

Note also that being reentrant is not the same thing as being thread safe. redirect_stdout(), for example, is definitely not thread safe, as it makes a global modification to the system state by binding sys.stdout to a different stream.

Reusable context managers

Distinct from both single use and reentrant context managers are “reusable” context managers (or, to be completely explicit, “reusable, but not reentrant” context managers, since reentrant context managers are also reusable). These context managers support being used multiple times, but will fail (or otherwise not work correctly) if the specific context manager instance has already been used in a containing with statement.

threading.Lock is an example of a reusable, but not reentrant, context manager (for a reentrant lock, it is necessary to use threading.RLock instead).

Another example of a reusable, but not reentrant, context manager is ExitStack, as it invokes all currently registered callbacks when leaving any with statement, regardless of where those callbacks were added:

>>> from contextlib import ExitStack
>>> stack = ExitStack()
>>> with stack:
...     stack.callback(print, "Callback: from first context")
...     print("Leaving first context")
...
Leaving first context
Callback: from first context
>>> with stack:
...     stack.callback(print, "Callback: from second context")
...     print("Leaving second context")
...
Leaving second context
Callback: from second context
>>> with stack:
...     stack.callback(print, "Callback: from outer context")
...     with stack:
...         stack.callback(print, "Callback: from inner context")
...         print("Leaving inner context")
...     print("Leaving outer context")
...
Leaving inner context
Callback: from inner context
Callback: from outer context
Leaving outer context

As the output from the example shows, reusing a single stack object across multiple with statements works correctly, but attempting to nest them will cause the stack to be cleared at the end of the innermost with statement, which is unlikely to be desirable behaviour.

Using separate ExitStack instances instead of reusing a single instance avoids that problem:

>>> from contextlib import ExitStack
>>> with ExitStack() as outer_stack:
...     outer_stack.callback(print, "Callback: from outer context")
...     with ExitStack() as inner_stack:
...         inner_stack.callback(print, "Callback: from inner context")
...         print("Leaving inner context")
...     print("Leaving outer context")
...
Leaving inner context
Callback: from inner context
Leaving outer context
Callback: from outer context

abc —- 抽象基类

源代码: Lib/abc.py


该模块提供了在 Python 中定义 抽象基类 (ABC) 的组件,在 PEP 3119 中已有概述。查看 PEP 文档了解为什么需要在 Python 中增加这个模块。(也可查看 PEP 3141 以及 numbers 模块了解基于 ABC 的数字类型继承关系。)

collections 模块中有一些派生自 ABC 的具体类;当然这些类还可以进一步被派生。此外,collections.abc 子模块中有一些 ABC 可被用于测试一个类或实例是否提供特定的接口,例如它是否可哈希或它是否为映射等。

该模块提供了一个元类 ABCMeta,可以用来定义抽象类,另外还提供一个工具类 ABC,可以用它以继承的方式定义抽象基类。

class abc.ABC

一个使用 ABCMeta 作为元类的工具类。抽象基类可以通过从 ABC 派生来简单地创建,这就避免了在某些情况下会令人混淆的元类用法,例如:

from abc import ABC
class MyABC(ABC):
    pass

注意 ABC 的类型仍然是 ABCMeta,因此继承 ABC 仍然需要关注元类使用中的注意事项,比如可能会导致元类冲突的多重继承。当然你也可以直接使用 ABCMeta 作为元类来定义抽象基类,例如:

from abc import ABCMeta
class MyABC(metaclass=ABCMeta):
    pass

3.4 新版功能.

class abc.ABCMeta

用于定义抽象基类(ABC)的元类。

使用该元类以创建抽象基类。抽象基类可以像 mix-in 类一样直接被子类继承。你也可以将不相关的具体类(包括内建类)和抽象基类注册为“抽象子类” —— 这些类以及它们的子类会被内建函数 issubclass() 识别为对应的抽象基类的子类,但是该抽象基类不会出现在其 MRO(Method Resolution Order,方法解析顺序)中,抽象基类中实现的方法也不可调用(即使通过 super() 调用也不行)。

使用 ABCMeta 作为元类创建的类含有如下方法:

  • register(subclass)

    将“子类”注册为该抽象基类的“抽象子类”,例如:

    from abc import ABC
    class MyABC(ABC):
        pass
    MyABC.register(tuple)
    assert issubclass(tuple, MyABC)
    assert isinstance((), MyABC)

    在 3.3 版更改: 返回注册的子类,使其能够作为类装饰器。

    在 3.4 版更改: 你可以使用 get_cache_token() 函数来检测对 register() 的调用。

你也可以在虚基类中重载这个方法。

  • __subclasshook__(subclass)

    (必须定义为类方法。)

    检查 subclass 是否是该抽象基类的子类。也就是说对于那些你希望定义为该抽象基类的子类的类,你不用对每个类都调用 register() 方法了,而是可以直接自定义 issubclass 的行为。(这个类方法是在抽象基类的 __subclasscheck__() 方法中调用的。)

    该方法必须返回 True, False 或是 NotImplemented。如果返回 Truesubclass 就会被认为是这个抽象基类的子类。如果返回 False,无论正常情况是否应该认为是其子类,统一视为不是。如果返回 NotImplemented,子类检查会按照正常机制继续执行。

为了对这些概念做一演示,请看以下定义 ABC 的示例:

class Foo:
    def __getitem__(self, index):
        ...
    def __len__(self):
        ...
    def get_iterator(self):
        return iter(self)
class MyIterable(ABC):
    @abstractmethod
    def __iter__(self):
        while False:
            yield None
    def get_iterator(self):
        return self.__iter__()
    @classmethod
    def __subclasshook__(cls, C):
        if cls is MyIterable:
            if any("__iter__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented
MyIterable.register(Foo)

ABC MyIterable 定义了标准的迭代方法 __iter__() 作为一个抽象方法。这里给出的实现仍可在子类中被调用。get_iterator() 方法也是 MyIterable 抽象基类的一部分,但它并非必须被非抽象派生类所重载。

这里定义的 __subclasshook__() 类方法指明了任何在其 __dict__ (或在其通过 __mro__ 列表访问的基类) 中具有 __iter__() 方法的类也都会被视为 MyIterable

最后,末尾行使得 Foo 成为 MyIterable 的一个虚子类,即使它没有定义 __iter__() 方法(它使用了以 __len__()__getitem__() 术语定义的旧式可迭代对象协议)。 请注意这将不会使 get_iterator 成为 Foo 的一个可用方法,它是被另外提供的。

此外,abc 模块还提供了这些装饰器:

@``abc.abstractmethod

用于声明抽象方法的装饰器。

使用此装饰器要求类的元类是 ABCMeta 或是从该类派生。一个具有派生自 ABCMeta 的元类的类不可以被实例化,除非它全部的抽象方法和特征属性均已被重载。抽象方法可通过任何普通的“super”调用机制来调用。 abstractmethod() 可被用于声明特性属性和描述器的抽象方法。

动态地添加抽象方法到一个类,或尝试在方法或类被创建后修改其抽象状态等操作仅在使用 update_abstractmethods() 函数时受到支持。 abstractmethod() 只会影响使用常规继承所派生的子类;通过 ABC 的 register() 方法注册的“虚子类”不会受到影响。

abstractmethod() 与其他方法描述符配合应用时,它应当被应用为最内层的装饰器,如以下用法示例所示:

class C(ABC):
    @abstractmethod
    def my_abstract_method(self, ...):
        ...
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, ...):
        ...
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(...):
        ...
    @property
    @abstractmethod
    def my_abstract_property(self):
        ...
    @my_abstract_property.setter
    @abstractmethod
    def my_abstract_property(self, val):
        ...
    @abstractmethod
    def _get_x(self):
        ...
    @abstractmethod
    def _set_x(self, val):
        ...
    x = property(_get_x, _set_x)

为了能正确地与抽象基类机制实现互操作,描述符必须使用 __isabstractmethod__ 将自身标识为抽象的。 通常,如果被用于组成描述符的任何方法都是抽象的则此属性应当为 True。 例如,Python 的内置 property 所做的就等价于:

class Descriptor:
    ...
    @property
    def __isabstractmethod__(self):
        return any(getattr(f, '__isabstractmethod__', False) for
                   f in (self._fget, self._fset, self._fdel))

注解

不同于 Java 抽象方法,这些抽象方法可能具有一个实现。 这个实现可在重载它的类上通过 super() 机制来调用。 这在使用协作多重继承的框架中可以被用作超调用的一个端点。

abc 模块还支持下列旧式装饰器:

@``abc.abstractclassmethod

3.2 新版功能.

3.3 版后已移除: 现在可以让 classmethod 配合 abstractmethod() 使用,使得此装饰器变得冗余。

内置 classmethod() 的子类,指明一个抽象类方法。 在其他方面它都类似于 abstractmethod()

这个特例已被弃用,因为现在当 classmethod() 装饰器应用于抽象方法时它会被正确地标识为抽象的:

class C(ABC):
    @classmethod
    @abstractmethod
    def my_abstract_classmethod(cls, ...):
        ...

3.2 新版功能.

3.3 版后已移除: 现在可以让 staticmethod 配合 abstractmethod() 使用,使得此装饰器变得冗余。

内置 staticmethod() 的子类,指明一个抽象静态方法。 在其他方面它都类似于 abstractmethod()

这个特例已被弃用,因为现在当 staticmethod() 装饰器应用于抽象方法时它会被正确地标识为抽象的:

class C(ABC):
    @staticmethod
    @abstractmethod
    def my_abstract_staticmethod(...):
        ...

3.3 版后已移除: 现在可以让 property, property.getter(), property.setter()property.deleter() 配合 abstractmethod() 使用,使得此装饰器变得冗余。

内置 property() 的子类,指明一个抽象特性属性。

这个特例已被弃用,因为现在当 property() 装饰器应用于抽象方法时它会被正确地标识为抽象的:

class C(ABC):
    @property
    @abstractmethod
    def my_abstract_property(self):
        ...

上面的例子定义了一个只读特征属性;你也可以通过适当地将一个或多个下层方法标记为抽象的来定义可读写的抽象特征属性:

class C(ABC):
    @property
    def x(self):
        ...
    @x.setter
    @abstractmethod
    def x(self, val):
        ...

如果只有某些组件是抽象的,则只需更新那些组件即可在子类中创建具体的特征属性:

class D(C):
    @C.x.setter
    def x(self, val):
        ...

abc 模块还提供了这些函数:

abc.get_cache_token()

返回当前抽象基类的缓存令牌

此令牌是一个不透明对象(支持相等性测试),用于为虚子类标识抽象基类缓存的当前版本。 此令牌会在任何 ABC 上每次调用 ABCMeta.register() 时发生更改。

3.4 新版功能.

abc.update_abstractmethods(cls)

重新计算一个抽象类的抽象状态的函数。 如果一个类的抽象方法在类被创建后被实现或被修改则应当调用此函数。 通常,此函数应当在一个类装饰器内部被调用。

返回 cls,使其能够用作类装饰器。

如果 cls 不是 ABCMeta 的子类,则不做任何操作。

注解

此函数会假定 cls 的上级类已经被更新。 它不会更新任何子类。

3.10 新版功能.

atexit —- 退出处理器

atexit 模块定义了清理函数的注册和反注册函数. 被注册的函数会在解释器正常终止时执行. atexit 会按照注册顺序的逆序执行; 如果你注册了 A, BC, 那么在解释器终止时会依序执行 C, B, A.

注意: 通过该模块注册的函数, 在程序被未被 Python 捕获的信号杀死时并不会执行, 在检测到 Python 内部致命错误以及调用了 os._exit() 时也不会执行.

在 3.7 版更改: 当配合 C-API 子解释器使用时,已注册函数是它们所注册解释器中的局部对象。

atexit.register(func, \args, *kwargs)

func 注册为终止时执行的函数. 任何传给 func 的可选的参数都应当作为参数传给 register(). 可以多次注册同样的函数及参数.

在正常的程序终止时 (举例来说, 当调用了 sys.exit() 或是主模块的执行完成时), 所有注册过的函数都会以后进先出的顺序执行. 这样做是假定更底层的模块通常会比高层模块更早引入, 因此需要更晚清理.

如果在 exit 处理句柄执行期间引发了异常,将会打印回溯信息 (除非引发的是 SystemExit) 并且异常信息会被保存。 在所有 exit 处理句柄都获得运行机会之后,所引发的最后一个异常会被重新引发。

这个函数返回 func 对象,可以把它当作装饰器使用。

atexit.unregister(func)

func 移出当解释器关闭时要运行的函数列表。 如果 func 之前未被注册则 unregister() 将静默地不做任何事。 如果 func 已被注册一次以上,则该函数每次在 atexit 调用栈中的出现都将被移除。 当取消注册时会在内部使用相等性比较 (==),因而函数引用不需要具有匹配的标识号。

atexit 示例

以下简单例子演示了一个模块在被导入时如何从文件初始化一个计数器,并在程序终结时自动保存计数器的更新值,此操作不依赖于应用在终结时对此模块进行显式调用。:

try:
    with open('counterfile') as infile:
        _count = int(infile.read())
except FileNotFoundError:
    _count = 0
def incrcounter(n):
    global _count
    _count = _count + n
def savecounter():
    with open('counterfile', 'w') as outfile:
        outfile.write('%d' % _count)
import atexit
atexit.register(savecounter)

位置和关键字参数也可传入 register() 以便传递给被调用的已注册函数:

def goodbye(name, adjective):
    print('Goodbye %s, it was %s to meet you.' % (name, adjective))
import atexit
atexit.register(goodbye, 'Donny', 'nice')
# or:
atexit.register(goodbye, adjective='nice', name='Donny')

作为 decorator: 使用:

import atexit
@atexit.register
def goodbye():
    print('You are now leaving the Python sector.')

只有在函数不需要任何参数调用时才能工作.

traceback —- 打印或检索堆栈回溯

源代码: Lib/traceback.py


该模块提供了一个标准接口来提取、格式化和打印 Python 程序的堆栈跟踪结果。它完全模仿Python 解释器在打印堆栈跟踪结果时的行为。当您想要在程序控制下打印堆栈跟踪结果时,例如在“封装”解释器时,这是非常有用的。

这个模块使用 traceback 对象 —— 这是存储在 sys.last_traceback 中的对象类型变量,并作为 sys.exc_info() 的第三项被返回。

这个模块定义了以下函数:

traceback.print_tb(tb, limit=None, file=None)

如果limit*是正整数,那么从 traceback 对象 “tb” 输出最高 *limit 个(从调用函数开始的)栈的堆栈回溯‎条目‎;如果 limit 是负数就输出 abs(limit) 个回溯条目;又如果 limit 被省略或者为 None,那么就会输出所有回溯条目。如果 file 被省略或为 None 那么就会输出至标准输出sys.stderr否则它应该是一个打开的文件或者文件类对象来接收输出

在 3.5 版更改: 添加了对负数值 limit 的支持

traceback.print_exception(exc, /, [value, tb, ]limit=None, file=None, chain=True)

打印回溯对象 tbfile 的异常信息和整个堆栈回溯。这和 print_tb() 比有以下方面不同:

  • 如果 tb 不为 None,它将打印头部 Traceback (most recent call last):
  • it prints the exception type and value after the stack trace
  • if type(value) is SyntaxError and value has the appropriate format, it prints the line where the syntax error occurred with a caret indicating the approximate position of the error.

Since Python 3.10, instead of passing value and tb, an exception object can be passed as the first argument. If value and tb are provided, the first argument is ignored in order to provide backwards compatibility.

The optional limit argument has the same meaning as for print_tb(). If chain is true (the default), then chained exceptions (the __cause__ or __context__ attributes of the exception) will be printed as well, like the interpreter itself does when printing an unhandled exception.

在 3.5 版更改: The etype argument is ignored and inferred from the type of value.

在 3.10 版更改: The etype parameter has been renamed to exc and is now positional-only.

traceback.print_exc(limit=None, file=None, chain=True)

This is a shorthand for print_exception(*sys.exc_info(), limit, file, chain).

traceback.print_last(limit=None, file=None, chain=True)

This is a shorthand for print_exception(sys.last_type, sys.last_value, sys.last_traceback, limit, file, chain). In general it will work only after an exception has reached an interactive prompt (see sys.last_type).

traceback.print_stack(f=None, limit=None, file=None)

Print up to limit stack trace entries (starting from the invocation point) if limit is positive. Otherwise, print the last abs(limit) entries. If limit is omitted or None, all entries are printed. The optional f argument can be used to specify an alternate stack frame to start. The optional file argument has the same meaning as for print_tb().

在 3.5 版更改: 添加了对负数值 limit 的支持

traceback.extract_tb(tb, limit=None)

Return a StackSummary object representing a list of “pre-processed” stack trace entries extracted from the traceback object tb. It is useful for alternate formatting of stack traces. The optional limit argument has the same meaning as for print_tb(). A “pre-processed” stack trace entry is a FrameSummary object containing attributes filename, lineno, name, and line representing the information that is usually printed for a stack trace. The line is a string with leading and trailing whitespace stripped; if the source is not available it is None.

traceback.extract_stack(f=None, limit=None)

Extract the raw traceback from the current stack frame. The return value has the same format as for extract_tb(). The optional f and limit arguments have the same meaning as for print_stack().

traceback.format_list(extracted_list)

Given a list of tuples or FrameSummary objects as returned by extract_tb() or extract_stack(), return a list of strings ready for printing. Each string in the resulting list corresponds to the item with the same index in the argument list. Each string ends in a newline; the strings may contain internal newlines as well, for those items whose source text line is not None.

traceback.format_exception_only(exc, /[, value])

Format the exception part of a traceback using an exception value such as given by sys.last_value. The return value is a list of strings, each ending in a newline. Normally, the list contains a single string; however, for SyntaxError exceptions, it contains several lines that (when printed) display detailed information about where the syntax error occurred. The message indicating which exception occurred is the always last string in the list.

Since Python 3.10, instead of passing value, an exception object can be passed as the first argument. If value is provided, the first argument is ignored in order to provide backwards compatibility.

在 3.10 版更改: The etype parameter has been renamed to exc and is now positional-only.

traceback.format_exception(exc, /, [value, tb, ]limit=None, chain=True)

Format a stack trace and the exception information. The arguments have the same meaning as the corresponding arguments to print_exception(). The return value is a list of strings, each ending in a newline and some containing internal newlines. When these lines are concatenated and printed, exactly the same text is printed as does print_exception().

在 3.5 版更改: The etype argument is ignored and inferred from the type of value.

在 3.10 版更改: This function’s behavior and signature were modified to match print_exception().

traceback.format_exc(limit=None, chain=True)

This is like print_exc(limit) but returns a string instead of printing to a file.

traceback.format_tb(tb, limit=None)

A shorthand for format_list(extract_tb(tb, limit)).

traceback.format_stack(f=None, limit=None)

A shorthand for format_list(extract_stack(f, limit)).

traceback.clear_frames(tb)

Clears the local variables of all the stack frames in a traceback tb by calling the clear() method of each frame object.

3.4 新版功能.

traceback.walk_stack(f)

Walk a stack following f.f_back from the given frame, yielding the frame and line number for each frame. If f is None, the current stack is used. This helper is used with StackSummary.extract().

3.5 新版功能.

traceback.walk_tb(tb)

Walk a traceback following tb_next yielding the frame and line number for each frame. This helper is used with StackSummary.extract().

3.5 新版功能.

The module also defines the following classes:

TracebackException Objects

3.5 新版功能.

TracebackException objects are created from actual exceptions to capture data for later printing in a lightweight fashion.

class traceback.TracebackException(exc_type, exc_value, exc_traceback, **, limit=None, lookup_lines=True, capture_locals=False, compact=False*)

Capture an exception for later rendering. limit, lookup_lines and capture_locals are as for the StackSummary class.

If compact is true, only data that is required by TracebackException‘s format method is saved in the class attributes. In particular, the __context__ field is calculated only if __cause__ is None and __suppress_context__ is false.

Note that when locals are captured, they are also shown in the traceback.

  • __cause__

    A TracebackException of the original __cause__.

  • __context__

    A TracebackException of the original __context__.

  • __suppress_context__

    The __suppress_context__ value from the original exception.

  • stack

    A StackSummary representing the traceback.

  • exc_type

    The class of the original traceback.

  • filename

    For syntax errors - the file name where the error occurred.

  • lineno

    For syntax errors - the line number where the error occurred.

  • text

    For syntax errors - the text where the error occurred.

  • offset

    For syntax errors - the offset into the text where the error occurred.

  • msg

    For syntax errors - the compiler error message.

  • classmethod from_exception(exc, **, limit=None, lookup_lines=True, capture_locals=False*)

    Capture an exception for later rendering. limit, lookup_lines and capture_locals are as for the StackSummary class.

    Note that when locals are captured, they are also shown in the traceback.

  • format(**, chain=True*)

    Format the exception.

    If chain is not True, __cause__ and __context__ will not be formatted.

    The return value is a generator of strings, each ending in a newline and some containing internal newlines. print_exception() is a wrapper around this method which just prints the lines to a file.

    The message indicating which exception occurred is always the last string in the output.

  • format_exception_only()

    Format the exception part of the traceback.

    The return value is a generator of strings, each ending in a newline.

    Normally, the generator emits a single string; however, for SyntaxError exceptions, it emits several lines that (when printed) display detailed information about where the syntax error occurred.

    The message indicating which exception occurred is always the last string in the output.

在 3.10 版更改: 增加了 compact 形参。

StackSummary Objects

3.5 新版功能.

StackSummary objects represent a call stack ready for formatting.

class traceback.StackSummary

  • classmethod extract(frame_gen, **, limit=None, lookup_lines=True, capture_locals=False*)

    Construct a StackSummary object from a frame generator (such as is returned by walk_stack() or walk_tb()).

    If limit is supplied, only this many frames are taken from frame_gen. If lookup_lines is False, the returned FrameSummary objects will not have read their lines in yet, making the cost of creating the StackSummary cheaper (which may be valuable if it may not actually get formatted). If capture_locals is True the local variables in each FrameSummary are captured as object representations.

  • classmethod from_list(a_list)

    Construct a StackSummary object from a supplied list of FrameSummary objects or old-style list of tuples. Each tuple should be a 4-tuple with filename, lineno, name, line as the elements.

  • format()

    Returns a list of strings ready for printing. Each string in the resulting list corresponds to a single frame from the stack. Each string ends in a newline; the strings may contain internal newlines as well, for those items with source text lines.

    For long sequences of the same frame and line, the first few repetitions are shown, followed by a summary line stating the exact number of further repetitions.

    在 3.6 版更改: Long sequences of repeated frames are now abbreviated.

FrameSummary Objects

3.5 新版功能.

FrameSummary objects represent a single frame in a traceback.

class traceback.FrameSummary(filename, lineno, name, lookup_line=True, locals=None, line=None)

Represent a single frame in the traceback or stack that is being formatted or printed. It may optionally have a stringified version of the frames locals included in it. If lookup_line is False, the source code is not looked up until the FrameSummary has the line attribute accessed (which also happens when casting it to a tuple). line may be directly provided, and will prevent line lookups happening at all. locals is an optional local variable dictionary, and if supplied the variable representations are stored in the summary for later display.

Traceback Examples

This simple example implements a basic read-eval-print loop, similar to (but less useful than) the standard Python interactive interpreter loop. For a more complete implementation of the interpreter loop, refer to the code module.

import sys, traceback
def run_user_code(envdir):
    source = input(">>> ")
    try:
        exec(source, envdir)
    except Exception:
        print("Exception in user code:")
        print("-"*60)
        traceback.print_exc(file=sys.stdout)
        print("-"*60)
envdir = {}
while True:
    run_user_code(envdir)

The following example demonstrates the different ways to print and format the exception and traceback:

import sys, traceback
def lumberjack():
    bright_side_of_death()
def bright_side_of_death():
    return tuple()[0]
try:
    lumberjack()
except IndexError:
    exc_type, exc_value, exc_traceback = sys.exc_info()
    print("*** print_tb:")
    traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
    print("*** print_exception:")
    # exc_type below is ignored on 3.5 and later
    traceback.print_exception(exc_type, exc_value, exc_traceback,
                              limit=2, file=sys.stdout)
    print("*** print_exc:")
    traceback.print_exc(limit=2, file=sys.stdout)
    print("*** format_exc, first and last line:")
    formatted_lines = traceback.format_exc().splitlines()
    print(formatted_lines[0])
    print(formatted_lines[-1])
    print("*** format_exception:")
    # exc_type below is ignored on 3.5 and later
    print(repr(traceback.format_exception(exc_type, exc_value,
                                          exc_traceback)))
    print("*** extract_tb:")
    print(repr(traceback.extract_tb(exc_traceback)))
    print("*** format_tb:")
    print(repr(traceback.format_tb(exc_traceback)))
    print("*** tb_lineno:", exc_traceback.tb_lineno)

The output for the example would look similar to this:

*** print_tb:
  File "<doctest...>", line 10, in <module>
    lumberjack()
*** print_exception:
Traceback (most recent call last):
  File "<doctest...>", line 10, in <module>
    lumberjack()
  File "<doctest...>", line 4, in lumberjack
    bright_side_of_death()
IndexError: tuple index out of range
*** print_exc:
Traceback (most recent call last):
  File "<doctest...>", line 10, in <module>
    lumberjack()
  File "<doctest...>", line 4, in lumberjack
    bright_side_of_death()
IndexError: tuple index out of range
*** format_exc, first and last line:
Traceback (most recent call last):
IndexError: tuple index out of range
*** format_exception:
['Traceback (most recent call last):\n',
 '  File "<doctest...>", line 10, in <module>\n    lumberjack()\n',
 '  File "<doctest...>", line 4, in lumberjack\n    bright_side_of_death()\n',
 '  File "<doctest...>", line 7, in bright_side_of_death\n    return tuple()[0]\n',
 'IndexError: tuple index out of range\n']
*** extract_tb:
[<FrameSummary file <doctest...>, line 10 in <module>>,
 <FrameSummary file <doctest...>, line 4 in lumberjack>,
 <FrameSummary file <doctest...>, line 7 in bright_side_of_death>]
*** format_tb:
['  File "<doctest...>", line 10, in <module>\n    lumberjack()\n',
 '  File "<doctest...>", line 4, in lumberjack\n    bright_side_of_death()\n',
 '  File "<doctest...>", line 7, in bright_side_of_death\n    return tuple()[0]\n']
*** tb_lineno: 10

The following example shows the different ways to print and format the stack:

>>> import traceback
>>> def another_function():
...     lumberstack()
...
>>> def lumberstack():
...     traceback.print_stack()
...     print(repr(traceback.extract_stack()))
...     print(repr(traceback.format_stack()))
...
>>> another_function()
  File "<doctest>", line 10, in <module>
    another_function()
  File "<doctest>", line 3, in another_function
    lumberstack()
  File "<doctest>", line 6, in lumberstack
    traceback.print_stack()
[('<doctest>', 10, '<module>', 'another_function()'),
 ('<doctest>', 3, 'another_function', 'lumberstack()'),
 ('<doctest>', 7, 'lumberstack', 'print(repr(traceback.extract_stack()))')]
['  File "<doctest>", line 10, in <module>\n    another_function()\n',
 '  File "<doctest>", line 3, in another_function\n    lumberstack()\n',
 '  File "<doctest>", line 8, in lumberstack\n    print(repr(traceback.format_stack()))\n']

This last example demonstrates the final few formatting functions:

>>> import traceback
>>> traceback.format_list([('spam.py', 3, '<module>', 'spam.eggs()'),
...                        ('eggs.py', 42, 'eggs', 'return "bacon"')])
['  File "spam.py", line 3, in <module>\n    spam.eggs()\n',
 '  File "eggs.py", line 42, in eggs\n    return "bacon"\n']
>>> an_error = IndexError('tuple index out of range')
>>> traceback.format_exception_only(type(an_error), an_error)
['IndexError: tuple index out of range\n']

__future__ —- Future 语句定义

源代码: Lib/future.py


__future__ 是一个真正的模块,这主要有 3 个原因:

  • 避免混淆已有的分析 import 语句并查找 import 的模块的工具。
  • 确保 future 语句 在 2.1 之前的版本运行时至少能抛出 runtime 异常(import __future__ 会失败,因为 2.1 版本之前没有这个模块)。
  • 当引入不兼容的修改时,可以记录其引入的时间以及强制使用的时间。这是一种可执行的文档,并且可以通过 import __future__ 来做程序性的检查。

__future__.py 中的每一条语句都是以下格式的:

FeatureName = _Feature(OptionalRelease, MandatoryRelease,
                       CompilerFlag)

通常 OptionalRelease 要比 MandatoryRelease 小,并且都是和 sys.version_info 格式一致的 5 元素元组。

(PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int
 PY_MINOR_VERSION, # the 1; an int
 PY_MICRO_VERSION, # the 0; an int
 PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string
 PY_RELEASE_SERIAL # the 3; an int
)

OptionalRelease 记录了一个特性首次发布时的 Python 版本。

MandatoryRelases 还没有发布时,MandatoryRelease 表示该特性会变成语言的一部分的预测时间。

其他情况下,MandatoryRelease 用来记录这个特性是何时成为语言的一部分的。从该版本往后,使用该特性将不需要 future 语句,不过很多人还是会加上对应的 import。

MandatoryRelease 也可能是 None, 表示这个特性已经被撤销。

_Feature 类的实例有两个对应的方法,getOptionalRelease()getMandatoryRelease()

CompilerFlag 是一个(位)标记,对于动态编译的代码,需要将这个标记作为第四个参数传入内建函数 compile() 中以开启对应的特性。这个标记存储在 _Feature 类实例的 compiler_flag 属性中。

__future__ 中不会删除特性的描述。从 Python 2.1 中首次加入以来,通过这种方式引入了以下特性:

特性 可选版本 强制加入版本 效果
nested_scopes 2.1.0b1 2.2 PEP 227: 静态嵌套作用域
generators 2.2.0a1 2.3 PEP 255: 简单生成器
division 2.2.0a2 3.0 PEP 238: 修改除法运算符
absolute_import 2.5.0a1 3.0 PEP 328: 导入:多行与绝对/相对
with_statement 2.5.0a1 2.6 PEP 343: “with” 语句
print_function 2.6.0a2 3.0 PEP 3105: print 改为函数
unicode_literals 2.6.0a2 3.0 PEP 3112: Python 3000 中的字节字面值
generator_stop 3.5.0b1 3.7 PEP 479: 在生成器中处理 StopIteration
annotations 3.7.0b1 3.11 PEP 563: Postponed evaluation of annotations

参见

future 语句

编译器怎样处理 future import。

gc —- 垃圾回收器接口

此模块提供可选的垃圾回收器的接口,提供的功能包括:关闭收集器、调整收集频率、设置调试选项。它同时提供对回收器找到但是无法释放的不可达对象的访问。由于 Python 使用了带有引用计数的回收器,如果你确定你的程序不会产生循环引用,你可以关闭回收器。可以通过调用 gc.disable() 关闭自动垃圾回收。若要调试一个存在内存泄漏的程序,调用 gc.set_debug(gc.DEBUG_LEAK) ;需要注意的是,它包含 gc.DEBUG_SAVEALL ,使得被垃圾回收的对象会被存放在 gc.garbage 中以待检查。

gc 模块提供下列函数:

gc.enable()

启用自动垃圾回收

gc.disable()

停用自动垃圾回收

gc.isenabled()

如果启用了自动回收则返回 True

gc.collect(generation=2)

若被调用时不包含参数,则启动完全的垃圾回收。可选的参数 generation 可以是一个整数,指明需要回收哪一代(从 0 到 2 )的垃圾。当参数 generation 无效时,会引发 ValueError 异常。返回发现的不可达对象的数目。

每当运行完整收集或最高代 (2) 收集时,为多个内置类型所维护的空闲列表会被清空。 由于特定类型特别是 float 的实现,在某些空闲列表中并非所有项都会被释放。

gc.set_debug(flags)

设置垃圾回收器的调试标识位。调试信息会被写入 sys.stderr 。此文档末尾列出了各个标志位及其含义;可以使用位操作对多个标志位进行设置以控制调试器。

gc.get_debug()

返回当前调试标识位。

gc.get_objects(generation=None)

返回一个收集器所跟踪的所有对象的列表,所返回的列表除外。 如果 generation 不为 None,则只返回收集器所跟踪的属于该生成的对象。

在 3.8 版更改: 新的 generation 形参。

引发一个 审计事件 gc.get_objects,附带参数 generation

gc.get_stats()

返回一个包含三个字典对象的列表,每个字典分别包含对应代的从解释器开始运行的垃圾回收统计数据。字典的键的数目在将来可能发生改变,目前每个字典包含以下内容:

  • collections 是该代被回收的次数;
  • collected 是该代中被回收的对象总数;
  • uncollectable 是在这一代中被发现无法收集的对象总数 (因此被移动到 garbage 列表中)。

3.4 新版功能.

gc.set_threshold(threshold0[, threshold1[, threshold2]])

设置垃圾回收阈值(收集频率)。 将 threshold0 设为零会禁用回收。

垃圾回收器把所有对象分类为三代,其依据是对象在多少次垃圾回收后幸存。 新建对象会被放在最年轻代(第 0 代)。 如果一个对象在一次垃圾回收后幸存,它会被移入下一个较老代。 由于第 2 代是最老代,这一代的对象在一次垃圾回收后仍会保留原样。 为了确定何时要运行,垃圾回收器会跟踪自上一次回收后对象分配和释放的数量。 当分配数量减去释放数量的结果值大于 threshold0 时,垃圾回收就会开始。 初始时只有第 0 代会被检查。 如果自第 1 代被检查后第 0 代已被检查超过 threshold1 次,则第 1 也会被检查。 对于第三代来说情况还会更复杂。

gc.get_count()

将当前回收计数以形为 (count0, count1, count2) 的元组返回。

gc.get_threshold()

将当前回收阈值以形为 (threshold0, threshold1, threshold2) 的元组返回。

gc.get_referrers(\objs*)

返回直接引用任意一个 ojbs 的对象列表。这个函数只定位支持垃圾回收的容器;引用了其它对象但不支持垃圾回收的扩展类型不会被找到。

需要注意的是,已经解除对 objs 引用的对象,但仍存在于循环引用中未被回收时,仍然会被作为引用者出现在返回的列表当中。若要获取当前正在引用 objs 的对象,需要调用 collect() 然后再调用 get_referrers()

警告

在使用 get_referrers() 返回的对象时必须要小心,因为其中一些对象可能仍在构造中因此处于暂时的无效状态。不要把 get_referrers() 用于调试以外的其它目的。

引发一个 审计事件 gc.get_referrers,附带参数 objs

gc.get_referents(\objs*)

返回被任意一个参数中的对象直接引用的对象的列表。返回的被引用对象是被参数中的对象的C语言级别方法(若存在) tp_traverse 访问到的对象,可能不是所有的实际直接可达对象。只有支持垃圾回收的对象支持 tp_traverse 方法,并且此方法只会在需要访问涉及循环引用的对象时使用。因此,可以有以下例子:一个整数对其中一个参数是直接可达的,这个整数有可能出现或不出现在返回的结果列表当中。

引发一个 审计事件 gc.get_referents,附带参数 objs

gc.is_tracked(obj)

当对象正在被垃圾回收器监控时返回 True ,否则返回 False 。一般来说,原子类的实例不会被监控,而非原子类(如容器、用户自定义的对象)会被监控。然而,会有一些特定类型的优化以便减少垃圾回收器在简单实例(如只含有原子性的键和值的字典)上的消耗。

>>> gc.is_tracked(0)
False
>>> gc.is_tracked("a")
False
>>> gc.is_tracked([])
True
>>> gc.is_tracked({})
False
>>> gc.is_tracked({"a": 1})
False
>>> gc.is_tracked({"a": []})
True

3.1 新版功能.

gc.is_finalized(obj)

如果给定对象已被垃圾回收器终结则返回 True,否则返回 False

>>> x = None
>>> class Lazarus:
...     def __del__(self):
...         global x
...         x = self
...
>>> lazarus = Lazarus()
>>> gc.is_finalized(lazarus)
False
>>> del lazarus
>>> gc.is_finalized(x)
True

3.9 新版功能.

gc.freeze()

冻结 gc 所跟踪的所有对象 —— 将它们移至永久代并忽略所有未来的集合。 这可以在 POSIX fork() 调用之前使用以便令对写入复制保持友好或加速收集。 并且在 POSIX fork() 调用之前的收集也可以释放页面以供未来分配,这也可能导致写入时复制,因此建议在主进程中禁用 gc 并在 fork 之前冻结,而在子进程中启用 gc。

3.7 新版功能.

gc.unfreeze()

解冻永久代中的对象,并将它们放回到年老代中。

3.7 新版功能.

gc.get_freeze_count()

返回永久代中的对象数量。

3.7 新版功能.

提供以下变量仅供只读访问(你可以修改但不应该重绑定它们):

gc.garbage

一个回收器发现不可达而又无法被释放的对象(不可回收对象)列表。 从 Python 3.4 开始,该列表在大多数时候都应该是空的,除非使用了含有非 NULL tp_del 空位的 C 扩展类型的实例。

如果设置了 DEBUG_SAVEALL ,则所有不可访问对象将被添加至该列表而不会被释放。

在 3.2 版更改: 当 interpreter shutdown 即解释器关闭时,若此列表非空,会产生 ResourceWarning ,即资源警告,在默认情况下此警告不会被提醒。如果设置了 DEBUG_UNCOLLECTABLE ,所有无法被回收的对象会被打印。

在 3.4 版更改: 根据 PEP 442 ,带有 __del__() 方法的对象最终不再会进入 gc.garbage

gc.callbacks

在垃圾回收器开始前和完成后会被调用的一系列回调函数。这些回调函数在被调用时使用两个参数: phaseinfo

phase 可为以下两值之一:

“start”: 垃圾回收即将开始。

“stop”: 垃圾回收已结束。

info is a dict providing more information for the callback. The following keys are currently defined:

“generation”(代) :正在被回收的最久远的一代。

“collected”(已回收的 ): 当phase 为 “stop” 时,被成功回收的对象的数目。

“uncollectable”(不可回收的): 当 phase 为 “stop” 时,不能被回收并被放入 garbage 的对象的数目。

应用程序可以把他们自己的回调函数加入此列表。主要的使用场景有:

统计垃圾回收的数据,如:不同代的回收频率、回收所花费的时间。

使应用程序可以识别和清理他们自己的在 garbage 中的不可回收类型的对象。

3.3 新版功能.

以下常量被用于 set_debug()

gc.DEBUG_STATS

在回收完成后打印统计信息。当回收频率设置较高时,这些信息会比较有用。

gc.DEBUG_COLLECTABLE

当发现可回收对象时打印信息。

gc.DEBUG_UNCOLLECTABLE

打印找到的不可回收对象的信息(指不能被回收器回收的不可达对象)。这些对象会被添加到 garbage 列表中。

在 3.2 版更改: 当 interpreter shutdown 时,即解释器关闭时,若 garbage 列表中存在对象,这些对象也会被打印输出。

gc.DEBUG_SAVEALL

设置后,所有回收器找到的不可达对象会被添加进 garbage 而不是直接被释放。这在调试一个内存泄漏的程序时会很有用。

gc.DEBUG_LEAK

调试内存泄漏的程序时,使回收器打印信息的调试标识位。(等价于 DEBUG_COLLECTABLE | DEBUG_UNCOLLECTABLE | DEBUG_SAVEALL )。

inspect —- 检查对象

源代码: Lib/inspect.py


inspect 模块提供了一些有用的函数帮助获取对象的信息,例如模块、类、方法、函数、回溯、帧对象以及代码对象。例如它可以帮助你检查类的内容,获取某个方法的源代码,取得并格式化某个函数的参数列表,或者获取你需要显示的回溯的详细信息。

该模块提供了4种主要的功能:类型检查、获取源代码、检查类与函数、检查解释器的调用堆栈。

类型和成员

getmembers() 函数获取对象的成员,例如类或模块。函数名以”is”开始的函数主要作为 getmembers() 的第2个参数使用。它们也可用于判定某对象是否有如下的特殊属性:

类型 属性 描述
module — 模块 doc 文档字符串
file 文件名(内置模块没有文件名)
class — 类 doc 文档字符串
name 类定义时所使用的名称
qualname qualified name — 限定名称
module 该类型被定义时所在的模块的名称
method — 方法 doc 文档字符串
name 该方法定义时所使用的名称
qualname qualified name — 限定名称
func 实现该方法的函数对象
self 该方法被绑定的实例,若没有绑定则为 None
module 定义此方法的模块的名称
function — 函数 doc 文档字符串
name 用于定义此函数的名称
qualname qualified name — 限定名称
code 包含已编译函数的代码对象 bytecode
defaults 所有位置或关键字参数的默认值的元组
kwdefaults mapping of any default values for keyword-only parameters
globals global namespace in which this function was defined
builtins builtins namespace
annotations mapping of parameters names to annotations; “return” key is reserved for return annotations.
module name of module in which this function was defined
回溯 tbframe 此级别的框架对象
tb_lasti index of last attempted instruction in bytecode
tb_lineno current line number in Python source code
tb_next next inner traceback object (called by this level)
框架 f_back next outer frame object (this frame’s caller)
f_builtins builtins namespace seen by this frame
f_code code object being executed in this frame
f_globals global namespace seen by this frame
f_lasti index of last attempted instruction in bytecode
f_lineno current line number in Python source code
f_locals local namespace seen by this frame
f_trace tracing function for this frame, or None
code co_argcount number of arguments (not including keyword only arguments, or * args)
co_code 原始编译字节码的字符串
co_cellvars 单元变量名称的元组(通过包含作用域引用)
co_consts 字节码中使用的常量元组
co_filename 创建此代码对象的文件的名称
co_firstlineno number of first line in Python source code
co_flags bitmap of CO flags, read more here
co_lnotab 编码的行号到字节码索引的映射
co_freevars tuple of names of free variables (referenced via a function’s closure)
co_posonlyargcount number of positional only arguments
co_kwonlyargcount number of keyword only arguments (not including * arg)
coname 定义此代码对象的名称
conames 局部变量名称的元组
conlocals 局部变量的数量
costacksize 需要虚拟机堆栈空间
covarnames 参数名和局部变量的元组
generator — 生成器 name 名称
qualname qualified name — 限定名称
giframe 框架
girunning 生成器在运行吗?
gicode code
giyieldfrom object being iterated by yield from, or None
coroutine — 协程 name 名称
_qualname qualified name — 限定名称
cr_await object being awaited on, or None
cr_frame 框架
cr_running is the coroutine running?
cr_code code
cr_origin where coroutine was created, or None. See sys.set_coroutine_origin_tracking_depth()
builtin __doc 文档字符串
__name 此函数或方法的原始名称
__qualname qualified name — 限定名称
__self instance to which a method is bound, or None

在 3.5 版更改: Add __qualname__ and gi_yieldfrom attributes to generators.

The __name__ attribute of generators is now set from the function name, instead of the code name, and it can now be modified.

在 3.7 版更改: Add cr_origin attribute to coroutines.

在 3.10 版更改: Add __builtins__ attribute to functions.

inspect.getmembers(object[, predicate])

Return all the members of an object in a list of (name, value) pairs sorted by name. If the optional predicate argument—which will be called with the value object of each member—is supplied, only members for which the predicate returns a true value are included.

注解

getmembers() will only return class attributes defined in the metaclass when the argument is a class and those attributes have been listed in the metaclass’ custom __dir__().

inspect.getmodulename(path)

Return the name of the module named by the file path, without including the names of enclosing packages. The file extension is checked against all of the entries in importlib.machinery.all_suffixes(). If it matches, the final path component is returned with the extension removed. Otherwise, None is returned.

Note that this function only returns a meaningful name for actual Python modules - paths that potentially refer to Python packages will still return None.

在 3.3 版更改: The function is based directly on importlib.

inspect.ismodule(object)

Return True if the object is a module.

inspect.isclass(object)

Return True if the object is a class, whether built-in or created in Python code.

inspect.ismethod(object)

Return True if the object is a bound method written in Python.

inspect.isfunction(object)

Return True if the object is a Python function, which includes functions created by a lambda expression.

inspect.isgeneratorfunction(object)

Return True if the object is a Python generator function.

在 3.8 版更改: Functions wrapped in functools.partial() now return True if the wrapped function is a Python generator function.

inspect.isgenerator(object)

Return True if the object is a generator.

inspect.iscoroutinefunction(object)

Return True if the object is a coroutine function (a function defined with an async def syntax).

3.5 新版功能.

在 3.8 版更改: Functions wrapped in functools.partial() now return True if the wrapped function is a coroutine function.

inspect.iscoroutine(object)

Return True if the object is a coroutine created by an async def function.

3.5 新版功能.

inspect.isawaitable(object)

Return True if the object can be used in await expression.

Can also be used to distinguish generator-based coroutines from regular generators:

def gen():
    yield
@types.coroutine
def gen_coro():
    yield
assert not isawaitable(gen())
assert isawaitable(gen_coro())

3.5 新版功能.

inspect.isasyncgenfunction(object)

Return True if the object is an asynchronous generator function, for example:

>>> async def agen():
...     yield 1
...
>>> inspect.isasyncgenfunction(agen)
True

3.6 新版功能.

在 3.8 版更改: Functions wrapped in functools.partial() now return True if the wrapped function is a asynchronous generator function.

inspect.isasyncgen(object)

Return True if the object is an asynchronous generator iterator created by an asynchronous generator function.

3.6 新版功能.

inspect.istraceback(object)

Return True if the object is a traceback.

inspect.isframe(object)

Return True if the object is a frame.

inspect.iscode(object)

Return True if the object is a code.

inspect.isbuiltin(object)

Return True if the object is a built-in function or a bound built-in method.

inspect.isroutine(object)

Return True if the object is a user-defined or built-in function or method.

inspect.isabstract(object)

Return True if the object is an abstract base class.

inspect.ismethoddescriptor(object)

Return True if the object is a method descriptor, but not if ismethod(), isclass(), isfunction() or isbuiltin() are true.

This, for example, is true of int.__add__. An object passing this test has a __get__() method but not a __set__() method, but beyond that the set of attributes varies. A __name__ attribute is usually sensible, and __doc__ often is.

Methods implemented via descriptors that also pass one of the other tests return False from the ismethoddescriptor() test, simply because the other tests promise more — you can, e.g., count on having the __func__ attribute (etc) when an object passes ismethod().

inspect.isdatadescriptor(object)

Return True if the object is a data descriptor.

Data descriptors have a __set__ or a __delete__ method. Examples are properties (defined in Python), getsets, and members. The latter two are defined in C and there are more specific tests available for those types, which is robust across Python implementations. Typically, data descriptors will also have __name__ and __doc__ attributes (properties, getsets, and members have both of these attributes), but this is not guaranteed.

inspect.isgetsetdescriptor(object)

Return True if the object is a getset descriptor.

CPython implementation detail: getsets are attributes defined in extension modules via PyGetSetDef structures. For Python implementations without such types, this method will always return False.

inspect.ismemberdescriptor(object)

Return True if the object is a member descriptor.

CPython implementation detail: Member descriptors are attributes defined in extension modules via PyMemberDef structures. For Python implementations without such types, this method will always return False.

Retrieving source code

inspect.getdoc(object)

Get the documentation string for an object, cleaned up with cleandoc(). If the documentation string for an object is not provided and the object is a class, a method, a property or a descriptor, retrieve the documentation string from the inheritance hierarchy.

在 3.5 版更改: Documentation strings are now inherited if not overridden.

inspect.getcomments(object)

Return in a single string any lines of comments immediately preceding the object’s source code (for a class, function, or method), or at the top of the Python source file (if the object is a module). If the object’s source code is unavailable, return None. This could happen if the object has been defined in C or the interactive shell.

inspect.getfile(object)

Return the name of the (text or binary) file in which an object was defined. This will fail with a TypeError if the object is a built-in module, class, or function.

inspect.getmodule(object)

Try to guess which module an object was defined in.

inspect.getsourcefile(object)

Return the name of the Python source file in which an object was defined. This will fail with a TypeError if the object is a built-in module, class, or function.

inspect.getsourcelines(object)

Return a list of source lines and starting line number for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a list of the lines corresponding to the object and the line number indicates where in the original source file the first line of code was found. An OSError is raised if the source code cannot be retrieved.

在 3.3 版更改: OSError is raised instead of IOError, now an alias of the former.

inspect.getsource(object)

Return the text of the source code for an object. The argument may be a module, class, method, function, traceback, frame, or code object. The source code is returned as a single string. An OSError is raised if the source code cannot be retrieved.

在 3.3 版更改: OSError is raised instead of IOError, now an alias of the former.

inspect.cleandoc(doc)

Clean up indentation from docstrings that are indented to line up with blocks of code.

All leading whitespace is removed from the first line. Any leading whitespace that can be uniformly removed from the second line onwards is removed. Empty lines at the beginning and end are subsequently removed. Also, all tabs are expanded to spaces.

Introspecting callables with the Signature object

3.3 新版功能.

The Signature object represents the call signature of a callable object and its return annotation. To retrieve a Signature object, use the signature() function.

inspect.signature(callable, **, follow_wrapped=True, globals=None, locals=None, eval_str=False*)

Return a Signature object for the given callable:

>>> from inspect import signature
>>> def foo(a, *, b:int, **kwargs):
...     pass
>>> sig = signature(foo)
>>> str(sig)
'(a, *, b:int, **kwargs)'
>>> str(sig.parameters['b'])
'b:int'
>>> sig.parameters['b'].annotation
<class 'int'>

Accepts a wide range of Python callables, from plain functions and classes to functools.partial() objects.

For objects defined in modules using stringized annotations (from __future__ import annotations), signature() will attempt to automatically un-stringize the annotations using inspect.get_annotations(). The global, locals, and eval_str parameters are passed into inspect.get_annotations() when resolving the annotations; see the documentation for inspect.get_annotations() for instructions on how to use these parameters.

Raises ValueError if no signature can be provided, and TypeError if that type of object is not supported. Also, if the annotations are stringized, and eval_str is not false, the eval() call(s) to un-stringize the annotations could potentially raise any kind of exception.

A slash(/) in the signature of a function denotes that the parameters prior to it are positional-only. For more info, see the FAQ entry on positional-only parameters.

3.5 新版功能: follow_wrapped parameter. Pass False to get a signature of callable specifically (callable.__wrapped__ will not be used to unwrap decorated callables.)

3.10 新版功能: globals, locals, and eval_str parameters.

注解

Some callables may not be introspectable in certain implementations of Python. For example, in CPython, some built-in functions defined in C provide no metadata about their arguments.

class inspect.Signature(parameters=None, **, return_annotation=Signature.empty*)

A Signature object represents the call signature of a function and its return annotation. For each parameter accepted by the function it stores a Parameter object in its parameters collection.

The optional parameters argument is a sequence of Parameter objects, which is validated to check that there are no parameters with duplicate names, and that the parameters are in the right order, i.e. positional-only first, then positional-or-keyword, and that parameters with defaults follow parameters without defaults.

The optional return_annotation argument, can be an arbitrary Python object, is the “return” annotation of the callable.

Signature objects are immutable. Use Signature.replace() to make a modified copy.

在 3.5 版更改: Signature objects are picklable and hashable.

  • empty

    A special class-level marker to specify absence of a return annotation.

  • parameters

    An ordered mapping of parameters’ names to the corresponding Parameter objects. Parameters appear in strict definition order, including keyword-only parameters.

    在 3.7 版更改: Python only explicitly guaranteed that it preserved the declaration order of keyword-only parameters as of version 3.7, although in practice this order had always been preserved in Python 3.

  • return_annotation

    The “return” annotation for the callable. If the callable has no “return” annotation, this attribute is set to Signature.empty.

  • bind(\args, *kwargs)

    Create a mapping from positional and keyword arguments to parameters. Returns BoundArguments if *args and **kwargs match the signature, or raises a TypeError.

  • bind_partial(\args, *kwargs)

    Works the same way as Signature.bind(), but allows the omission of some required arguments (mimics functools.partial() behavior.) Returns BoundArguments, or raises a TypeError if the passed arguments do not match the signature.

  • replace(\, parameters*)

    Create a new Signature instance based on the instance replace was invoked on. It is possible to pass different parameters and/or return_annotation to override the corresponding properties of the base signature. To remove return_annotatio