47、python3.8的新特性
python3.8的新增功能
本文介绍了与3.7相比,Python 3.8的新功能。有关完整的详细信息,请参见changelog。
Python 3.8已于2019年10月14日发布。
新功能
赋值表达式
有一种新语法:=
可将值赋给变量,作为较大表达式的一部分。由于它与海象的眼睛和象牙很像,因此被亲切地称为“海象操作员” 。
在此示例中,赋值表达式有助于避免调用 len()
两次:
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
在正则表达式匹配期间会产生类似的好处,其中需要两次匹配对象,一次是测试是否发生匹配,另一次是提取子组:
discount = 0.0
if (mo := re.search(r'(\d+)% discount', advertisement)):
discount = float(mo.group(1)) / 100.0
该运算符对while循环也很有用,该循环计算一个值以测试循环终止,然后在循环体中再次需要相同的值:
# Loop over fixed length blocks
while (block := f.read(256)) != '':
process(block)
另一个具有启发性的用例出现在列表理解中,其中表达式主体中还需要在过滤条件下计算出的值:
[clean_name.title() for name in names
if (clean_name := normalize('NFC', name)) in allowed_names]
请尽量将海象运算符的使用限制在清晰的场合中,以降低复杂性并提升可读性。
看到 有关完整说明,请参见PEP 572。
仅限位置形参
新增了一个函数形参语法 /
用来指明某些函数形参必须使用仅限位置而非关键字参数的形式。 这种标记语法与通过 help()
所显示的使用 Larry Hastings 的 Argument Clinic 工具标记的 C 函数相同。
在下面的例子中,形参 a 和 b 为仅限位置形参,c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参:
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
以下均为合法的调用:
f(10, 20, 30, d=40, e=50, f=60)
但是,以下均为不合法的调用:
f(10, b=20, c=30, d=40, e=50, f=60) # b cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60) # e must be a keyword argument
这种标记形式的一个用例是它允许纯 Python 函数完整模拟现有的用 C 代码编写的函数的行为。 例如,内置的 pow()
函数不接受关键字参数:
def pow(x, y, z=None, /):
"Emulate the built in pow() function"
r = x ** y
return r if z is None else r%z
另一个用例是在不需要形参名称时排除关键字参数。 例如,内置的 len()
函数的签名为 len(obj, /)
。 这可以排除如下这种笨拙的调用形式:
len(obj='hello') # The "obj" keyword argument impairs readability
另一个益处是将形参标记为仅限位置形参将允许在未来修改形参名而不会破坏客户的代码。 例如,在 statistics
模块中,形参名 dist 在未来可能被修改。 这使得以下函数描述成为可能:
def quantiles(dist, /, *, n=4, method='exclusive')
...
由于在 /
左侧的形参不会被公开为可用关键字,其他形参名仍可在 **kwargs
中使用:
>>> def f(a, b, /, **kwargs):
... print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3) # a and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}
这极大地简化了需要接受任意关键字参数的函数和方法的实现。 例如,以下是一段摘自 collections
模块的代码:
class Counter(dict):
def __init__(self, iterable=None, /, **kwds):
# Note "iterable" is a possible keyword argument
请参阅 PEP 570 了解详情。
用于已编译字节码文件的并行文件系统缓存
新增的 PYTHONPYCACHEPREFIX
设置 (也可使用 -X
pycache_prefix
) 可将隐式的字节码缓存配置为使用单独的并行文件系统树,而不是默认的每个源代码目录下的 __pycache__
子目录。
缓存的位置会在 sys.pycache_prefix
中报告 (None
表示默认位置即 __pycache__
子目录)。
调试构建使用与发布构建相同的 ABI
Python 现在不论是以发布模式还是调试模式进行构建都将使用相同的 ABI。 在 Unix 上,当 Python 以调试模式构建时,现在将可以加载以发布模式构建的 C 扩展和使用稳定版 ABI 构建的 C 扩展。
发布构建和调试构建现在都是 ABI 兼容的:定义 Py_DEBUG
宏不会再启用 Py_TRACE_REFS
宏,它引入了唯一的 ABI 不兼容性。 Py_TRACE_REFS
宏添加了 sys.getobjects()
函数和 PYTHONDUMPREFS
环境变量,它可以使用新的 ./configure --with-trace-refs
构建选项来设置。 (由 Victor Stinner 在 bpo-36465 中贡献。)
在 Unix 上,C 扩展不会再被链接到 libpython,但 Android 和 Cygwin 例外。 现在静态链接的 Python 将可以加载使用共享库 Python 构建的 C 扩展。 (由 Victor Stinner 在 bpo-21536 中贡献。)
在 Unix 上,当 Python 以调试模式构建时,导入操作现在也会查找在发布模式下编译的 C 扩展以及使用稳定版 ABI 编译的 C 扩展。 (由 Victor Stinner 在 bpo-36722 中贡献。)
要将 Python 嵌入到一个应用中,必须将新增的 --embed
选项传给 python3-config --libs --embed
以获得 -lpython3.8
(将应用链接到 libpython)。 要同时支持 3.8 和旧版本,请先尝试 python3-config --libs --embed
并在此命令失败时回退到 python3-config --libs
(即不带 --embed
)。
增加一个 pkg-config python-3.8-embed
模块用来将 Python 嵌入到一个应用中: pkg-config python-3.8-embed --libs
包含 -lpython3.8
。 要同时支持 3.8 和旧版本,请先尝试 pkg-config python-X.Y-embed --libs
并在此命令失败时回退到 pkg-config python-X.Y --libs
(即不带 --embed
) (请将 X.Y
替换为 Python 版本号)。
另一方面,pkg-config python3.8 --libs
不再包含 -lpython3.8
。 C 扩展不可被链接到 libpython
f-字符串支持 =
用于自动记录表达式和调试文档
增加 =
说明符用于 f-string。 形式为 f'{expr=}'
的 f-字符串将扩展表示为表达式文本,加一个等于号,再加表达式的求值结果。 例如:
>>> user = 'eric_idle'
>>> member_since = date(1975, 7, 31)
>>> f'{user=} {member_since=}'
"user='eric_idle' member_since=datetime.date(1975, 7, 31)"
通常的 f-字符串格式说明符 允许更细致地控制所要显示的表达式结果:
>>> delta = date.today() - member_since
>>> f'{user=!s} {delta.days=:,d}'
'user=eric_idle delta.days=16,075'
=
说明符将输出整个表达式,以便详细演示计算过程:
>>> print(f'{theta=} {cos(radians(theta))=:.3f}')
theta=30 cos(radians(theta))=0.866
新增模块
新增的 importlib.metadata
模块提供了从第三方包读取元数据的(临时)支持。 例如,它可以提取一个已安装软件包的版本号、入口点列表等等:
>>> # Note following example requires that the popular "requests"
>>> # package has been installed.
>>>
>>> from importlib.metadata import version, requires, files
>>> version('requests')
'2.22.0'
>>> list(requires('requests'))
['chardet (<3.1.0,>=3.0.2)']
>>> list(files('requests'))[:5]
[PackagePath('requests-2.22.0.dist-info/INSTALLER'),
PackagePath('requests-2.22.0.dist-info/LICENSE'),
PackagePath('requests-2.22.0.dist-info/METADATA'),
PackagePath('requests-2.22.0.dist-info/RECORD'),
PackagePath('requests-2.22.0.dist-info/WHEEL')]
改进的模块
ast
AST 节点现在具有 end_lineno
和 end_col_offset
属性,它们给出节点结束的精确位置。 (这只适用于具有 lineno
和 col_offset
属性的节点。)
新增函数 ast.get_source_segment()
返回指定 AST 节点的源代码。
ast.parse()
函数具有一些新的旗标:
type_comments=True
导致其返回与特定 AST 节点相关联的 PEP 484 和 PEP 526 类型注释文本;mode='func_type'
可被用于解析 PEP 484 "签名类型注释" (为函数定义 AST 节点而返回);feature_version=(3, N)
允许指定一个更早的 Python 3 版本。 (例如,feature_version=(3, 4)
将把async
和await
视为非保留字。)
asyncio
输入python -m asyncio
将直接发起异步PEPL,这样就不需要让特别紧急的任务处于等待状态,也不需要再输入asyncio.run()
来直接调用
$ python -m asyncio
asyncio REPL 3.8.0
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
>>> await asyncio.sleep(10, result='hello')
hello
在 Windows 上,现在默认的事件循环为 ProactorEventLoop
。ProactorEventLoop
现在也支持 UDP。 ProactorEventLoop
现在可通过 KeyboardInterrupt
("CTRL+C") 来中断。
collections
collections.namedtuple()
的 _asdict()
方法现在将返回 dict
而不是 collections.OrderedDict
。 此项更改是因为普通字典自 Python 3.7 起已保证具有确定的元素顺序。 如果还需要 OrderedDict
的额外特性,推荐的解决方案是将结果转换为需要的类型: OrderedDict(nt._asdict())
。
curses
添加了一个新变量用于保存下层 ncurses 库的结构版信息: ncurses_version
。
datetime
添加了新的替代构造器 datetime.date.fromisocalendar()
和 datetime.datetime.fromisocalendar()
,它们分别基于 ISO 年份、周序号和周内日序号来构造 date
和 datetime
对象;这两者分别是其所对应类中 isocalendar
方法的逆操作。 (由 Paul Ganssle 在 bpo-36004 中贡献。)
functools
functools.lru_cache()
现在可直接作为装饰器而不是作为返回装饰器的函数。 因此这两种写法现在都被支持:
@lru_cache
def f(x):
...
@lru_cache(maxsize=256)
def f(x):
...
添加了一个新的functools.cached_property()装饰器,用于在实例生命期内缓存的计算属性。
import functools
import statistics
class Dataset:
def __init__(self, sequence_of_numbers):
self.data = sequence_of_numbers
@functools.cached_property
def variance(self):
return statistics.variance(self.data)
gc
get_objects()现在可以接收一个可选的生成参数,指示从中获取对象的生成
gettext
添加了 pgettext()
及其变化形式
gzip
添加 mtime 形参到 gzip.compress()
用于可重现的输出。 (由 Guo Ci Teo 在 bpo-34898 中贡献。)
对于特定类型的无效或已损坏 gzip 文件现在将引发 BadGzipFile
而不是 OSError
。
idlelib 与 IDLE
超过 N 行(默认值为 50)的输出将被折叠为一个按钮。 N 可以在 Settings 对话框的 General 页的 PyShell 部分中进行修改。 数量较少但是超长的行可以通过在输出上右击来折叠。 被折叠的输出可通过双击按钮来展开,或是通过右击按钮来放入剪贴板或是单独的窗口。
在 Run 菜单中增加了 "Run Customized" 以使用自定义设置来运行模块。 输入的任何命令行参数都会被加入 sys.argv。 它们在下次自定义运行时会再次显示在窗体中。 用户也可以禁用通常的 Shell 主模块重启。
在 IDLE 编辑器窗口中增加了可选的行序号。 窗口打开时默认不带行序号,除非在配置对话框的 General 选项卡中进行设置。 已打开窗口中的行序号可以在 Options 菜单中显示和隐藏。
上述修改已被反向移植到 3.7 维护发行版中。
inspect
inspect.getdoc()
函数现在可以找到 __slots__
的文档字符串,如果该属性是一个元素值为文档字符串的 dict
的话。 这提供了类似于目前已有的 property()
, classmethod()
和 staticmethod()
等函数的文档选项:
class AudioClip:
__slots__ = {'bit_rate': 'expressed in kilohertz to one decimal place',
'duration': 'in seconds, rounded up to an integer'}
def __init__(self, bit_rate, duration):
self.bit_rate = round(bit_rate / 1000.0, 1)
self.duration = ceil(duration)
io
在开发模式 (-X
env
) 和调试构建中,io.IOBase
终结器现在会在 close()
方法失败时将异常写入日志。 发生的异常在发布构建中默认会被静默忽略。
json.tool
添加选项 --json-lines
用于将每个输入行解析为单独的 JSON 对象。
math
添加了新的函数 math.dist()
用于计算两点之间的欧几里得距离。
扩展了 math.hypot()
函数以便处理更多的维度。 之前它仅支持 2-D 的情况。
添加了新的函数 math.prod()
作为的 sum()
同类,该函数返回 'start' 值 (默认值: 1) 乘以一个数字可迭代对象的积:
>>> prior = 0.8
>>> likelihoods = [0.625, 0.84, 0.30]
>>> math.prod(likelihoods, start=prior)
0.126
添加了新的函数 math.isqrt()
用于计算整数平方根。
函数 math.factorial()
不再接受非整数类参数。
mmap
mmap.mmap
类现在具有一个 madvise()
方法用于访问 madvise()
系统调用。
multiprocessing
新增 multiprocessing.shared_memory
模块.
在macOS上,现在默认使用的启动方式是spawn启动方式。
os
添加了新的 os.memfd_create()
函数用于包装 memfd_create()
系统调用。
在 Windows 上,大部分用于处理重解析点,(包括符号链接和目录连接)的手动逻辑已被委托给操作系统。 特别地,os.stat()
现在将会遍历操作系统所支持的任何内容,而 os.lstat()
将只打开被标识为“名称代理”的重解析点,而其要由 os.stat()
打开其他的重解析点。 在所有情况下,stat_result.st_mode
将只为符号链接而非其他种类的重解析点设置 S_IFLNK
。 要标识其他种类的重解析点,请检查新的 stat_result.st_reparse_tag
属性。
在 Windows 上,os.readlink()
现在能够读取目录连接。 请注意 islink()
会对目录连接返回 False
,因此首先检查 islink
的代码将连续把连接视为目录,而会处理 os.readlink()
所引发错误的代码现在会把连接视为链接。
os.path
返回布尔值结果的 os.path
函数例如 exists()
, lexists()
, isdir()
, isfile()
, islink()
, 以及 ismount()
现在对于包含在 OS 层级无法表示的字符或字节的路径将会返回 False
而不是引发 ValueError
或其子类 UnicodeEncodeError
和 UnicodeDecodeError
。
expanduser()
on Windows now prefers the USERPROFILE
environment variable and does not use HOME
, which is not normally set for regular user accounts.
isdir()
在 Windows 上不再为不存在的目录的链接返回真值。
realpath()
在 Windows 上现在会识别重解析点,包括符号链接和目录连接。
pathlib
返回布尔值结果的 pathlib.Path
方法例如 exists()
, is_dir()
, is_file()
, is_mount()
, is_symlink()
, is_block_device()
, is_char_device()
, is_fifo()
, is_socket()
现在对于包含在 OS 层级无法表示的字符或字节的路径将会返回 False
而不是引发 ValueError
或其子类 UnicodeEncodeError
。
添加了 pathlib.Path.link_to()
用于创建指向某个路径的硬链接。
plistlib
添加了新的 plistlib.UID
并启动了对读取和写入经过 NSKeyedArchiver 编码的二进制 plists 的支持
py_compile
py_compile.compile()
现在支持静默模式。
shlex
新增了 shlex.join()
函数作为 shlex.split()
的逆操作。
shutil
shutil.copytree()
现在接受新的 dirs_exist_ok
关键字参数。
shutil.make_archive()
现在对新的归档默认使用 modern pax (POSIX.1-2001) 格式以提升可移植性和标准一致性,此特性继承自对 tarfile
模块的相应更改。
shutil.rmtree()
on Windows now removes directory junctions without recursively removing their contents first.
socket
添加了便捷的 create_server()
和 has_dualstack_ipv6()
函数以自动化在创建服务器套接字时通常情况下所必须的任务,包括在同一套接字中同时接受 IPv4 和 IPv6 连接。
socket.if_nameindex()
, socket.if_nametoindex()
和 socket.if_indextoname()
函数已经在 Windows 上实现。
ssl
增加了 ssl.SSLContext.post_handshake_auth
以及 ssl.SSLSocket.verify_client_post_handshake()
来启用并初始化 TLS 1.3 握手后验证。
statistics
添加了 statistics.fmean()
作为 statistics.mean()
的更快速的浮点数版版本。
添加了 statistics.geometric_mean()
添加了 statistics.multimode()
用于返回最常见值的列表。
添加了 statistics.quantiles()
用于将数据或分布划分为多个等概率区间
添加了 statistics.NormalDist
用于创建和操纵随机变量的正态分布。
>>> temperature_feb = NormalDist.from_samples([4, 12, -3, 2, 7, 14])
>>> temperature_feb.mean
6.0
>>> temperature_feb.stdev
6.356099432828281
>>> temperature_feb.cdf(3) # Chance of being under 3 degrees
0.3184678262814532
>>> # Relative chance of being 7 degrees versus 10 degrees
>>> temperature_feb.pdf(7) / temperature_feb.pdf(10)
1.2039930378537762
>>> el_niño = NormalDist(4, 2.5)
>>> temperature_feb += el_niño # Add in a climate effect
>>> temperature_feb
NormalDist(mu=10.0, sigma=6.830080526611674)
>>> temperature_feb * (9/5) + 32 # Convert to Fahrenheit
NormalDist(mu=50.0, sigma=12.294144947901014)
>>> temperature_feb.samples(3) # Generate random samples
[7.672102882379219, 12.000027119750287, 4.647488369766392]
sys
添加了新的 sys.unraisablehook()
函数,可被重载以便控制如何处理“不可引发的异常”。 它会在发生了一个异常但 Python 没有办法处理时被调用。 例如,当一个析构器在垃圾回收时 (gc.collect()
) 所引发的异常。
tarfile
tarfile
模块现在对新的归档默认使用 modern pax (POSIX.1-2001) 格式而不再是之前的 GNU 专属格式。 这通过标准化和可扩展格式的统一编码 (UTF-8) 提升了跨平台可移植性,还提供了其他一些益处。
threading
添加了新的 threading.excepthook()
函数用来处理未捕获的 threading.Thread.run()
异常。 它可被重载以便控制如何处理未捕获的 threading.Thread.run()
异常。
添加了新的 threading.get_native_id()
函数以及 threading.Thread
类的 native_id
属性。 它们会返回内核所分配给当前线程的原生整数线程 ID。 此特性仅在特定平台上可用,参见 get_native_id
了解详情。
tokenize
当提供不带末尾新行的输入时,tokenize
模块现在会隐式地添加 NEWLINE
形符。 此行为现在已与 C 词法分析器的内部行为相匹配。
tkinter
在 tkinter.Spinbox
中添加了方法 selection_from()
, selection_present()
, selection_range()
和 selection_to()
。
在 tkinter.Canvas
类中添加了方法 moveto()
。
tkinter.PhotoImage
类现在具有 transparency_get()
和 transparency_set()
方法。
time
为 macOS 10.12 添加了新的时钟 CLOCK_UPTIME_RAW
。
typing
typing
模块加入了一些新特性:
-
一个带有键专属类型的字典类型。 参见 PEP 589 和
typing.TypedDict
。 TypedDict 只使用字符串作为键。 默认情况下每个键都要求提供。 指定 "total=False" 以允许键作为可选项:class Location(TypedDict, total=False): lat_long: tuple grid_square: str xy_coordinate: tuple
-
Literal 类型。 参见 PEP 586 和
typing.Literal
。 Literal 类型指明一个形参或返回值被限定为一个或多个特定的字面值:def get_status(port: int) -> Literal['connected', 'disconnected']: ...
-
"Final" 变量、函数、方法和类。 参见 PEP 591,
typing.Final
和typing.final()
。 final 限定符会指示静态类型检查器限制进行子类化、重载或重新赋值:pi: Final[float] = 3.1415926536
-
协议定义。 参见 PEP 544,
typing.Protocol
和typing.runtime_checkable()
。 简单的 ABC 例如typing.SupportsInt
现在是Protocol
的子类。 -
新的协议类
typing.SupportsIndex
。 -
新的函数
typing.get_origin()
和typing.get_args()
。
unicodedata
unicodedata
模块现在已升级为使用 Unicode 12.1.0 发布版。
新的函数 is_normalized()
可被用来验证字符串是否为特定正规形式,通常会比实际进行字符串正规化要快得多。
unittest
添加了 AsyncMock
以支持异步版本的 Mock
。 同时也添加了相应的断言函数用于测试。
unittest 添加了 addModuleCleanup()
和 addClassCleanup()
以支持对 setUpModule()
和 setUpClass()
进行清理。
一些模拟断言函数现在也会在失败时打印一个实际调用列表。
unittest
模块已支持通过 unittest.IsolatedAsyncioTestCase
来使用协程作为测试用例。
import unittest
class TestRequest(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
self.connection = await AsyncConnection()
async def test_get(self):
response = await self.connection.get("https://example.com")
self.assertEqual(response.status_code, 200)
async def asyncTearDown(self):
await self.connection.close()
if __name__ == "__main__":
unittest.main()
venv
现在 venv
在所有平台上都会包含 Activate.ps1
脚本用于在 PowerShell Core 6.1 下激活虚拟环境。
weakref
由 weakref.proxy()
返回的代理对象现在除其他算术运算符外也支持矩阵乘法运算符 @
和 @=
。
xml
作为对 DTD 和外部实体检索的缓解,在默认情况下 xml.dom.minidom
和 xml.sax
模块不再处理外部实体。
xml.etree.ElementTree
模块中的 .find*()
方法支持通配符搜索例如 {*}tag
,此搜索会忽略命名空间以及返回给定命名空间中所有标签的 {namespace}*
。
xml.etree.ElementTree
模块提供了实现 C14N 2.0 的新函数 –xml.etree.ElementTree.canonicalize()
。
xml.etree.ElementTree.XMLParser
的目标对象可通过新的回调方法 start_ns()
和 end_ns()
来接受命名空间声明事件。 此外,xml.etree.ElementTree.TreeBuilder
目标可被配置为处理有关注释和处理指令事件以将它们包含在所生成的树当中。
性能优化
-
subprocess
模块现在能在某些情况下使用os.posix_spawn()
函数以获得更好的性能。 目前,它的使用仅限 macOS 和 Linux(使用 glibc 2.24 或更新版本),并要求满足以下条件:- close_fds 为假值;
- preexec_fn, pass_fds, cwd 和 start_new_session 形参未设置;
- executable 路径包含一个目录。
(由 Joannah Nanjekye 和 Victor Stinner 在 bpo-35537 中贡献。)
-
shutil.copyfile()
,shutil.copy()
,shutil.copy2()
,shutil.copytree()
和shutil.move()
在 Linux 和 macOS 上会使用平台专属的 "fast-copy" 系统调用以提高效率。 "fast-copy" 意味着拷贝操作发生于内核中,从而避免在进行 "outfd.write(infd.read())
" 等操作时使用 Python 中的用户空间缓冲区。 在 Windows 上shutil.copyfile()
会使用更大的默认缓冲区(1 MiB 而不是 16 KiB)并且使用基于memoryview()
的shutil.copyfileobj()
版本。 在同一分区内拷贝一个 512 MiB 文件的速度提升在 Linux 上约为 +26%,在 macOS 上为 +50%,在 Windows 上为 +40%。 此外还将消耗更少的 CPU 周期。 参见 Platform-dependent efficient copy operations 一节。 (由 Giampaolo Rodolà 在 bpo-33671 中贡献。) -
shutil.copytree()
会根据其所用缓存的os.stat()
值使用os.scandir()
函数及所有拷贝函数。 拷贝一个包含 8000 文件的目录的速度提升在 Linux 上约为 +9%,在 Windows 上为 +20%,对于 Windows SMB 共享目录则为 +30%。 此外os.stat()
系统调用的次数也减少了 38%,使得shutil.copytree()
在网络文件系统上会特别快速。 (由Giampaolo Rodolà 在 bpo-33695 中贡献。) -
pickle
模块使用的默认协议现在为 Protocol 4,最早在 Python 3.4 中被引入。 它提供了比自 Python 3.0 起可用的 Protocol 3 更好的性能和更小的数据尺寸。 -
Removed one
Py_ssize_t
member fromPyGC_Head
. All GC tracked objects (e.g. tuple, list, dict) size is reduced 4 or 8 bytes. (Contributed by Inada Naoki in bpo-33597.) -
uuid.UUID
now uses__slots__
to reduce its memory footprint. (Contributed by Wouter Bolsterlee and Tal Einat in bpo-30977) -
operator.itemgetter()
的性能提升了 33%。 优化了参数处理,并为常见的在元组中单个非负整数索引的情况新增了一条快速路径(这是标准库中的典型用例)。 (由 Raymond Hettinger 在 bpo-35664 中贡献。 -
加快了在
collections.namedtuple()
中的字段查找。 它们现在的速度快了两倍以上,成为 Python 中最快的实例变量查找形式。 (由 Raymond Hettinger, Pablo Galindo 和 Joe Jevnik, Serhiy Storchaka 在 bpo-32492 中贡献。) -
如果输入的可迭代对象的长度已知 (即输入对象实现了
__len__
),list
构造器不会过度分配内部项缓冲区。 这使得所创建的列表资源占用平均减少了 12%。 (由 Raymond Hettinger 和 Pablo Galindo 在 bpo-33234 中贡献。) -
类变量写入速度加倍。 当一个非冗余属性被更新时,之前存在一个更新 slots 的非必要调用。 (由 Stefan Behnel, Pablo Galindo Salgado, Raymond Hettinger, Neil Schemenauer, 和 Serhiy Storchaka 在 bpo-36012 中贡献。)
-
减少了传递给许多内置函数和方法的参数转换的开销。 这使得某些简单内置函数和方法的速度提升了 20--50%。 (由 Serhiy Storchaka 在 bpo-23867, bpo-35582 和 bpo-36127 中贡献。)
-
LOAD_GLOBAL
指令现在会使用新的 "per opcode cache" 机制。 它的速度现在提升了大约 40%。 (由 Yury Selivanov 和 Inada Naoki 在 bpo-26219 中贡献。)
构建和 C API 的改变
-
默认的
sys.abiflags
成为一个空字符串:pymalloc 的m
旗标不再有意义(无论是否启用 pymalloc 构建都是兼容 ABI 的)因此已被移除。 (由 Victor Stinner 在 bpo-36707 中贡献。)改变的例子:
- 只会安装
python3.8
程序,不再有python3.8m
程序。 - 只会安装
python3.8-config
脚本,不再有python3.8m-config
脚本。 m
旗标已经从动态库文件名后缀中移除:包括标准库中的扩展模块以及第三方包所产生和安装的模块例如从 PyPI 下载的模块。 以 Linux 为例,Python 3.7 的后缀.cpython-37m-x86_64-linux-gnu.so
在 Python 3.8 中改为.cpython-38-x86_64-linux-gnu.so
。
- 只会安装
-
重新组织了所有头文件以更好地区分不同种类的 API:
Include/*.h
应为可移植的公有稳定版 C API。Include/cpython/*.h
应为 CPython 专属的不稳定版 C API;公有 API,部分私有 API 附加_Py
or_PY
前缀。Include/internal/*.h
应为 CPython 特别专属的私有内部 C API。 此 API 不具备向下兼容保证并且不应在 CPython 以外被使用。 它们的公开仅适用于特别限定的需求例如调试器和性能分析等必须直接访问 CPython 内部数据而不通过调用函数的应用。 此 API 现在是通过make install
安装的。
(由 Victor Stinner 在 bpo-35134 和 bpo-35081 中贡献,相关工作由 Eric Snow 在 Python 3.7 中发起。)
-
某些宏已被转换为静态内联函数:形参类型和返回类型定义良好,它们不再会有与宏相关的问题,变量具有局部作用域。 例如:
Py_INCREF()
,Py_DECREF()
Py_XINCREF()
,Py_XDECREF()
PyObject_INIT()
,PyObject_INIT_VAR()
- 私有函数:
_PyObject_GC_TRACK()
,_PyObject_GC_UNTRACK()
,_Py_Dealloc()
(由 Victor Stinner 在 bpo-35059 中贡献。)
-
PyByteArray_Init()
和PyByteArray_Fini()
函数已被移除。 它们自 Python 2.7.4 和 Python 3.2.0 起就没有任何用处,被排除在受限 API (稳定版 ABI) 之外,并且未被写入文档。 (由 Victor Stinner 在 bpo-35713 中贡献。) -
PyExceptionClass_Name()
的结果类型现在是const char *
而非char *
。 (由 Serhiy Storchaka 在 bpo-33818 中贡献。) -
Modules/Setup.dist
与Modules/Setup
两者的共存已被移除。 之前在更新 CPython 源码树时,开发者必须手动拷贝Modules/Setup.dist
(在源码树内) 到Modules/Setup
(在构建树内) 以反映上游的任何改变。 旧特性对打包者来说有一点益处,但代价是对追踪 CPython 开发进程的开发者造成经常性的麻烦,因为忘记拷贝该文件可能导致构建失败。现在构建系统总是会从源码树内的
Modules/Setup
读取数据。 建议希望定制该文件的开发者在 CPython 的一个 git 分叉或补丁文件中维护他们的更改,就如他们对源码树做任何其他改变时一样。(由 Antoine Pitrou 在 bpo-32430 中贡献。)
-
将 Python 数字转换为 C 整型的函数例如
PyLong_AsLong()
以及带有'i'
之类整型转换格式单元的参数解析函数例如PyArg_ParseTuple()
现在如果可能将会使用__index__()
特殊方法而不是__int__()
。 对于带有__int__()
方法但没有__index__()
方法的对象 (例如Decimal
和Fraction
) 将会发出弃用警告。 对于实现了__index__()
的对象PyNumber_Check()
现在将返回1
。PyNumber_Long()
,PyNumber_Float()
和PyFloat_AsDouble()
现在如果可能也将会使用__index__()
方法。 (由 Serhiy Storchaka 在 bpo-36048 和 bpo-20092 中贡献。) -
堆分配类型对象现在将增加它们在
PyObject_Init()
(及其对应的宏PyObject_INIT
) 中的引用计数而不是在PyType_GenericAlloc()
中。 修改实例分配或中止分配的类型可能需要进行调整。 (由 Elizondo 在 bpo-35810 中贡献。) -
新增函数
PyCode_NewWithPosOnlyArgs()
允许创建代码对象例如PyCode_New()
,但带有一个额外的 posonlyargcount 形参以指明仅限位置参数的数量。 (由 Pablo Galindo 在 bpo-37221 中贡献。) -
Py_SetPath()
现在会将sys.executable
设为程序完整路径 (Py_GetProgramFullPath()
) 而不是程序名称 (Py_GetProgramName()
)。 (由 Victor Stinner 在 bpo-38234 中贡献。)
弃用
-
distutils 的
bdist_wininst
命令现在已弃用,请改用bdist_wheel
(wheel 包)。 (由 Victor Stinner 在 bpo-37481 中贡献。) -
ElementTree
模块中的已弃用方法getchildren()
和getiterator()
现在会引发DeprecationWarning
而不是PendingDeprecationWarning
。 它们将在 Python 3.9 中被移除。 (由 Serhiy Storchaka 在 bpo-29209 中贡献。) -
将不是
concurrent.futures.ThreadPoolExecutor
实例的对象传给asyncio.loop.set_default_executor()
已被弃用,并将在 Python 3.9 中被禁止。 (由 Elvis Pranskevichus 在 bpo-34075 中贡献。) -
xml.dom.pulldom.DOMEventStream
,wsgiref.util.FileWrapper
和fileinput.FileInput
的__getitem__()
方法已被弃用。这些方法的实现会忽略它们的 index 形参,并改为返回下一条目。 (由 Berker Peksag 在 bpo-9372 中贡献。)
-
typing.NamedTuple
类已弃用了_field_types
属性而改用具有同样信息的__annotations__
属性。 (由 Raymond Hettinger 在 bpo-36320 中贡献。) -
ast
类Num
,Str
,Bytes
,NameConstant
和Ellipsis
被视为已弃用并将在未来的 Python 版本中被移除。 应当改用Constant
。 (由 Serhiy Storchaka 在 bpo-32892 中贡献。) -
ast.NodeVisitor
的方法visit_Num()
,visit_Str()
,visit_Bytes()
,visit_NameConstant()
和visit_Ellipsis()
现在已被弃用,并且在未来的 Python 版本中将不再被调用。 添加visit_Constant()
方法来处理所有常量节点。 (由 Serhiy Storchaka 在 bpo-36917 中贡献。) -
gettext
模块中的下列函数和方法已被弃用:lgettext()
,ldgettext()
,lngettext()
和ldngettext()
。 它们返回已编码的字节串,如果转换后的字符串存在编码问题你将可能遭遇预期之外的异常。 更好的做法是使用 Python 3 中返回 Unicode 字符串的操作作为替代。 前面的函数都早已不宜使用。函数
bind_textdomain_codeset()
,方法output_charset()
和set_output_charset()
,以及函数translation()
和install()
的 codeset 形参也忆被弃用,因为它们仅适用于l*gettext()
函数。 (由 Serhiy Storchaka 在 bpo-33710 中贡献。) -
threading.Thread
的isAlive()
方法已弃用。 (由 Dong-hee Na 在 bpo-35283 中贡献。) -
许多接受整数参数的内置和扩展模块的函数现在将对传入
Decimal
,Fraction
以及任何其他可被转换为整数但会丢失精度(即具有__int__()
方法但没有__index__()
方法)的对象发出弃用警告。 在未来的版本中则将报错。 (由 Serhiy Storchaka 在 bpo-36048 中贡献。) -
以下参数作为关键字参数传递的方式已被弃用:
functools.partialmethod()
,weakref.finalize()
,profile.Profile.runcall()
,cProfile.Profile.runcall()
,bdb.Bdb.runcall()
,trace.Trace.runfunc()
与curses.wrapper()
中的 func。unittest.TestCase.addCleanup()
中的 function。concurrent.futures.ThreadPoolExecutor
和concurrent.futures.ProcessPoolExecutor
的submit()
方法中的 fn。contextlib.ExitStack.callback()
,contextlib.AsyncExitStack.callback()
和contextlib.AsyncExitStack.push_async_callback()
中的 callback。multiprocessing.managers.Server
和multiprocessing.managers.SharedMemoryServer
的create()
方法中的 c 和 typeid。weakref.finalize()
中的 obj。
在未来版本的 Python 中它们将成为 仅限位置参数。 (由 Serhiy Storchaka 在 bpo-36492 中贡献。)
API 与特性的移除
下列特性与 API 已从 Python 3.8 中移除:
macpath
模块,在 Python 3.7 中弃用,现已被移除。- 函数
platform.popen()
已被移除,它自 Python 3.3 起就已被弃用:请改用os.popen()
。 - 函数
time.clock()
已被移除,它自 Python 3.3 起就已被弃用:请根据具体需求改用time.perf_counter()
或time.process_time()
以获得具有良好定义的行为。 pyvenv
脚本已被移除,推荐改用python3.8 -m venv
来帮助消除容易混淆pyvenv
脚本所关联的 Python 解释器这一问题。parse_qs
,parse_qsl
和escape
已从cgi
模块中被移除。 这些函数自 Python 3.2 或更早就已被弃用。 它们应改为从urllib.parse
和html
模块导入。filemode
函数已从tarfile
模块中被移除。 该函数未被写入文档,自 Python 3.3 起就已弃用。XMLParser
构造器不再接受 html 参数。 它从来没有任何作用并在 Python 3.4 中已被弃用。 所有其他形参现在都是 仅限关键字参数。XMLParser
的doctype()
方法已被移除。- "unicode_internal" 编解码器已被移除。
sqlite3
模块的Cache
和Statement
对象已不再公开给用户。fileinput.input()
和fileinput.FileInput()
中自 Python 3.6 起就已被忽略并弃用的bufsize
关键字参数已被移除。- 在 Python 3.7 中弃用的函数
sys.set_coroutine_wrapper()
和sys.get_coroutine_wrapper()
已被移除。
移植到 Python 3.8
本节列出了先前描述的更改以及可能需要更改代码的其他错误修正.
Python 行为的改变
- yield 表达式(包括
yield
和yield from
子句)现在不允许在推导式和生成器表达式中使用(但for
子句最左边的可迭代对象表达式除外)。 (由 Serhiy Storchaka 在 bpo-10544 中贡献。) - The compiler now produces a
SyntaxWarning
when identity checks (is
andis not
) are used with certain types of literals (e.g. strings, numbers). These can often work by accident in CPython, but are not guaranteed by the language spec. The warning advises users to use equality tests (==
and!=
) instead. (Contributed by Serhiy Storchaka in bpo-34850.) - CPython 解释器在某些情况下可以忽略异常。 在 Python 3.8 中这种情况会更少发生。 特别地,从类型字典获取属性时引发的异常不会再被忽略。 (由 Serhiy Storchaka 在 bpo-35459 中贡献。)
- 从内置类型
bool
,int
,float
,complex
和标准库的一些类中移除了__str__
实现。 它们现在会从object
继承__str__()
。 作为结果,在这些类的子类中定义__repr__()
方法将会影响它们的字符串表示。 (由 Serhiy Storchaka 在 bpo-36793 中贡献。) - 在 AIX 上,
sys.platform
将不再包含主要版本号。 它将总是'aix'
而不再是'aix3'
..'aix7'
。 由于较旧的 Python 版本会包含该版本号,因此推荐总是使用sys.platform.startswith('aix')
。 (由 M. Felt 在 bpo-36588 中贡献。) PyEval_AcquireLock()
andPyEval_AcquireThread()
now terminate the current thread if called while the interpreter is finalizing, making them consistent withPyEval_RestoreThread()
,Py_END_ALLOW_THREADS()
, andPyGILState_Ensure()
. If this behavior is not desired, guard the call by checking_Py_IsFinalizing()
orsys.is_finalizing()
. (Contributed by Joannah Nanjekye in bpo-36475.)
更改的Python API
- 在 Windows 上
os.getcwdb()
函数现在会使用 UTF-8 编码格式而不是 ANSI 代码页:请参看 PEP 529 了解具体原因。 该函数在 Windows 上不再被弃用。 (由 Victor Stinner 在 bpo-37412 中贡献。) - 现在
subprocess.Popen
在某些情况下会使用os.posix_spawn()
以获得更好的性能。 在适用于 Linux 的 Windows 子系统和 QEMU 用户模拟器上,使用os.posix_spawn()
的Popen
构造器不会再因为“找不到程序”这样的错误引发异常。 而是让子进程失败并返回一个非零的returncode
。 (由 Joannah Nanjekye 和 Victor Stinner 在 bpo-35537 中贡献。) - The preexec_fn argument of *
subprocess.Popen
is no longer compatible with subinterpreters. The use of the parameter in a subinterpreter now raisesRuntimeError
. (Contributed by Eric Snow in bpo-34651, modified by Christian Heimes in bpo-37951.) - The
imap.IMAP4.logout()
method no longer ignores silently arbitrary exceptions. (Contributed by Victor Stinner in bpo-36348.) - 函数
platform.popen()
已被移除,它自 Python 3.3 起就已被弃用:请改用os.popen()
。 (由 Victor Stinner 在 bpo-35345 中贡献。) - 当传入多模数据时
statistics.mode()
函数不会再引发异常。 它将改为返回在输入数据中遇到的第一个模式。 (由 Raymond Hettinger 在 bpo-35892 中贡献。) tkinter.ttk.Treeview
类的selection()
方法不再接受参数。 带参数调用该方法来改变选择在 Python 3.6 中已弃用。 请使用专门方法例如selection_set()
来改变选择。 (由 Serhiy Storchaka 在 bpo-31508 中贡献。)xml.dom.minidom
的writexml()
,toxml()
和toprettyxml()
方法以及xml.etree
的write()
方法现在会保留用户指定的属性顺序。 (由 Diego Rojas 和 Raymond Hettinger 在 bpo-34160 中贡献。)- 附带
'r'
旗标打开的dbm.dumb
数据库现在将是只读的。 如果数据库不存在,附带'r'
和'w'
旗标的dbm.dumb.open()
不会再创建数据库。 (由 Serhiy Storchaka 在 bpo-32749 中贡献。) - 在
XMLParser
的子类中定义的doctype()
方法将不会再被调用,并将导致发出RuntimeWarning
而不是DeprecationWarning
。 请在目标上定义doctype()
方法来处理 XML doctype 声明。 (由 Serhiy Storchaka 在 bpo-29209 中贡献。) - 现在当自定义元类未在传给
type.__new__
的命名空间中提供__classcell__
入口时将引发RuntimeError
。 在 Python 3.6--3.7 中是则是引发DeprecationWarning
。 (由 Serhiy Storchaka 在 bpo-23722 中贡献。) cProfile.Profile
类现在可被用作上下文管理器。 (由 Scott Sanderson 在 bpo-29235 中贡献。)shutil.copyfile()
,shutil.copy()
,shutil.copy2()
,shutil.copytree()
和shutil.move()
会使用平台专属的 "fast-copy" 系统调用(参见 Platform-dependent efficient copy operations 一节)。shutil.copyfile()
在 Windows 上的默认缓冲区大小从 16 KiB 改为 1 MiB。PyGC_Head
结构已被完全改变。 所有接触到该结构的代码都应当被重写。 (参见 bpo-33597。)PyInterpreterState
结构已被移入 "internal" 头文件 (特别是 Include/internal/pycore_pystate.h)。 不透明的PyInterpreterState
作为公有 API (和稳定版 ABI) 的一部分仍然可用。 文档指明该结构的任何字段都不是公有的,因此我们希望没人在使用它们。 但是,如果你确实依赖其中某一个或更多个私有字段并且没有其他替代选项,则请开一个 BPO 问题。 我们将尽力帮助你进行调整 (可能包括向公有 API 添加访问器函数)。 (参见 bpo-35886。)- 现在 asyncio 任务可以被命名,具体方式是将
name
关键字参数传给asyncio.create_task()
或create_task()
事件循环方法,或是在任务对象上调用set_name()
方法。 任务名称可在asyncio.Task
的repr()
输出中查看,并可使用get_name()
方法来获取。 - 现在所有平台下的
mmap.flush()
方法都会在成功时返回None
并在错误时引发异常。 之前它的行为取决于具体平台: Windows 下会在成功时返回非零值;在失败时返回零。 Unix 下会在成功时返回零;在失败时引发错误。 (由 Berker Peksag 在 bpo-2122 中贡献。) xml.dom.minidom
和xml.sax
模块默认将不再处理外部实体。 (由 Christian Heimes 在 bpo-17239 中贡献。)- 从只读的
dbm
数据库 (dbm.dumb
,dbm.gnu
或dbm.ndbm
) 删除键将会引发error
(dbm.dumb.error
,dbm.gnu.error
或dbm.ndbm.error
) 而不是KeyError
。 (由 Xiang Zhang 在 bpo-33106 中贡献。) expanduser()
on Windows now prefers theUSERPROFILE
environment variable and does not useHOME
, which is not normally set for regular user accounts. (Contributed by Anthony Sottile in bpo-36264.)- The exception
asyncio.CancelledError
now inherits fromBaseException
rather than aException
. (Contributed by Yury Selivanov in bpo-13528.) - DLL dependencies for extension modules and DLLs loaded with
ctypes
on Windows are now resolved more securely. Only the system paths, the directory containing the DLL or PYD file, and directories added withadd_dll_directory()
are searched for load-time dependencies. Specifically,PATH
and the current working directory are no longer used, and modifications to these will no longer have any effect on normal DLL resolution. If your application relies on these mechanisms, you should check foradd_dll_directory()
and if it exists, use it to add your DLLs directory while loading your library. Note that Windows 7 users will need to ensure that Windows Update KB2533625 has been installed (this is also verified by the installer). (Contributed by Steve Dower in bpo-36085.) - 关联到 pgen 的头文件和函数在其被纯 Python 实现取代后已被移除。 (由 Pablo Galindo 在 bpo-36623 中贡献。)
types.CodeType
在构造器的第二个位置新增了一个形参 (posonlyargcount) 以支持在 PEP 570 中定义的仅限位置参数。 第一个参数 (argcount) 现在表示位置参数的总数量 (包括仅限位置参数)。types.CodeType
中新增的replace()
方法可用于让代码支持 future 特性。
C API 中的改变
-
The
PyCompilerFlags
structure got a new cf_feature_version field. It should be initialized toPY_MINOR_VERSION
. The field is ignored by default, and is used if and only ifPyCF_ONLY_AST
flag is set in cf_flags. (Contributed by Guido van Rossum in bpo-35766.) -
PyEval_ReInitThreads()
函数已从 C API 中移除。 它不应当被显式地调用;请改用PyOS_AfterFork_Child()
。 (由 Victor Stinner 在 bpo-36728 中贡献。) -
在 Unix 上,C 扩展不会再被链接到 libpython,但 Android 和 Cygwin 例外。 当 Python 被嵌入时,
libpython
不可使用RTLD_LOCAL
加载,而要改用RTLD_GLOBAL
。 之前使用RTLD_LOCAL
已经不可能加载未链接到libpython
的 C 扩展了,例如通过Modules/Setup
的*shared*
部分构建的标准库 C 扩展。 (由 Victor Stinner 在 bpo-21536 中贡献。) -
在解析或构建值时(例如
PyArg_ParseTuple()
,Py_BuildValue()
,PyObject_CallFunction()
等等)使用形如#
的格式而不定义PY_SSIZE_T_CLEAN
现在将会引发DeprecationWarning
。 它将在 3.10 或 4.0 中被移除。 请参阅 语句解释及变量编译 了解详情。 (由 Inada Naoki 在 bpo-36381 中贡献。) -
堆分配类型的实例(例如使用
PyType_FromSpec()
创建的实例)会保存一个对其类型对象的引用。 提升这些类型对象引用计数的操作已从PyType_GenericAlloc()
移至更低层级的函数PyObject_Init()
和PyObject_INIT()
。 这使用通过This makes types created throughPyType_FromSpec()
所创建类型的行为与管理代码中的其他类保持一致。静态分配类型将不受影响。
在大部分情况下,这应该都不会有附带影响。 但是,在分配实例后手动提升引用计数的类型(也许是为了绕过漏洞)现在可能永远不会被销毁。 要避免这种情况,这些类需要在实例撤销分配期间在类型对象上调用 Py_DECREF。
要正确地将这些类型移植到 3.8,请应用以下修改:
-
在分配实例之后在类型对象上移除
Py_INCREF
—— 如果有的话。 这可以发生在调用PyObject_New()
,PyObject_NewVar()
,PyObject_GC_New()
,PyObject_GC_NewVar()
或任何其他使用PyObject_Init()
或PyObject_INIT()
的自定义分配器之后。示例:
static foo_struct * foo_new(PyObject *type) { foo_struct *foo = PyObject_GC_New(foo_struct, (PyTypeObject *) type); if (foo == NULL) return NULL; #if PY_VERSION_HEX < 0x03080000 // Workaround for Python issue 35810; no longer necessary in Python 3.8 PY_INCREF(type) #endif return foo; }
确保所有堆分配类型的自定义
tp_dealloc
函数会减少类型的引用计数。static void foo_dealloc(foo_struct *instance) { PyObject *type = Py_TYPE(instance); PyObject_GC_Del(instance); #if PY_VERSION_HEX >= 0x03080000 // This was not needed before Python 3.8 (Python issue 35810) Py_DECREF(type); #endif }
-
-
Py_DEPRECATED()
宏已经针对 MSVC 实现。 这个宏现在必须放在符号名称之前。示例:
Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);
-
解释器将不再假装支持跨发布版本的扩展类型二进制兼容性。 由第三方扩展模块所导出的
PyTypeObject
应该具有当前 Python 版本所要求的所有空位,包括tp_finalize
(Py_TPFLAGS_HAVE_FINALIZE
不会再在读取tp_finalize
之前被检查)。(由 Antoine Pitrou 在 bpo-32388 中贡献。)
-
PyCode_New()
在第二个位置添加了新的形参 (posonlyargcount) 以支持 PEP 570,指明仅限位置参数的数量。 -
函数
PyNode_AddChild()
和PyParser_AddToken()
现在接受两个额外的int
参数 end_lineno 和 end_col_offset。 -
The
libpython38.a
file to allow MinGW tools to link directly againstpython38.dll
is no longer included in the regular Windows distribution. If you require this file, it may be generated with thegendef
anddlltool
tools, which are part of the MinGW binutils package:gendef python38.dll > tmp.def dlltool --dllname python38.dll --def tmp.def --output-lib libpython38.a
已安装的
pythonXY.dll
所在位置将取决于安装选项以及 Windows 的版本和语言。 请参阅 在Windows上使用 Python 了解更多信息。 该结果库应当放在与pythonXY.lib
相同的目录下,这通常是你的 Python 安装路径下的libs
目录。
CPython 字节码的改变
-
解释器循环已通过将块堆栈展开逻辑移入编译器获得了简化。 编译器现在会发出显式指令来调整值堆栈并为
break
,continue
和return
调用清除代码。移除了操作码
BREAK_LOOP
,CONTINUE_LOOP
,SETUP_LOOP
和SETUP_EXCEPT
。 添加了新的操作码ROT_FOUR
,BEGIN_FINALLY
,CALL_FINALLY
和POP_FINALLY
。 修改了END_FINALLY
和WITH_CLEANUP_START
的行为。 -
添加了新的操作码
END_ASYNC_FOR
用于处理当等待async for
循环的下一项时引发的异常。 -
MAP_ADD
现在会预期值为栈的第一个元素而键为第二个元素。 作出此改变以使得字典推导式能如 PEP 572 所提议的那样,键总是会在值之前被求值。
演示和工具
- 添加了一个检测脚本用于对访问变量的不同方式进行计时:
Tools/scripts/var_access_benchmark.py
。