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 suitetest.support.socket_helper
—- Utilities for socket teststest.support.script_helper
—- Utilities for the Python execution teststest.support.bytecode_helper
—- Support tools for testing correct bytecode generationtest.support.threading_helper
—- Utilities for threading teststest.support.os_helper
—- Utilities for os teststest.support.import_helper
—- Utilities for import teststest.support.warnings_helper
—- Utilities for warnings tests
- 调试和分析
- 审计事件表
bdb
—- Debugger frameworkfaulthandler
—- Dump the Python tracebackpdb
—- Python 的调试器- Python Profilers 分析器
timeit
—- 测量小代码片段的执行时间trace
—- 跟踪Python语句的执行tracemalloc
—- 跟踪内存分配
- 软件打包和分发
distutils
—- 构建和安装 Python 模块ensurepip
—- Bootstrapping thepip
installervenv
—- 创建虚拟环境zipapp
—- Manage executable Python zip archives
- Python运行时服务
sys
—- 系统相关的参数和函数sysconfig
—- Provide access to Python’s configuration informationbuiltins
—- 内建对象__main__
—- Top-level code environmentwarnings
—— 警告信息的控制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 tablestoken
—- 与Python解析树一起使用的常量keyword
—- 检验Python关键字tokenize
—- 对 Python 代码使用的标记解析器tabnanny
—- 模糊缩进检测pyclbr
—- Python 模块浏览器支持py_compile
—- 编译 Python 源文件compileall
—- Byte-compile Python librariesdis
—- Python 字节码反汇编器pickletools
—- pickle 开发者工具集
- Windows系统相关模块
msilib
—- Read and write Microsoft Installer filesmsvcrt
—- 来自 MS VC++ 运行时的有用例程winreg
—- 访问 Windows 注册表winsound
—— Windows 系统的音频播放接口
- Unix 专有服务
posix
—- 最常见的 POSIX 系统调用pwd
—- 用户密码数据库spwd
—- The shadow password databasegrp
—- 组数据库crypt
—— 验证 Unix 口令的函数termios
—- POSIX 风格的 tty 控制tty
—- 终端控制功能pty
—- 伪终端工具fcntl
—— 系统调用fcntl
和ioctl
pipes
—- 终端管道接口resource
—- Resource usage informationnis
—- 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
, 3
或 4
。两个片段的长度应相同。如果发生溢出,较长的采样将被截断。
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。
参数 weightA 和 weightB 是简单数字滤波器的参数,默认分别为 1
和 0
。
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 声音格式的便利接口。请注意此模块与 aifc
和 wave
是兼容接口的。
音频文件由标头和数据组成。标头的字段为:
域 | 目录 |
---|---|
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.html 和 https://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 新版功能: exr 和 webp 格式被添加。
你可以扩展此 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 也会返回实际值或者在无法推测或者难以解码时返回 0
。 frames 则是实际值或 -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:
setfmt()
to set the output formatchannels()
to set the number of channelsspeed()
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_MESSAGES和
LANG` 中。
如果遗漏了 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)
修改或查询当前的全局域。如果 domain 为 None
,则返回当前的全局域,不为 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()
接受的域相同。可选参数 *localedir 与 bindtextdomain()
中的相同。可选参数 languages 是多条字符串的列表,其中每条字符串都是一种语言代码。
如果没有传入 localedir,则使用默认的系统语言环境目录。如果没有传入 *languages,则搜索以下环境变量:LANGUAGE
、LC_ALL
、LC_MESSAGES
和 LANG
。从这些变量返回的第一个非空值将用作 *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)
根据 domain、localedir 和 languages,返回 *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()
函数的 domain、localedir 和 codeset,在 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)在编目中查找 context 和 message 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 程序提供不同语言的消息,需要执行以下步骤:
- 准备程序或模块,将可翻译的字符串特别标记起来
- 在已标记的文件上运行一套工具,用来生成原始消息编目
- 创建消息编目的不同语言的翻译
- 使用
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.py 和 msgfmt.py,某些 Python 发行版已经安装了它们。pygettext.py 类似于 xgettext,但只能理解 Python 源代码,无法处理诸如 C 或 C++ 的其他编程语言。pygettext.py 支持的命令行界面类似于 xgettext,查看其详细用法请运行 pygettext.py --help
。msgfmt.py 与 GNU msgfmt 是二进制兼容的。有了这两个程序,可以不需要 GNU gettext 包来国际化 Python 应用程序。)
xgettext、pygettext 或类似工具生成的 .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 extract
和 xpot 都支持此功能,使用 -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 inre
.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 thetime.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”个类:
TurtleScreen
类定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas
或ScrolledCanvas
作为参数。应在turtle
作为某个程序的一部分的时候使用。Screen()
函数返回一个TurtleScreen
子类的单例对象。此函数应在turtle
作为独立绘图工具时使用。作为一个单例对象,其所属的类是不可被继承的。TurtleScreen/Screen 的所有方法还存在对应的函数,即作为面向过程的接口组成部分。
RawTurtle
(别名:RawPen
) 类定义海龟对象在TurtleScreen
上绘图。它的构造器需要一个 Canvas, ScrolledCanvas 或 TurtleScreen 作为参数,以指定 RawTurtle 对象在哪里绘图。从 RawTurtle 派生出子类
Turtle
(别名:Pen
),该类对象在Screen
实例上绘图,如果实例不存在则会自动创建。RawTurtle/Turtle 的所有方法也存在对应的函数,即作为面向过程的接口组成部分。
过程式接口提供与 Screen
和 Turtle
类的方法相对应的函数。函数名与对应的方法名相同。当 Screen 类的方法对应函数被调用时会自动创建一个 Screen 对象。当 Turtle 类的方法对应函数被调用时会自动创建一个 (匿名的) Turtle 对象。
如果屏幕上需要有多个海龟,就必须使用面向对象的接口。
shlex
—— 简单的词法分析
源代码: Lib/shlex.py
shlex
类可用于编写类似 Unix shell 的简单词法分析程序。通常可用于编写“迷你语言”(如 Python 应用程序的运行控制文件)或解析带引号的字符串。
shlex
模块中定义了以下函数:
shlex.split
(s, comments=False, posix=True)
用类似 shell 的语法拆分字符串 s。如果 comments 为 False
(默认值),则不会解析给定字符串中的注释 (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_split
为False
,则未声明为单词字符、空白或引号的字符将作为单字符的词法单元返回。若为True
, 则shlex
只根据空白符拆分单词。 - EOF 用空字符串(
''
)表示; - 空字符串无法解析,即便是加了引号。
在 POSIX 模式时,shlex
将尝试遵守以下解析规则:
- 引号会被剔除,且不会拆分单词(
"Do"Not"Separate"
将解析为单个单词DoNotSeparate
); - 未加引号包裹的转义字符(如
'\'
)保留后一个字符的字面意思; - 引号中的字符不属于
escapedquotes
(例如,"'"
),则保留引号中所有字符的字面值; - 若引号包裹的字符属于
escapedquotes
(例如'"'
),则保留引号中所有字符的字面意思,属于escape
中的字符除外。仅当后跟后半个引号或转义字符本身时,转义字符才保留其特殊含义。否则,转义字符将视作普通字符; - EOF 用
None
表示; - 允许出现引号包裹的空字符串(
''
)。
改进的 shell 兼容性
3.6 新版功能.
shlex
类提供了与常见 Unix shell(如 bash
、dash
和sh
)的解析兼容性。为了充分利用这种兼容性,请在构造函数中设定 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
时始终使用 posix
和 whitespace_split
,这将完全否定 wordchars
。
为了达到最佳效果,punctuation_chars
应与 posix=True
一起设置。(注意 posix=False
是 shlex
的默认设置)。
cmd
—- 支持面向行的命令解释器
源代码: Lib/cmd.py
Cmd
类提供简单框架用于编写面向行的命令解释器。 这些通常对测试工具,管理工具和原型有用,这些工具随后将被包含在更复杂的接口中。
class cmd.Cmd
(completekey=’tab’, stdin=None, stdout=None)
一个 Cmd
实例或子类实例是面向行的解释器框架结构。 实例化 Cmd
本身是没有充分理由的, 它作为自定义解释器类的超类是非常有用的为了继承 Cmd
的方法并且封装动作方法。
可选参数 completekey 是完成键的 readline
名称;默认是 Tab 。如果 completekey 不是 None
并且 readline
是可用的, 命令完成会自动完成。
可选参数 stdin 和 stdout 指定了Cmd实例或子类实例将用于输入和输出的输入和输出文件对象。如果没有指定,他们将默认为 sys.stdin
和 sys.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()
方法返回一个真值 。参数 stop 到 postcmd()
是命令对应的返回值 do_*()
的方法。
如果激活了完成,全部命令将会自动完成,并且通过调用 complete_foo()
参数 text , line, begidx ,和 endidx 完成全部命令参数。 text 是我们试图匹配的字符串前缀,所有返回的匹配项必须以它为开头。 line 是删除了前导空格的当前的输入行, begidx 和 endidx 是前缀文本的开始和结束索引。,可以用于根据参数位置提供不同的完成。
所有 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 框架和工具。
tkinter
— Tcl/Tk的Python接口- Architecture
- Tkinter 模块
- Tkinter Life Preserver
- Threading model
- Handy Reference
- File Handlers
tkinter.colorchooser
— 颜色选择对话框tkinter.font
— Tkinter 字体封装- Tkinter 对话框
tkinter.simpledialog
— 标准 Tkinter 输入对话框tkinter.filedialog
— 文件选择对话框.tkinter.commondialog
— 对话窗口模板
tkinter.messagebox
— Tkinter 消息提示tkinter.scrolledtext
— 滚动文字控件tkinter.dnd
— 拖放操作支持tkinter.ttk
— Tk主题部件tkinter.tix
— TK扩展包- IDLE
- 目录
- 编辑和导航
- 启动和代码执行
- 帮助和偏好
开发工具
本章中描述的各模块可帮你编写 Python 程序。例如,pydoc
模块接受一个模块并根据该模块的内容来生成文档。doctest
和 unittest
这两个模块包含了用于编写单元测试的框架,并可用于自动测试所编写的代码,验证预期的输出是否产生。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
- 使用 mock
- 2to3 - 自动将 Python 2 代码转为 Python 3 代码
- 使用 2to3
- 修复器
lib2to3
—— 2to3 支持库
test
—- Python回归测试包- Writing Unit Tests for the
test
package - Running tests using the command-line interface
- Writing Unit Tests for the
test.support
—- Utilities for the Python test suitetest.support.socket_helper
—- Utilities for socket teststest.support.script_helper
—- Utilities for the Python execution teststest.support.bytecode_helper
—- Support tools for testing correct bytecode generationtest.support.threading_helper
—- Utilities for threading teststest.support.os_helper
—- Utilities for os teststest.support.import_helper
—- Utilities for import teststest.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
。子类型也可以当作参数。
类型别名
把类型赋给别名,就可以定义类型别名。本例中,Vector
和 list[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
时,静态类型检查器认为 Alias
与 Original
完全等价。 这种方式适用于简化复杂类型签名。
反之,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
当作 应急出口。
Any
和 object
的区别。与 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 静态类型系统定义为应用 名义子类型。即,当且仅当 A
是 B
的子类时,才能在预期 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, ...]
。Tuple
与 Tuple[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
andConcatenate
). ParamSpec
andCallable
.
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=True
至 get_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:
The return value is a boolean.
If the return value is
True
, the type of its argument is the type insideTypeGuard
.例如:
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=True
或 contravariant=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:
- The type checker can’t type check the
inner
function because*args
and**kwargs
have to be typedAny
.cast()
may be required in the body of theadd_logging
decorator when returning theinner
function, or the static type checker must be told to ignore thereturn inner
.
args
kwargs
Since
ParamSpec
captures both positional and keyword parameters,P.args
andP.kwargs
can be used to split aParamSpec
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
andP.kwargs
are instances respectively ofParamSpecArgs
andParamSpecKwargs
.
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
andConcatenate
). Callable
andConcatenate
.
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.abc
的 Iterable
非常类似,只擅长做一件事。 例如:
@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
的泛型版本。适用于注解返回类型。注解参数时,最好使用 Sequence
或 Iterable
等抽象容器类型。
该类型用法如下:
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
模块中的 Pattern
与 Match
类现已支持 []
。详见 PEP 585 与 Generic Alias Type。
class typing.Text
Text
是 str
的别名。提供了对 Python 2 代码的向下兼容:Python 2 中,Text
是 unicode
的别名。
使用 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
的泛型版本。
该类型代表了 bytes
、bytearray
、memoryview
等字节序列类型。
作为该类型的简称,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 模块里的其他泛型不同, Generator
的 SendType
属于逆变行为,不是协变行为,也是不变行为。
如果生成器只产生值,可将 SendType
与 ReturnType
设为 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__
相同。此外,可通过在 globals
与 locals
命名空间里进行评估,以此来处理编码为字符串字面量的前向引用。如有需要,在默认值设置为 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
pydoc -b 将启动服务并额外打开一个 Web 浏览器访问模块索引页。 所发布的每个页面顶端都带有导航栏,你可以点击 Get 获取特定条目的帮助,点击 Search 在所有模块的提要行中搜索特定关键词,或是点击 Module index, Topics 和 Keywords 前往相应的页面。
当 pydoc 生成文档内容时,它会使用当前环境和路径来定位模块。 因此,发起调用 pydoc spam 得到的文档版本会与你启动 Python 解释器并输入 import spam
时得到的模块版本完全相同。
核心模块的模块文档位置对应于 https://docs.python.org/X.Y/library/
其中 X
和 Y
是 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”.
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
参数则可以明确指定不使用的修复器。下面的例子会只使用 imports
和 has_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 语句的代码运行修复器。 也可以使用 -e
将 exec()
解读为函数。
-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 SomeClass
和 type(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_value
,sys.exc_type
,sys.exc_traceback
替换为 sys.exc_info()
的用法。
throw
修复生成器的 throw()
方法的 API 变更。
tuple_params
移除隐式的元组参数解包。这个修复器会插入临时变量。
types
修复 type
模块中一些成员的移除引起的代码问题。
unicode
将 unicode
重命名为 str
。
urllib
将 urllib
和 urllib2
重命名为 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回归测试包
test
— Python回归测试包test.support
— Utilities for the Python test suitetest.support.socket_helper
— Utilities for socket teststest.support.script_helper
— Utilities for the Python execution teststest.support.bytecode_helper
— Support tools for testing correct bytecode generationtest.support.threading_helper
— Utilities for threading teststest.support.os_helper
— Utilities for os teststest.support.import_helper
— Utilities for import teststest.support.warnings_helper
— Utilities for warnings tests
调试和分析
这些库可以帮助你进行 Python 开发:调试器使你能够逐步执行代码,分析堆栈帧并设置中断点等等,性能分析器可以运行代码并为你提供执行时间的详细数据,使你能够找出你的程序中的瓶颈。 审计事件提供运行时行为的可见性,如果没有此工具则需要进行侵入式调试或修补。
- 审计事件表
bdb
— Debugger frameworkfaulthandler
—— 转储 Python 的跟踪信息pdb
— Python 的调试器- Python Profilers 分析器
timeit
— 测量小代码片段的执行时间trace
—— 跟踪 Python 语句的执行tracemalloc
— 跟踪内存分配
审计事件表
下表包含了在整个 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 thepip
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>
: Installspip
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
: Installspip
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, thepipX
script will not be installed.--default-pip
: if a “default pip” installation is requested, thepip
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 。
参见
创建虚拟环境
通过执行 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 安装 配置好 PATH
和 PATHEXT
变量:
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
选项,否则将会调用 ensurepip
将 pip
引导到虚拟环境中。
可以向 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 新版功能: fish
和 csh
激活脚本。
3.8 新版功能: 在 POSIX 上安装 PowerShell 激活脚本,以支持 PowerShell Core。
注解
虚拟环境是一个 Python 环境,安装到其中的 Python 解释器、库和脚本与其他虚拟环境中的内容是隔离的,且(默认)与“系统级” Python(操作系统的一部分)中安装的库是隔离的。
虚拟环境是一个目录树,其中包含 Python 可执行文件和其他文件,其他文件指示了这是一个是虚拟环境。
常用安装工具如 setuptools 和 pip 可以在虚拟环境中按预期工作。换句话说,当虚拟环境被激活,它们就会将 Python 软件包安装到虚拟环境中,无需明确指示。
当虚拟环境被激活(即虚拟环境的 Python 解释器正在运行),属性 sys.prefix
和 sys.exec_prefix
指向的是虚拟环境的基础目录,而 sys.base_prefix
和 sys.base_exec_prefix
指向非虚拟环境的 Python 安装,即曾用于创建虚拟环境的那个 Python 安装。如果虚拟环境没有被激活,则 sys.prefix
与 sys.base_prefix
相同,且 sys.exec_prefix
与 sys.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)创建环境目录和所有必需的目录,并返回一个上下文对象。该对象只是一个容器,保存属性(如路径),供其他方法使用。允许目录已经存在,如果指定了
clear
或upgrade
就允许在现有环境目录上进行操作。create_configuration
(context)在环境中创建
pyvenv.cfg
配置文件。setup_python
(context)在环境中创建 Python 可执行文件的拷贝或符号链接。在 POSIX 系统上,如果给定了可执行文件
python3.x
,将创建指向该可执行文件的python
和python3
符号链接,除非相同名称的文件已经存在。setup_scripts
(context)将适用于平台的激活脚本安装到虚拟环境中。
upgrade_dependencies
(context)升级环境中 venv 依赖的核心软件包(当前为
pip
和setuptools
)。通过在环境中使用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 目录的名称(bin
或Scripts
)。__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:
Create your application in a directory as normal, so you have a
myapp
directory containing a__main__.py
file, and any supporting application code.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).Optionally, delete the
.dist-info
directories created by pip in themyapp
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.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.
- 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 insys.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 tosys.path
at runtime, based on the user’s machine). - 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. - 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 themultiprocessing
module, it will need to callmultiprocessing.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:
- 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 insys.getfilesystemencoding()
on POSIX. - 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
ObjectsStackSummary
ObjectsFrameSummary
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
发现处于一个虚拟环境中, prefix
和 exec_prefix
将会指向虚拟环境。然而 base_prefix
和 base_exec_prefix
将仍然会指向基础的 Python 环境(用来创建虚拟环境的 Python 环境)
3.3 新版功能.
sys.base_prefix
在 site.py
运行之前, Python 启动的时候被设置为跟 prefix
同样的值。如果不是运行在 虚拟环境 中, 两个值会保持相同;如果 site.py
发现处于一个虚拟环境中, prefix
和 exec_prefix
将会指向虚拟环境。然而 base_prefix
和 base_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
文件。该值会被初始化为 True
或 False
,依据是 -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__
程序开始时,这些对象存有 breakpointhook
、displayhook
、excepthook
和 unraisablehook
的初始值。保存它们是为了可以在 breakpointhook
、displayhook
和 excepthook
、unraisablehook
被破坏或被替换时恢复它们。
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'
,那么对于(非无穷的)浮点数 x
,repr(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,则返回从栈顶往下相应调用层数的帧对象。如果该数比调用栈更深,则抛出 ValueError
。depth 的默认值是 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_type 和 platform_version。service_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_mask 和 product_type。
在 3.6 版更改: 添加了 platform_version
sys.get_asyncgen_hooks
()
返回一个 asyncgen_hooks 对象,该对象类似于 namedtuple
,形式为 (firstiter, finalizer),其中 firstiter 和 finalizer 为 None
或函数,函数以 异步生成器迭代器 作为参数,并用于在事件循环中干预异步生成器的终结。
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_bits 和 seed_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
曾是 0xFFFF
或 0x10FFFF
,具体取决于配置选项,该选项指定将 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
。性能分析函数中的错误将导致其自身被解除设置。
性能分析函数应接收三个参数:frame、event 和 arg。frame 是当前的堆栈帧。event 是一个字符串:'call'
、'return'
、'c_call'
、'c_return'
或 'c_exception'
。arg 取决于事件类型。
引发一个 审计事件 sys.setprofile
,不附带任何参数。
这些事件具有以下含义:
'call'
表示调用了某个函数(或进入了其他的代码块)。性能分析函数将被调用,arg 为
None
。'return'
表示某个函数(或别的代码块)即将返回。性能分析函数将被调用,arg 是即将返回的值,如果此次返回事件是由于抛出异常,arg 为
None
。'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()
。
跟踪函数应接收三个参数:frame、event 和 arg。frame 是当前的堆栈帧。event 是一个字符串:'call'
、'line'
、'return'
、'exception'
或 'opcode'
。arg 取决于事件类型。
每次进入 trace 函数的新的局部作用范围,都会调用 trace 函数( event 会被设置为 'call'
),它应该返回一个引用,指向即将用在新作用范围上的局部跟踪函数;如果不需要跟踪当前的作用范围,则返回 None
。
局部跟踪函数应返回对自身的引用(或对另一个函数的引用,用来在其作用范围内进行进一步的跟踪),或者返回 None
来停止跟踪其作用范围。
如果跟踪函数出错,则该跟踪函数将被取消设置,类似于调用 settrace(None)
。
这些事件具有以下含义:
'call'
表示调用了某个函数(或进入了其他的代码块)。全局跟踪函数将被调用,arg 为
None
。返回值将指定局部跟踪函数。'line'
表示解释器即将执行新一行代码或重新执行循环条件。局部跟踪函数将被调用,arg 为
None
,其返回值将指定新的局部跟踪函数。关于其工作原理的详细说明,请参见Objects/lnotab_notes.txt
。要在该堆栈帧禁用每行触发事件,可以在堆栈帧上将f_trace_lines
设置为False
。'return'
表示某个函数(或别的代码块)即将返回。局部跟踪函数将被调用,arg 是即将返回的值,如果此次返回事件是由于抛出异常,arg 为
None
。跟踪函数的返回值将被忽略。'exception'
表示发生了某个异常。局部跟踪函数将被调用,arg 是一个
(exception, value, traceback)
元组,返回值将指定新的局部跟踪函数。'opcode'
表示解释器即将执行一个新的操作码。局部跟踪函数将被调用,arg 为
None
,其返回值将指定新的局部跟踪函数。每操作码触发事件默认情况下都不发出:必须在堆栈帧上将f_trace_opcodes
显式地设置为True
来请求这些事件。
注意,由于异常是在链式调用中传播的,所以每一级都会产生一个 'exception'
事件。
更细微的用法是,可以显式地通过赋值 frame.f_trace = tracefunc
来设置跟踪函数,而不是用现有跟踪函数的返回值去间接设置它。当前帧上的跟踪函数必须激活,而 settrace()
还没有做这件事。注意,为了使上述设置起效,必须使用 settrace()
来安装全局跟踪函数才能启用运行时跟踪机制,但是它不必与上述是同一个跟踪函数(它可以是一个开销很低的跟踪函数,只返回 None
,即在各个帧上立即将其自身禁用)。
引发一个 审计事件 sys.settrace
,不附带任何参数。
CPython implementation detail: settrace()
函数仅用于实现调试器,性能分析器,打包工具等。它的行为是实现平台的一部分,而不是语言定义的一部分,因此并非在所有 Python 实现中都可用。
在 3.7 版更改: 添加了 'opcode'
事件类型;为帧对象添加了 f_trace_lines
和 f_trace_opcodes
属性
sys.set_asyncgen_hooks
(firstiter, finalizer)
接受两个可选的关键字参数,要求它们是可调用对象,且接受一个 异步生成器迭代器 作为参数。firstiter 对象将在异步生成器第一次迭代时调用。finalizer 将在异步生成器即将被销毁时调用。
引发一个 审计事件 sys.set_asyncgen_hooks_firstiter
,不附带任何参数。
引发一个 审计事件 sys.set_asyncgen_hooks_finalizer
,不附带任何参数。
之所以会引发两个审计事件,是因为底层的 API 由两个调用组成,每个调用都须要引发自己的事件。
3.6 新版功能: 更多详情请参阅 PEP 525,finalizer 方法的参考示例可参阅 Lib/asyncio/base_events.py 中 asyncio.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_encoding
和PyConfig.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__
程序开始时,这些对象存有 stdin
、stderr
和 stdout
的初始值。它们在程序结束前都可以使用,且在需要向实际的标准流打印内容时很有用,无论 sys.std*
对象是否已重定向。
如果实际文件已经被覆盖成一个损坏的对象了,那它也可用于将实际文件还原成能正常工作的文件对象。但是,本过程的最佳方法应该是,在原来的流被替换之前就显式地保存它,并使用这一保存的对象来还原。
注解
某些情况下的 stdin
、stdout
和 stderr
以及初始值 __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_msg 和 object 格式化为: f'{err_msg}: {object!r}'
;如果 err_msg 为 None
则采用 “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, releaselevel 和 serial*。 除 *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:
- the name of the top-level environment of the program, which can be checked using the
__name__ == '__main__'
expression; and - 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 |
bytes 和 bytearray 相关警告的基类。 |
ResourceWarning |
资源利用相关警告的基类。 |
在 3.7 版更改: 以前 DeprecationWarning
和 FutureWarning
是根据某个功能是否完全删除或改变其行为来区分的。现在是根据受众和默认警告过滤器的处理方式来区分的。
警告过滤器
警告过滤器控制着警告是否被忽略、显示或转为错误(触发异常)。
从概念上讲,警告过滤器维护着一个经过排序的过滤器类别列表;任何具体的警告都会依次与列表中的每种过滤器进行匹配,直到找到一个匹配项;过滤器决定了匹配项的处理方式。每个列表项均为 ( 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 必须是个字符串,category 是 Warning
的子类;或者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 是要包含在警告信息中的一行源代码;如果未提供 line,showwarning()
将尝试读取由filename 和 lineno 指定的行。
warnings.formatwarning
(message, category, filename, lineno, line=None)
以标准方式格式化一条警告信息。将返回一个字符串,可能包含内嵌的换行符,并以换行符结束。如果未提供 line*,formatwarning()
将尝试读取由 *filename 和 lineno 指定的行。
warnings.filterwarnings
(action, message=’’, category=Warning, module=’’, lineno=0, append=False)
在 警告过滤器种类 列表中插入一条数据项。默认情况下,该数据项将被插到前面;如果 append 为 True,则会插到后面。这里会检查参数的类型,编译 message 和 module 正则表达式,并将他们作为一个元组插入警告过滤器的列表中。如果两者都与某种警告匹配,那么靠近列表前面的数据项就会覆盖后面的项。省略的参数默认匹配任意值。
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
。 如果 record 为 True
,则返回一个列表,列表由自定义 showwarning()
函数所用对象逐步填充(该函数还会抑制 sys.stdout
的输出)。 列表中每个对象的属性与 showwarning()
的参数名称相同。
module 参数代表一个模块,当导入 warnings
时,将被用于代替返回的模块,其过滤器将被保护。该参数主要是为了测试 warnings
模块自身。
注解
catch_warnings
管理器的工作方式,是替换并随后恢复模块的 showwarning()
函数和内部的过滤器种类列表。这意味着上下文管理器将会修改全局状态,因此不是线程安全的。
dataclasses
—- 数据类
这个模块提供了一个装饰器和一些函数,用于自动添加生成的 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()
装饰器会检查类以查找 field
。 field
被定义为具有 类型标注 的类变量。 除了下面描述的两个例外,在 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
(默认值),则根据eq
和frozen
的设置方式生成__hash__()
方法。__hash__()
由内置的hash()
使用,当对象被添加到散列集合(如字典和集合)时。有一个__hash__()
意味着类的实例是不可变的。可变性是一个复杂的属性,取决于程序员的意图,__eq__()
的存在性和行为,以及dataclass()
装饰器中eq
和frozen
标志的值。默认情况下,
dataclass()
不会隐式添加__hash__()
方法,除非这样做是安全的。 它也不会添加或更改现有的明确定义的__hash__()
方法。 设置类属性__hash__ = None
对 Python 具有特定含义,如__hash__()
文档中所述。如果
__hash__()
没有显式定义,或者它被设为None
,则dataclass()
可能 会添加一个隐式__hash__()
方法。 虽然并不推荐,但你可以用unsafe_hash=True
来强制dataclass()
创建一个__hash__()
方法。 如果你的类在逻辑上不可变但却仍然可被修改那么可能就是这种情况。 这是一个特殊用例并且应当被仔细地考虑。以下是隐式创建
__hash__()
方法的规则。请注意,你不能在数据类中都使用显式的__hash__()
方法并设置unsafe_hash=True
;这将导致TypeError
。如果
eq
和frozen
都是 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 新版功能.
field
s 可以选择使用普通的 Python 语法指定默认值:
@dataclass
class C:
a: int # 'a' has no default value
b: int = 0 # assign a default value for 'b'
在这个例子中, a
和 b
都将包含在添加的 __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
:如果提供,它必须是一个零参数可调用对象,当该字段需要一个默认值时,它将被调用。除了其他目的之外,这可以用于指定具有可变默认值的字段,如下所述。 同时指定default
和default_factory
将产生错误。init
:如果为true(默认值),则该字段作为参数包含在生成的__init__()
方法中。repr
:如果为true(默认值),则该字段包含在生成的__repr__()
方法返回的字符串中。hash
:这可以是布尔值或None
。如果为true,则此字段包含在生成的__hash__()
方法中。如果为None
(默认值),请使用compare
的值,这通常是预期的行为。如果字段用于比较,则应在 hash 中考虑该字段。不鼓励将此值设置为None
以外的任何值。设置
hash=False
但compare=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.x
和 C.y
将不设置。
class dataclasses.Field
Field
对象描述每个定义的字段。这些对象在内部创建,并由 fields()
模块级方法返回(见下文)。用户永远不应该直接实例化 Field
对象。 其有文档的属性是:
name
:字段的名字。type
:字段的类型。default
,default_factory
,init
,repr
,hash
,compare
,metadata
和kw_only
具有与field()
函数中对应参数相同的含义和值。
可能存在其他属性,但它们是私有的,不能被审查或依赖。
dataclasses.fields
(class_or_instance)
返回 Field
对象的元组,用于定义此数据类的字段。 接受数据类或数据类的实例。如果没有传递一个数据类或实例将引发 TypeError
。 不返回 ClassVar
或 InitVar
的伪字段。
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
会被用作 type
。 init
, repr
, eq
, order
, unsafe_hash
, frozen
, match_args
, kw_only
和 slots
等值与它们在 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__()
形参必须以关键字形式来指定。
在这个例子中,字段 y
和 z
将被标记为仅限关键字字段:
@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()
将返回 i
和 j
的 Field
对象,但不包括 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
最后的字段列表依次是 x
、 y
、 z
。 x
的最终类型是 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.x
和 D.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
,dict
或set
的默认形参时将会引发TypeError
。 这是一个部分解决方案,但它确实能防止许多常见错误。使用默认工厂函数是一种创建可变类型新实例的方法,并将其作为字段的默认值:
@dataclass class D: x: list = field(default_factory=list) assert D().x is not D().x
contextlib
—- 为 with
语句上下文提供的工具
此模块为涉及 with
语句的常见任务提供了实用的工具。
工具
提供的函数和类:
class contextlib.AbstractContextManager
一个为实现了 object.__aenter__()
与 object.__aexit__()
的类提供的 abstract base class。 为 object.__aenter__()
提供的一个默认实现是返回 self
而 object.__aexit__()
是一个默认返回 None
的抽象方法。
3.6 新版功能.
class contextlib.AbstractAsyncContextManager
一个为实现了 object.__aenter__()
与 object.__aexit__()
的类提供的 abstract base class。 为 object.__aenter__()
提供的一个默认实现是返回 self
而 object.__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 时重新被引发。 因此,你可以使用 try
…except
…finally
语句来捕获该异常(如果有的话),或确保进行了一些清理。 如果仅出于记录日志或执行某些操作(而非完全抑制异常)的目的捕获了异常,生成器必须重新引发该异常。 否则生成器的上下文管理器将向 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 withasync 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 awith
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
。如果返回True
,subclass 就会被认为是这个抽象基类的子类。如果返回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
, B
和 C
, 那么在解释器终止时会依序执行 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)
打印回溯对象 tb 到 file 的异常信息和整个堆栈回溯。这和 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 bywalk_stack()
orwalk_tb()
).If limit is supplied, only this many frames are taken from frame_gen. If lookup_lines is
False
, the returnedFrameSummary
objects will not have read their lines in yet, making the cost of creating theStackSummary
cheaper (which may be valuable if it may not actually get formatted). If capture_locals isTrue
the local variables in eachFrameSummary
are captured as object representations.classmethod
from_list
(a_list)Construct a
StackSummary
object from a supplied list ofFrameSummary
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
在垃圾回收器开始前和完成后会被调用的一系列回调函数。这些回调函数在被调用时使用两个参数: phase 和 info 。
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 aTypeError
.bind_partial
(\args, *kwargs)Works the same way as
Signature.bind()
, but allows the omission of some required arguments (mimicsfunctools.partial()
behavior.) ReturnsBoundArguments
, or raises aTypeError
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/orreturn_annotation
to override the corresponding properties of the base signature. To remove return_annotatio