Python 3.8 的新增Function

  • Editor

    • Raymond Hettinger

本文介绍了与 3.7 相比,Python 3.8 的新Function。有关详细信息,请参见changelog

Python 3.8 已于 2019 年 10 月 14 日发布。

摘要-发布要点

New Features

Assignment expressions

有新的语法:=将值分配给变量,作为较大表达式的一部分。由于它与海象的眼睛和象牙相似,因此被亲切地称为“海象运算符”。

在此示例中,赋值表达式有助于避免两次调用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]

try限制使用海象运算符来清理可降低复杂性并提高可读性的案例。

完整说明请参见 PEP 572

(由bpo-35224中的 Emily Morehouse 提供。)

Positional-only parameters

有一个新的函数参数语法/来指示某些函数参数必须在位置上指定,并且不能用作关键字参数。对于由 Larry Hastings 的Argument Clinic工具 Comments 的 C 函数,此符号与help()所示相同。

在以下示例中,参数* 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 编码函数的行为。例如,内置的divmod()函数不接受关键字参数:

def divmod(a, b, /):
    "Emulate the built in divmod() function"
    return (a // b, a % b)

另一个用例是在参数名称无用时排除关键字参数。例如,内置的len()函数具有签名len(obj, /)。这避免了尴尬的调用,例如:

len(obj='hello')  # The "obj" keyword argument impairs readability

将参数标记为仅位置的另一个好处是,它允许将来更改参数名称而不会破坏 Client 端代码。例如,在statistics模块中,将来可能会更改参数名称* dist *。pass以下Function说明可以实现此目的:

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

(由 Pablo Galindo 在bpo-36540中贡献。)

编译的字节码文件的并行文件系统缓存

新的 PYTHONPYCACHEPREFIX设置(也可用于-X pycache_prefix)将隐式字节码缓存配置为使用单独的并行文件系统树,而不是每个源目录中的默认__pycache__子目录。

缓存的位置在sys.pycache_prefix中报告(None表示__pycache__子目录中的默认位置)。

(由 Carl Meyer 在bpo-33499中贡献。)

调试版本使用与发布版本相同的 ABI

不管是在发布模式还是调试模式下构建,Python 现在都使用相同的 ABI。在 Unix 上,当 Python 以调试模式构建时,现在可以加载以发布模式构建的 C 扩展和使用稳定 ABI 构建的 C 扩展。

发行版本和调试版本现在与 ABI 兼容:定义Py_DEBUG宏不再意味着Py_TRACE_REFS宏,它引入了唯一的 ABI 不兼容性。可以使用新的./configure --with-trace-refs构建选项来设置Py_TRACE_REFS宏,该宏添加了sys.getobjects()函数和 PYTHONDUMPREFS环境变量。 (由 Victor Stinner 在bpo-36465中贡献。)

在 Unix 上,除了 Android 和 Cygwin 之外,C 扩展不再链接到 libpython。现在,静态链接的 Python 可以加载使用共享库 Python 构建的 C 扩展。 (由 Victor Stinner 在bpo-21536中贡献。)

在 Unix 上,当 Python 以调试模式构建时,import 现在还将寻找以发布模式编译的 C 扩展以及使用稳定的 ABI 编译的 C 扩展。 (由 Victor Stinner 在bpo-36722中贡献。)

要将 Python 嵌入到应用程序中,必须将新的--embed选项传递给python3-config --libs --embed以获得-lpython3.8(将应用程序链接到 libpython)。要同时支持 3.8 和更早版本,请先trypython3-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 和更早版本,请先trypkg-config python-X.Y-embed --libs并try回退到pkg-config python-X.Y --libs(不使用--embed),如果先前的命令失败(将X.Y替换为 Python 版本)。

另一方面,pkg-config python3.8 --libs不再包含-lpython3.8。 C 扩展不得链接到 libpython(Android 和 Cygwin 除外,它们的情况由脚本处理);此更改是有意向后不兼容的。 (由 Victor Stinner 在bpo-36721中贡献。)

f 字符串支持=用于自记录表达式和调试

f-string s 中添加了=说明符。诸如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

(由bpo-36817中的 Eric V. Smith 和 Larry Hastings 贡献。)

PEP 578:Python 运行时审核钩子

PEP 添加了“审核钩子”和“已验证的打开钩子”。两者均可从 Python 和本机代码获得,从而允许使用纯 Python 代码编写的应用程序和框架利用额外的通知,同时还允许嵌入程序或系统 Management 员在始终启用审核的情况下部署 Python 版本。

有关完整详细信息,请参见 PEP 578

PEP 587:Python 初始化配置

PEP 587添加了一个新的 C API 以配置 Python 初始化,从而提供了对整个配置的更好控制和更好的错误报告。

New structures:

New functions:

该 PEP 还将_PyRuntimeState.preconfig(PyPreConfig类型)和PyInterpreterState.config(PyConfig类型)字段添加到这些内部结构中。 PyInterpreterState.config成为新的参考配置,替换了全局配置变量和其他私有变量。

有关文档,请参见Python 初始化配置

完整说明请参见 PEP 587

(由 Victor Stinner 在bpo-36763中贡献。)

Vectorcall:CPython 的快速调用协议

“ vectorcall”协议已添加到 Python/C API。它旨在将已经针对各种类进行的现有优化形式化。任何实现可调用的扩展类型都可以使用此协议。

目前这是临时的。目的是使其在 Python 3.9 中完全公开。

完整说明请参见 PEP 590

(由 Jeroen Demeyer 和 Mark Shannon 在bpo-36974中贡献。)

具有带外数据缓冲区的 Pickle 协议 5

pickle用于在 Python 进程之间传输大数据以利用多核或多计算机处理时,重要的是pass减少内存副本并可能pass应用自定义技术(例如依赖于数据的压缩)来优化传输。

pickle协议 5 引入了对带外缓冲区的支持,其中 PEP 3118兼容的数据可以根据通信层的判断从主 pickle 流中单独发送出去。

完整说明请参见 PEP 574

(由bpo-36785中的 Antoine Pitrou 提供。)

其他语言更改

>>> notice = 'Copyright © 2019'
>>> copyright_year_pattern = re.compile(r'\N{copyright sign}\s*(\d{4})')
>>> int(copyright_year_pattern.search(notice).group(1))
2019

(由 Jonathan Eunice 和 Serhiy Storchaka 在bpo-30688中贡献。)

  • Dict 和 dictview 现在可以使用reversed()以相反的插入 Sequences 进行迭代。 (由 RémiLapeyre 在bpo-33462中贡献。)

  • 函数调用中允许关键字名称使用的语法受到进一步限制。特别是,不再允许f((keyword)=arg)。从来没有打算在关键字参数赋值术语的左侧仅允许使用裸名。 (由本杰明·彼得森在bpo-34641中贡献。)

  • yieldreturn语句中的广义可迭代拆包不再需要用括号括起来。这使* yield return *语法与常规赋值语法更好地达成了一致:

>>> def parse(family):
        lastname, *members = family.split()
        return lastname.upper(), *members

>>> parse('simpsons homer marge bart lisa sally')
('SIMPSONS', 'homer', 'marge', 'bart', 'lisa', 'sally')

(由 David Cuthbert 和 Jordan Chapman 在bpo-32117中贡献。)

  • 如果在诸如[(10, 20) (30, 40)]之类的代码中缺少逗号,则编译器会显示SyntaxWarning并提供有用的建议。这在仅具有一个TypeError指示第一个 Tuples 不可调用的情况下有所改进。 (由 Serhiy Storchaka 在bpo-15248中贡献。)

  • datetime.datedatetime.datetimedatetime.timedelta对象的子类之间的算术运算现在返回该子类的实例,而不是 Base Class。这也会影响其实现(直接或间接)使用datetime.timedelta算术(例如astimezone())的操作的返回类型。 (由 Paul Ganssle 在bpo-32417中贡献。)

  • 当 Python 解释器被 Ctrl-C(SIGINT)break并且未捕获到所产生的KeyboardInterrupt异常时,Python 进程现在pass SIGINTsignal 或使用正确的退出代码退出,以便调用进程可以检测到它是由于 Ctrl-C。 POSIX 和 Windows 上的 Shell 使用它来正确终止交互式会话中的脚本。 (由 Google 在bpo-1054041中pass Gregory P. Smith 提供。)

  • 某些高级编程风格需要更新types.CodeType对象以用于现有Function。由于代码对象是不可变的,因此需要创建一个新的代码对象,该对象以现有的代码对象为模型。使用 19 个参数,这有点乏味。现在,新的replace()方法使创建带有一些更改参数的克隆成为可能。

这是更改statistics.mean()函数以防止* data *参数用作关键字参数的示例:

>>> from statistics import mean
>>> mean(data=[10, 20, 90])
40
>>> mean.__code__ = mean.__code__.replace(co_posonlyargcount=1)
>>> mean(data=[10, 20, 90])
Traceback (most recent call last):
  ...
TypeError: mean() got some positional-only arguments passed as keyword arguments: 'data'

(由 Victor Stinner 在bpo-37032中贡献。)

  • 对于整数,在底数相对于模数为质数的情况下,pow()函数的三参数形式现在允许指数为负。然后,当指数为-1时,它会计算与基数的模逆,并为其他负指数计算该逆的合适幂。例如,要计算 38 以 137 为模的模乘逆,请 Importing:
>>> pow(38, -1, 137)
119
>>> 119 * 38 % 137
1

线性丢番图方程的解中出现模逆。例如,要找到4258? + 147? = 369的整数解,请首先将其重写为4258? ≡ 369 (mod 147),然后求解:

>>> x = 369 * pow(4258, -1, 147) % 147
>>> y = (4258 * x - 369) // -147
>>> 4258 * x + 147 * y
369

(由 Mark Dickinson 在bpo-36027中贡献。)

  • Dict 理解已与 dictLiterals 同步,因此首先计算键,然后计算值:
>>> # Dict comprehension
>>> cast = {input('role? '): input('actor? ') for i in range(2)}
role? King Arthur
actor? Chapman
role? Black Knight
actor? Cleese

>>> # Dict literal
>>> cast = {input('role? '): input('actor? ')}
role? Sir Robin
actor? Eric Idle

保证执行 Sequences 对分配表达式很有用,因为在键表达式中分配的变量将在值表达式中可用:

>>> names = ['Martin von Löwis', 'Łukasz Langa', 'Walter Dörwald']
>>> {(n := normalize('NFC', name)).casefold() : n for name in names}
{'martin von löwis': 'Martin von Löwis',
 'łukasz langa': 'Łukasz Langa',
 'walter dörwald': 'Walter Dörwald'}

(由 JörnHeissler 在bpo-35224中贡献。)

  • object.reduce()方法现在可以返回长度为 2 到 6 个元素的 Tuples。以前,五个是极限。新的可选第六元素是带有(obj, state)签名的可调用元素。这允许直接控制特定对象的状态更新行为。如果不是* None *,则此可调用对象的优先级高于对象的setstate()方法。 (由 Pierre Glaser 和 Olivier Grisel 在bpo-35900中贡献。)

New Modules

  • 新的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')]

(由 Barry Warsaw 和 Jason R. Coombs 在bpo-34632中贡献。)

Improved Modules

ast

AST 节点现在具有end_linenoend_col_offset属性,它们可提供节点末端的精确位置。 (这仅适用于具有linenocol_offset属性的节点.)

新函数ast.get_source_segment()返回特定 AST 节点的源代码。

(由 Ivan Levkivskyi 在bpo-33416中贡献。)

ast.parse()函数具有一些新标志:

  • type_comments=True使其返回与某些 AST 节点关联的 PEP 484 PEP 526类型的 Comments 的文本;

  • mode='func_type'可用于解析 PEP 484“签名类型 Comments”(为函数定义 AST 节点返回);

  • feature_version=(3, N)允许指定早期的 Python 3 版本。例如,feature_version=(3, 4)asyncawait视为非保留字。

(由 Guido van Rossum 在bpo-35766中贡献。)

asyncio

asyncio.run()已从临时 API 升级为稳定的 API。此函数可用于执行coroutine并返回结果,同时自动 Management 事件循环。例如:

import asyncio

async def main():
    await asyncio.sleep(0)
    return 42

asyncio.run(main())

大致相当于:

import asyncio

async def main():
    await asyncio.sleep(0)
    return 42

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
    loop.run_until_complete(main())
finally:
    asyncio.set_event_loop(None)
    loop.close()

实际的实现要复杂得多。因此,asyncio.run()应该是运行异步程序的首选方式。

(由 Yury Selivanov 在bpo-32314中贡献。)

运行python -m asyncio将启动本地异步 REPL。这样可以快速测试具有顶级await的代码。不再需要直接调用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

(由 Yury Selivanov 在bpo-37028中贡献。)

现在,异常asyncio.CancelledError继承自BaseException而不是Exception,并且不再继承自concurrent.futures.CancelledError。 (由 Yury Selivanov 在bpo-32528中贡献。)

在 Windows 上,默认事件循环现在为ProactorEventLoop。 (由 Victor Stinner 在bpo-34687中贡献。)

ProactorEventLoop现在还支持 UDP。 (由 Adam Meily 和 Andrew Svetlov 在bpo-29883中贡献。)

ProactorEventLoop现在可以被KeyboardInterrupt(“ CTRL C”)打断。 (由 Vladimir Matveev 在bpo-23057中贡献。)

添加了asyncio.Task.get_coro()以便在asyncio.Task内获取包装好的协程。 (由 AlexGrönholm 在bpo-36999中贡献。)

现在可以pass将name关键字参数传递给asyncio.create_task()create_task()事件循环方法,或者pass在任务对象上调用set_name()方法来命名 Asyncio 任务。任务名称在asyncio.Taskrepr()输出中可见,也可以使用get_name()方法检索。 (由 AlexGrönholm 在bpo-34270中贡献。)

添加了对Happy Eyeballsasyncio.loop.create_connection()的支持。为了指定行为,添加了两个新参数:* happy_eyeballs_delay interleave *。passtry同时使用两者进行连接,Happy Eyeballs 算法可提高支持 IPv4 和 IPv6 的应用程序的响应速度。 (由bpo-33530中的 Twisteroid 大使提供。)

builtins

内置compile()已得到改进,可以接受ast.PyCF_ALLOW_TOP_LEVEL_AWAIT标志。传递此新标志后,compile()将允许通常认为无效语法的顶级awaitasync forasync with构造。然后可以返回标记有CO_COROUTINE标志的异步代码对象。 (由 Matthias Bussonnier 在bpo-34616中贡献)

collections

collections.namedtuple()_asdict()方法现在返回dict而不是collections.OrderedDict。之所以可行,是因为自 3.7 以来,常规命令就保证了排序。如果需要OrderedDict的其他Function,建议的补救措施是将结果转换为所需的类型:OrderedDict(nt._asdict())。 (由 Raymond Hettinger 在bpo-35864中贡献。)

cProfile

cProfile.Profile类现在可以用作上下文 Management 器。pass运行以下代码来分析代码块:

import cProfile

with cProfile.Profile() as profiler:
      # code to be profiled
      ...

(由 Scott Sanderson 在bpo-29235中贡献。)

csv

csv.DictReader现在返回dict而不是collections.OrderedDict的实例。该工具现在速度更快,使用的内存更少,同时仍然保留了字段 Sequences。 (由 Michael Selik 在bpo-34003中贡献。)

curses

添加了一个新变量,用于存放基础 ncurses 库的结构化版本信息:ncurses_version。 (由 Serhiy Storchaka 在bpo-31680中贡献。)

ctypes

在 Windows 上,CDLL和子类现在接受一个* winmode *参数来指定基础LoadLibraryEx调用的标志。默认标志设置为仅从受信任的位置加载 DLL 依赖项,包括存储 DLL 的路径(如果使用完整或部分路径来加载初始 DLL)和add_dll_directory()添加的路径。 (由 Steve Dower 在bpo-36085中贡献。)

datetime

添加了新的备用构造函数datetime.date.fromisocalendar()datetime.datetime.fromisocalendar(),分别从 ISO 年,周号和工作日构造datedatetime对象;这些是每个类的isocalendar方法的反函数。 (由 Paul Ganssle 在bpo-36004中贡献。)

functools

functools.lru_cache()现在可以用作纯修饰符,而不能用作返回修饰符的函数。所以现在都支持这两个:

@lru_cache
def f(x):
    ...

@lru_cache(maxsize=256)
def f(x):
    ...

(由 Raymond Hettinger 在bpo-36772中贡献。)

添加了一个新的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)

(由 Carl Meyer 在bpo-21145中贡献)

添加了一个新的functools.singledispatchmethod()装饰器,该装饰器使用single dispatch将方法转换为generic functions

from functools import singledispatchmethod
from contextlib import suppress

class TaskManager:

    def __init__(self, tasks):
        self.tasks = list(tasks)

    @singledispatchmethod
    def discard(self, value):
        with suppress(ValueError):
            self.tasks.remove(value)

    @discard.register(list)
    def _(self, tasks):
        targets = set(tasks)
        self.tasks = [x for x in self.tasks if x not in targets]

(由 Ethan Smith 在bpo-32380中贡献)

gc

get_objects()现在可以接收可选的* generation *参数,该参数指示从中获取对象的一代。 (由 Pablo Galindo 在bpo-36016中贡献。)

gettext

添加了pgettext()及其变体。 (由 Franz Glasner,ÉricAraujo 和 Cheryl Sabella 在bpo-2504中贡献。)

gzip

gzip.compress()添加了* mtime *参数,以实现可重现的输出。 (由 Guo Ci Teo 在bpo-34898中贡献。)

对于某些类型的无效或损坏的 gzip 文件,现在引发BadGzipFile而不是OSError的异常。 (由bpo-6584中的 FilipGruszczyński,MicheleOrrù和 Zackery Spytz 贡献。)

IDLE 和 idlelib

N 行(默认为 50 行)上的输出被压缩为一个按钮。可以在“设置”对话框的“常规”页面的“ PyShell”部分中更改 N。右键单击输出可以减少行,但可能会更长。可以pass双击按钮将压缩的输出扩展到适当位置,或者pass右键单击按钮将其扩展到剪贴板或单独的窗口中。 (由 Tal Einat 在bpo-1529353中贡献。)

将“自定义运行”添加到“运行”菜单,以运行具有自定义设置的模块。Importing 的所有命令行参数都将添加到 sys.argv。它们还会重新出现在框中,以进行下一次自定义运行。还可以抑制 Shell 主模块正常重启。 (由 Cheryl Sabella,Terry Jan Reedy 和其他人在bpo-5680bpo-37627中贡献。)

添加了 IDLE 编辑器窗口的可选行号。除非在配置对话框的“常规”选项卡中另有设置,否则 Windows 将打开而没有行号。现有窗口的行号在“选项”菜单中显示和隐藏。 (由 Tal Einat 和 Saimadhav Heblikar 在bpo-17535中贡献。)

现在,OS 本机编码用于在 Python 字符串和 Tcl 对象之间进行转换。这使 IDLE 可以处理表情符号和其他非 BMP 字符。这些字符可以显示或复制并粘贴到剪贴板或从剪贴板粘贴。将字符串从 Tcl 转换为 Python 并返回现在永远不会失败。 (许多人为此工作了八年,但问题终于由bpo-13153的 Serhiy Storchaka 解决了。)

以上更改已反向移植到 3.7 维护版本。

inspect

如果该属性是dict且值是文档字符串,则inspect.getdoc()函数现在可以找到__slots__的文档字符串。这提供了类似于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)

(由 Raymond Hettinger 在bpo-36326中贡献。)

io

在开发模式(-X env)和调试版本中,如果close()方法失败,则io.IOBase终结器现在记录异常。在发行版本中,默认情况下将忽略该异常。 (由 Victor Stinner 在bpo-18748中贡献。)

itertools

itertools.accumulate()函数添加了一个* initial *关键字参数来指定初始值:

>>> from itertools import accumulate
>>> list(accumulate([10, 5, 30, 15], initial=1000))
[1000, 1010, 1015, 1045, 1060]

(由 Lisa Roach 在bpo-34659中贡献。)

json.tool

添加选项--json-lines将每个 Importing 行解析为一个单独的 JSON 对象。 (由 Weipeng Hong 在bpo-31553中贡献。)

logging

logging.basicConfig()上添加了一个* force *关键字参数。当设置为 true 时,在执行其他参数指定的配置之前,将删除并关闭附加到根记录程序的所有现有处理程序。

这解决了一个长期存在的问题。一旦调用了 logger 或* basicConfig(),随后对 basicConfig()*的调用将被忽略。这使得使用交互式提示或 Jupyter 笔记本电脑难以更新,试验或教授各种日志记录配置选项。

(由 Raymond Hettinger 建议,由 Dong-hee Na 实施,并由 Vinay Sajip 在bpo-33897中进行了审查。)

math

添加了新Functionmath.dist(),用于计算两点之间的欧几里得距离。 (由 Raymond Hettinger 在bpo-33089中贡献。)

扩展了math.hypot()函数以处理多个维度。以前,它仅支持二维情况。 (由 Raymond Hettinger 在bpo-33089中贡献。)

sum()类似,添加了新函数math.prod(),该函数返回“起始”值(默认值:1)乘以数字可迭代数的乘积:

>>> prior = 0.8
>>> likelihoods = [0.625, 0.84, 0.30]
>>> math.prod(likelihoods, start=prior)
0.126

(由 Pablo Galindo 在bpo-35606中贡献。)

添加了两个新的组合函数math.perm()math.comb()

>>> math.perm(10, 3)    # Permutations of 10 things taken 3 at a time
720
>>> math.comb(10, 3)    # Combinations of 10 things taken 3 at a time
120

(由 Yash Aggarwal,Keller Fuchs,Serhiy Storchaka 和 Raymond Hettinger 在bpo-37128bpo-37178bpo-35431中贡献。)

添加了一个新函数math.isqrt(),用于计算准确的整数平方根,而无需转换为浮点数。新函数支持任意大的整数。它比floor(sqrt(n))快,但比math.sqrt()慢:

>>> r = 650320427
>>> s = r ** 2
>>> isqrt(s - 1)         # correct
650320426
>>> floor(sqrt(s - 1))   # incorrect
650320427

(由 Mark Dickinson 在bpo-36887中贡献。)

函数math.factorial()不再接受非整数类型的参数。 (由 Pablo Galindo 在bpo-33083中贡献。)

mmap

现在,mmap.mmap类具有madvise()方法来访问madvise()系统调用。 (由 Zackery Spytz 在bpo-32941中贡献。)

multiprocessing

添加了新的multiprocessing.shared_memory模块。 (由bpo-35813中的 Davin Potts 贡献。)

在 macOS 上,默认情况下现在使用* spawn *启动方法。 (由 Victor Stinner 在bpo-33725中贡献。)

os

在 Windows 上添加了新Functionadd_dll_directory(),用于在导入扩展模块或使用ctypes加载 DLL 时为本地依赖项提供其他搜索路径。 (由 Steve Dower 在bpo-36085中贡献。)

添加了一个新的os.memfd_create()函数来包装memfd_create() syscall。 (由 Zackery Spytz 和 Christian Heimes 在bpo-26836中贡献。)

在 Windows 上,许多用于处理重解析点的手动逻辑(包括符号链接和目录连接)已委派给 os。具体来说,os.stat()现在将遍历 os 支持的所有内容,而os.lstat()将仅打开标识为“名称代理”的重新解析点,而其他的os.stat()则打开。在所有情况下,stat_result.st_mode只会为符号链接设置S_IFLNK,而不会设置其他种类的重新解析点。要标识其他种类的重解析点,请检查新的stat_result.st_reparse_tag属性。

在 Windows 上,os.readlink()现在可以读取目录连接。请注意,islink()将为目录连接返回False,因此首先检查islink的代码将 continue 将连接视为目录,而处理os.readlink()的错误的代码现在可能会将连接视为链接。

(由 Steve Dower 在bpo-37834中贡献。)

os.path

现在,返回布尔值的os.path函数(例如exists()lexists()isdir()isfile()islink()ismount())返回False,而不是提高ValueError或其子类UnicodeEncodeErrorUnicodeDecodeError的路径,这些路径包含在 os 级别无法表示的字符或字节。 (由 Serhiy Storchaka 在bpo-33721中贡献。)

Windows 上的expanduser()现在更喜欢 USERPROFILE环境变量,并且不使用 HOME,通常不会为常规用户帐户设置。 (由 Anthony Sottile 在bpo-36264中贡献。)

Windows 上的isdir()不再为指向不存在的目录的链接返回True

Windows 上的realpath()现在可以解析重新解析点,包括符号链接和目录连接。

(由 Steve Dower 在bpo-37834中贡献。)

pathlib

pathlib.Path返回布尔结果(例如exists()is_dir()is_file()is_mount()is_symlink()is_block_device()is_char_device()is_fifo()is_socket())的方法现在返回False,而不是针对包含在 OS 级别上无法表示的字符的路径提高ValueError或其子类UnicodeEncodeError。 (由 Serhiy Storchaka 在bpo-33721中贡献。)

添加了pathlib.Path.link_to(),它创建了指向路径的硬链接。 (由 Joannah Nanjekye 在bpo-26978中贡献)

pickle

现在,pass定义特殊的reducer_override()方法,对 C 优化的Pickler进行子类化的pickle扩展可以覆盖函数和类的 Pickling 逻辑。 (由 Pierre Glaser 和 Olivier Grisel 在bpo-35900中贡献。)

plistlib

添加了新的plistlib.UID并启用了对读写 NSKeyedArchiver 编码的二进制 plists 的支持。 (由 Jon Janzen 在bpo-26707中贡献。)

pprint

pprint模块向多个函数添加了* sort_dicts 参数。默认情况下,这些Function会在渲染或打印之前 continue 对字典进行排序。但是,如果 sort_dicts *设置为 false,则字典将保留插入键的 Sequences。这对于在调试期间与 JSONImporting 进行比较很有用。

此外,还有一个方便的新Function,pprint.pp()类似于pprint.pprint(),但* sort_dicts *默认为False

>>> from pprint import pprint, pp
>>> d = dict(source='input.txt', operation='filter', destination='output.txt')
>>> pp(d, width=40)                  # Original order
{'source': 'input.txt',
 'operation': 'filter',
 'destination': 'output.txt'}
>>> pprint(d, width=40)              # Keys sorted alphabetically
{'destination': 'output.txt',
 'operation': 'filter',
 'source': 'input.txt'}

(由 RémiLapeyre 在bpo-30670中贡献。)

py_compile

py_compile.compile()现在支持静音模式。 (由 Joannah Nanjekye 在bpo-22640中贡献。)

shlex

新的shlex.join()函数充当shlex.split()的逆函数。 (由 Bo Bayles 在bpo-32102中贡献。)

shutil

shutil.copytree()现在接受新的dirs_exist_ok关键字参数。 (由 Josh Bronson 在bpo-20849中贡献。)

对于新 Files,shutil.make_archive()现在默认为现代 pax(POSIX.1-2001)格式,以提高可移植性和标准一致性,该格式继承自对tarfile模块的相应更改。 (由 C.A.M. Gerlach 在bpo-30661中贡献。)

Windows 上的shutil.rmtree()现在可以删除目录连接,而无需先递归地删除其内容。 (由 Steve Dower 在bpo-37834中贡献。)

socket

添加了create_server()has_dualstack_ipv6()便利Function,以自动化创建服务器套接字时通常涉及的必要任务,包括在同一套接字上同时接受 IPv4 和 IPv6 连接。 (由 GiampaoloRodolà在bpo-17561中贡献。)

socket.if_nameindex()socket.if_nametoindex()socket.if_indextoname()Function已在 Windows 上实现。 (由 Zackery Spytz 在bpo-37007中贡献。)

ssl

添加了post_handshake_auth以启用verify_client_post_handshake()以启动 TLS 1.3 握手后身份验证。 (由 Chris Heimes 在bpo-34670中贡献。)

statistics

添加了statistics.fmean()作为statistics.mean()的更快的浮点变量。 (由bpo-35904的 Raymond Hettinger 和 Steven D'Aprano 提供。)

添加了statistics.geometric_mean()(由bpo-27181中的 Raymond Hettinger 贡献。)

添加了statistics.multimode(),该参数返回最常用值的列表。 (由 Raymond Hettinger 在bpo-35892中贡献。)

添加了statistics.quantiles(),它将数据或分布划分为等概率间隔(例如,四分位数,十分位数或百分位数)。 (由 Raymond Hettinger 在bpo-36546中贡献。)

添加了statistics.NormalDist,该工具用于创建和处理随机变量的正态分布。 (由 Raymond Hettinger 在bpo-36018中贡献。)

>>> 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())。 (由 Victor Stinner 在bpo-36829中贡献。)

tarfile

现在,对于新 Files,tarfile模块默认为现代 pax(POSIX.1-2001)格式,而不是先前的特定于 GNU 的格式。这以标准化且可扩展的格式pass一致的编码(UTF-8)改善了跨平台的可移植性,并提供了其他一些好处。 (由 C.A.M. Gerlach 在bpo-36268中贡献。)

threading

添加一个新的threading.excepthook()函数来处理未捕获的threading.Thread.run()异常。可以重写它来控制未捕获的threading.Thread.run()异常的处理方式。 (由 Victor Stinner 在bpo-1230540中贡献。)

threading.Thread类添加新的threading.get_native_id()函数和native_id属性。它们返回内核分配的当前线程的本机整数 Thread ID。此Function仅在某些平台上可用,有关更多信息,请参见get_native_id。 (由bpo-36084中的 Jake Tesler 贡献。)

tokenize

现在,提供了没有尾随新行的 Importing 时,tokenize模块隐式发出NEWLINE令牌。现在,此行为与 C 标记程序内部执行的操作匹配。 (由 Ammar Askar 在bpo-33899中贡献。)

tkinter

tkinter.Spinbox类中添加了方法selection_from()selection_present()selection_range()selection_to()。 (由 Juliette Monsel 在bpo-34829中贡献。)

tkinter.Canvas类中添加了方法moveto()。 (由 Juliette Monsel 在bpo-23831中贡献。)

现在,tkinter.PhotoImage类具有transparency_get()transparency_set()方法。 (由 Zackery Spytz 在bpo-25451中贡献。)

time

为 macOS 10.12 添加了新时钟CLOCK_UPTIME_RAW。 (由 Joannah Nanjekye 在bpo-35702中贡献。)

typing

typing模块合并了几个新Function:

  • 具有每个键类型的字典类型。参见 PEP 589typing.TypedDict。 TypedDict 仅使用字符串键。默认情况下,要求每个密钥都存在。指定“ total = False”以允许键是可选的:
class Location(TypedDict, total=False):
    lat_long: tuple
    grid_square: str
    xy_coordinate: tuple
  • Literals 类型。参见 PEP 586typing.Literal。Literals 类型表示参数或返回值被限制为一个或多个特定 Literals 值:
def get_status(port: int) -> Literal['connected', 'disconnected']:
    ...
  • “finally”变量,函数,方法和类。参见 PEP 591typing.Finaltyping.final()。finally限定符指示静态类型检查器限制子类化,重写或重新分配:
pi: Final[float] = 3.1415926536

unicodedata

unicodedata模块已升级为使用Unicode 12.1.0版本。

新Functionis_normalized()可用于验证字符串是否具有特定的正常形式,通常比实际规范化字符串要快得多。 (由 Max Belanger,David Euresti 和 Greg Price 在bpo-32285bpo-37966中贡献)。

unittest

添加了AsyncMock以支持Mock的异步版本。还添加了用于测试的适当的新 assert 函数。 (由bpo-26467中的 Lisa Roach 贡献)。

添加了addModuleCleanup()addClassCleanup()进行单元测试以支持对setUpModule()setUpClass()的清理。 (由bpo-24412中的 Lisa Roach 贡献。)

现在,一些模拟 assert 函数还可以在失败时打印出实际调用的列表。 (由bpo-35047中的 Petter Strandmark 提供。)

unittest模块已支持将协程用作unittest.IsolatedAsyncioTestCase的测试用例。 (由 Andrew Svetlov 在bpo-32972中贡献。)

Example:

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 下激活虚拟环境。 (由 Brett Cannon 在bpo-32718中贡献。)

weakref

现在,由weakref.proxy()返回的代理对象除了支持其他数字运算符之外,还支持矩阵乘法运算符@@=。 (由 Mark Dickinson 在bpo-36669中贡献。)

xml

为了避免 DTD 和外部实体检索,默认情况下xml.dom.minidomxml.sax模块不再处理外部实体。 (由 Chris Heimes 在bpo-17239中贡献。)

xml.etree.ElementTree模块中的.find*()方法支持通配符搜索,例如{*}tag忽略名称空间,{namespace}*返回给定名称空间中的所有标记。 (由 Stefan Behnel 在bpo-28238中贡献。)

xml.etree.ElementTree模块提供了实现 C14N 2.0 的新Function–xml.etree.ElementTree.canonicalize()。 (由 Stefan Behnel 在bpo-13611中贡献。)

xml.etree.ElementTree.XMLParser的目标对象可以pass新的回调方法start_ns()end_ns()接收名称空间语句事件。另外,可以将xml.etree.ElementTree.TreeBuilder目标配置为处理有关 Comments 的事件并处理指令以将其包括在生成的树中。 (由 Stefan Behnel 在bpo-36676bpo-36673中贡献。)

xmlrpc

xmlrpc.client.ServerProxy现在支持可选的* headers *关键字参数,用于随每个请求发送的 HTTPHeaders 序列。除其他外,这使得从默认的基本身份验证升级到更快的会话身份验证成为可能。 (由 CédricKrier 在bpo-35153中贡献。)

Optimizations

  • 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 上使用特定于平台的“快速复制”系统调用,以便更有效地复制文件。 “快速复制”是指复制操作在内核内进行,避免了像“ outfd.write(infd.read())”那样在 Python 中使用用户空间缓冲区。在 Windows 上,shutil.copyfile()使用更大的默认缓冲区大小(1 MiB 而不是 16 KiB),并使用基于memoryview()shutil.copyfileobj()变体。在同一分区内复制 512 MiB 文件的速度在 Linux 上约为 26%,在 macOS 上约为 50%,在 Windows 上约为 40%。而且,消耗的 CPU 周期要少得多。参见平台相关的高效复制操作部分。 (由bpo-33671的 GiampaoloRodolà提供。)

  • shutil.copytree()使用os.scandir()函数,并且取决于它的所有复制函数都使用缓存的os.stat()值。在 Linux 上,复制包含 8000 个文件的目录的速度约为 9%,在 Windows 上约为 20%,在 Windows SMB 共享上约为 30%。 os.stat()系统调用的数量也减少了 38%,从而使shutil.copytree()在网络文件系统上特别快。 (由 GiampaoloRodolà在bpo-33695中贡献。)

  • pickle模块中的默认协议现在是协议 4,该协议最初是在 Python 3.4 中引入的。与自 Python 3.0 以来可用的协议 3 相比,它提供了更好的性能和更小的尺寸。

  • PyGC_Head中删除了一个Py_ssize_t成员。所有 GC 跟踪的对象(例如 Tuples,列表,字典)的大小都减少了 4 或 8 个字节。 (由 Inada Naoki 在bpo-33597中贡献。)

  • uuid.UUID现在使用__slots__来减少其内存占用量。 (由 Wouter Bolsterlee 和 Tal Einat 在bpo-30977中贡献)

  • operator.itemgetter()的性能提高了 33%。优化了参数处理,并为单个非负整数索引进入 Tuples 的常见情况添加了一条快速路径(这是标准库中的典型用例)。 (由 Raymond Hettinger 在bpo-35664中贡献。)

  • collections.namedtuple()中加速字段查找。现在它们的速度快了两倍以上,使其成为 Python 中最快的实例变量查找形式。 (由bpo-32492中的 Raymond Hettinger,Pablo Galindo 和 Joe Jevnik,Serhiy Storchaka 贡献。)

  • 如果可迭代的 Importing 具有已知长度(Importing 实现__len__),则list构造函数不会整体分配内部项目缓冲区。这样可使创建的列表平均缩小 12%。 (由 Raymond Hettinger 和 Pablo Galindo 在bpo-33234中贡献。)

  • 将类变量的写入速度提高了一倍。更新 non-dunder 属性时,不需要进行更新插槽的调用。 (由bpo-36012由 Stefan Behnel,Pablo Galindo Salgado,Raymond Hettinger,Neil Schemenauer 和 Serhiy Storchaka 贡献。)

  • 减少了转换传递给许多内置函数和方法的参数的开销。这加快了一些简单的内置函数和方法的调用,这些函数和方法的使用率高达 20%到 50%。 (由 Serhiy Storchaka 在bpo-23867bpo-35582bpo-36127中贡献。)

  • LOAD_GLOBAL指令现在使用新的“每个操作码缓存”机制。现在快了 40%。 (由 Yury Selivanov 和 Inada Naoki 在bpo-26219中贡献。)

Build 和 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_PY作为前缀。

    • Include/internal/*.h是专用于 CPython 的私有内部 C API。该 API 不具有向后兼容性保证,因此不应在 CPython 之外使用。仅针对非常特定的需求(例如调试器和配置文件)才公开它,而无需调用函数即可访问 CPython 内部。该 API 现在已由make install安装。

(由 Victor Stinner 在bpo-35134bpo-35081中贡献,由 Eric Snow 在 Python 3.7 中启动。)

  • 一些宏已转换为静态内联函数:参数类型和返回类型定义明确,它们没有特定于宏的问题,变量具有局部作用域。例子:

  • Py_INCREF(), Py_DECREF()

    • Py_XINCREF(), Py_XDECREF()

    • PyObject_INIT() , PyObject_INIT_VAR()

    • 专用Function:_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.distModules/Setup的对偶已被删除。以前,在更新 CPython 源代码树时,必须手动将Modules/Setup.dist(在源代码树内部)复制到Modules/Setup(在构建树内部),以反映上游的任何更改。对于打包人员来说,这是一个小好处,但以 CPython 开发之后对开发人员的频繁烦恼为代价,因为忘记复制文件可能会导致构建失败。

现在,构建系统始终从源代码树中的Modules/Setup读取。鼓励想要自定义该文件的人将其更改保存在 CPython 的 git fork 中或作为补丁文件进行,就像对源代码树进行任何其他更改一样。

(由bpo-32430中的 Antoine Pitrou 提供。)

Deprecated

这些方法的实现都忽略了它们的* index *参数,而是返回了下一项。 (由 Berker Peksag 在bpo-9372中贡献。)

函数bind_textdomain_codeset(),方法output_charset()set_output_charset()以及函数translation()install()的* codeset *参数也已弃用,因为它们仅用于l*gettext()函数。 (由 Serhiy Storchaka 在bpo-33710中贡献。)

在 Future 的 Python 版本中,它们将是positional-only。 (由 Serhiy Storchaka 在bpo-36492中贡献。)

API 和Function删除

以下Function和 API 已从 Python 3.8 中删除:

  • 从 Python 3.3 开始,不建议从collections导入 ABC,而应该从collections.abc导入。能够从集合导入的Function在 3.8 中被标记为已删除,但已延迟到 3.9. (请参见bpo-36952。)

  • 已删除 Python 3.7 中不推荐使用的macpath模块。 (由 Victor Stinner 在bpo-35471中贡献。)

  • 自 python 3.3 起不推荐使用platform.popen()函数,请删除它们:使用os.popen()代替。 (由 Victor Stinner 在bpo-35345中贡献。)

  • 自 python 3.3 起不推荐使用time.clock()函数,该函数已被删除:根据您的要求,使用time.perf_counter()time.process_time()来具有明确定义的行为。 (由 Matthias Bussonnier 在bpo-36895中贡献。)

  • 删除了pyvenv脚本,而赞成python3.8 -m venv,以消除关于pyvenv脚本所绑定的 Python 解释器的困惑。 (由 Brett Cannon 在bpo-25427中贡献。)

  • parse_qsparse_qslescape已从cgi模块中删除。在 Python 3.2 或更早版本中不推荐使用它们。应该从urllib.parsehtml模块导入它们。

  • filemodeFunction已从tarfile模块中删除。自 Python 3.3 起未记录和不推荐使用。

  • XMLParser构造函数不再接受* html *参数。它从未起作用,在 Python 3.4 中已弃用。现在,所有其他参数均为keyword-only。 (由 Serhiy Storchaka 在bpo-29209中贡献。)

  • 删除了XMLParserdoctype()方法。 (由 Serhiy Storchaka 在bpo-29209中贡献。)

  • 删除了“ unicode_internal”编解码器。 (由 Inada Naoki 在bpo-36297中贡献。)

  • sqlite3模块的CacheStatement对象不向用户公开。 (由 Aviv Palivoda 在bpo-30262中贡献。)

  • fileinput.input()fileinput.FileInput()bufsize关键字参数已被删除,因为删除了 Python 3.6,因此已弃用。 bpo-36952(由 Matthias Bussonnier 贡献.)

  • Python 3.7 中弃用的Functionsys.set_coroutine_wrapper()sys.get_coroutine_wrapper()已被删除; bpo-36933(由 Matthias Bussonnier 贡献.)

移植到 Python 3.8

本节列出了先前描述的更改以及可能需要对代码进行更改的其他错误修正。

Python 行为的变化

  • 现在,理解和生成器表达式(除了最左边的for子句中的可迭代表达式)都不允许使用 yield 表达式(yieldyield from子句)。 (由 Serhiy Storchaka 在bpo-10544中贡献。)

  • 现在,当身份检查(isis not)与某些类型的 Literals(例如字符串,数字)一起使用时,编译器会生成SyntaxWarning。这些通常在 CPython 中偶然地起作用,但是语言规范无法保证。该警告建议用户改用相等性测试(==!=)。 (由 Serhiy Storchaka 在bpo-34850中贡献。)

  • 在某些情况下,CPython 解释器可以吞下异常。在 Python 3.8 中,这种情况很少发生。特别是,从类型字典中获取属性时引发的异常将不再被忽略。 (由 Serhiy Storchaka 在bpo-35459中贡献。)

  • 从内置类型boolintfloatcomplex中删除了__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()PyEval_AcquireThread(),则终止当前线程,使它们与PyEval_RestoreThread()Py_END_ALLOW_THREADS()PyGILState_Ensure()一致。如果不需要此行为,请pass检查_Py_IsFinalizing()sys.is_finalizing()来保护呼叫。 (由bpo-36475中的 Joannah Nanjekye 提供。)

Python API 中的更改

  • 现在,os.getcwdb()函数在 Windows 上使用 UTF-8 编码,而不是 ANSI 代码页:基本原理请参见 PEP 529。 Windows 不再弃用该Function。 (由 Victor Stinner 在bpo-37412中贡献。)

  • subprocess.Popen现在可以在某些情况下使用os.posix_spawn()以获得更好的性能。在 Linux 子系统和 QEMU 用户仿真的 Windows 子系统上,使用os.posix_spawn()Popen构造函数不再针对诸如“缺少程序”之类的错误引发异常。相反,子进程失败,返回非零returncode。 (由bpo-35537中的 Joannah Nanjekye 和 Victor Stinner 贡献。)

  • imap.IMAP4.logout()方法不再静默忽略任意异常。 (由 Victor Stinner 在bpo-36348中贡献。)

  • 自 python 3.3 起不推荐使用platform.popen()函数,请删除它们:使用os.popen()代替。 (由 Victor Stinner 在bpo-35345中贡献。)

  • 给定多峰数据时,statistics.mode()函数不再引发异常。而是返回 Importing 数据中遇到的第一个模式。 (由 Raymond Hettinger 在bpo-35892中贡献。)

  • tkinter.ttk.Treeview类的selection()方法不再使用参数。在 Python 3.6 中,不建议将其与用于更改选择的参数一起使用。使用selection_set()之类的专用方法来更改选择。 (由 Serhiy Storchaka 在bpo-31508中贡献。)

  • xml.dom.minidomwritexml()toxml()toprettyxml()方法以及xml.etreewrite()方法现在保留了用户指定的属性 Sequences。 (由 Diego Rojas 和 Raymond Hettinger 在bpo-34160中贡献。)

  • 现在,使用标志'r'打开的dbm.dumb数据库是只读的。如果标记'r''w'不存在,则dbm.dumb.open()不再创建数据库。 (由 Serhiy Storchaka 在bpo-32749中贡献。)

  • XMLParser子类中定义的doctype()方法将不再被调用,并且将发出RuntimeWarning而不是DeprecationWarning。在目标上定义doctype()方法,以处理 XML 文档类型语句。 (由 Serhiy Storchaka 在bpo-29209中贡献。)

  • 现在,当自定义元类在传递给type.__new__的命名空间中未提供__classcell__条目时,将引发RuntimeError。在 Python 3.6–3.7 中发出了DeprecationWarning。 (由 Serhiy Storchaka 在bpo-23722中贡献。)

  • 现在可以将cProfile.Profile类用作上下文 Management 器。 (由 Scott Sanderson 在bpo-29235中贡献。)

  • shutil.copyfile()shutil.copy()shutil.copy2()shutil.copytree()shutil.move()使用特定于平台的“快速复制”系统调用(请参见平台相关的高效复制操作部分)。

  • shutil.copyfile() Windows 上的默认缓冲区大小已从 16 KiB 更改为 1 MiB。

  • PyGC_Head结构已完全更改。所有与 struct 成员相关的代码都应重写。 (请参阅bpo-33597。)

  • PyInterpreterState结构已移至“内部”头文件(特别是 Include/internal/pycore_pystate.h)。作为公共 API(和稳定的 ABI)的一部分,不透明的PyInterpreterState仍然可用。该文档表明该结构的字段均未公开,因此我们希望没有人使用它们。但是,如果您确实依赖这些私有字段中的一个或多个,并且别无选择,请打开 BPO 问题。我们将努力帮助您进行调整(可能包括向公共 API 添加访问器Function)。 (请参阅bpo-35886。)

  • 现在,在所有平台上,mmap.flush()方法成功返回None,并在错误时引发异常。以前,它的行为取决于平台:成功时返回非零值; Windows 下的错误返回零。成功返回零值。在 Unix 下,由于错误而引发了异常。 (由 Berker Peksag 在bpo-2122中贡献。)

  • 默认情况下,xml.dom.minidomxml.sax模块不再处理外部实体。 (由 Chris Heimes 在bpo-17239中贡献。)

  • 从只读dbm数据库(dbm.dumbdbm.gnudbm.ndbm)中删除密钥会引发error(dbm.dumb.errordbm.gnu.errordbm.ndbm.error)而不是KeyError。 (由张翔在bpo-33106中贡献。)

  • Literals 的简化 AST。所有常量都将表示为ast.Constant个实例。实例化旧类NumStrBytesNameConstantEllipsis将返回Constant的实例。 (由 Serhiy Storchaka 在bpo-32892中贡献。)

  • Windows 上的expanduser()现在更喜欢 USERPROFILE环境变量,并且不使用 HOME,通常不会为常规用户帐户设置。 (由 Anthony Sottile 在bpo-36264中贡献。)

  • 现在,异常asyncio.CancelledError继承自BaseException而不是Exception,并且不再继承自concurrent.futures.CancelledError。 (由 Yury Selivanov 在bpo-32528中贡献。)

  • 现在,使用asyncio.Task实例时,函数asyncio.wait_for()正正确 await 取消。以前,达到* timeout *时,它被取消并立即返回。 (由 Elvis Pranskevichus 在bpo-32751中贡献。)

  • 现在,当将'socket'传递给* name *参数时,函数asyncio.BaseTransport.get_extra_info()返回一个可以安全使用的套接字对象。 (由 Yury Selivanov 在bpo-37027中贡献。)

  • asyncio.BufferedProtocol已升级到稳定的 API。

  • 现在可以更安全地解决 Windows 上扩展模块的 DLL 依赖关系和ctypes加载的 DLL 的依赖关系。仅搜索系统路径,包含 DLL 或 PYD 文件的目录以及以add_dll_directory()添加的目录以查找加载时间依赖性。具体来说,不再使用 PATH和当前工作目录,并且对它们的修改将不再对正常的 DLL 解析产生任何影响。如果您的应用程序依赖于这些机制,则应检查add_dll_directory(),如果存在,则在加载库时使用它来添加 DLL 目录。请注意,Windows 7 用户将需要确保已安装 Windows Update KB2533623(安装程序也已对此进行了验证)。 (由 Steve Dower 在bpo-36085中贡献。)

  • 与 pgen 相关的头文件和Function在用纯 Python 实现替换后已删除。 (由 Pablo Galindo 在bpo-36623中贡献。)

  • types.CodeType在构造函数的第二个位置(* posonlyargcount )具有一个新参数,以支持 PEP 570中定义的仅位置参数。现在,第一个参数( argcount *)表示位置参数(包括仅位置参数)的总数。 types.CodeType的新replace()方法可用于使代码面向 Future。

C API 的更改

  • PyCompilerFlags结构有一个新的* cf_feature_version 字段。应该将其初始化为PY_MINOR_VERSION。默认情况下,该字段将被忽略,并且仅当在 cf_flags *中设置PyCF_ONLY_AST标志时才使用该字段。 (由 Guido van Rossum 在bpo-35766中贡献。)

  • PyEval_ReInitThreads()函数已从 C API 中删除。不应显式调用它:改为使用PyOS_AfterFork_Child()。 (由 Victor Stinner 在bpo-36728中贡献。)

  • 在 Unix 上,除了 Android 和 Cygwin 之外,C 扩展不再链接到 libpython。嵌入 Python 时,不得将RTLD_LOCAL加载libpython,而应使用RTLD_GLOBAL加载。以前,使用RTLD_LOCAL不可能加载未链接到libpython的 C 扩展,例如Modules/Setup*shared*部分构建的标准库的 C 扩展。 (由 Victor Stinner 在bpo-21536中贡献。)

  • 在未定义PY_SSIZE_T_CLEAN的情况下使用#格式的变体来解析或构建值(例如PyArg_ParseTuple()Py_BuildValue()PyObject_CallFunction()等)会提高DeprecationWarning。它将在 3.10 或 4.0 中删除。阅读解析参数和构建值了解详细信息。 (由 Inada Naoki 在bpo-36381中贡献。)

  • 堆分配类型的实例(例如使用PyType_FromSpec()创建的实例)持有对其类型对象的引用。这些类型对象的引用计数增加已从PyType_GenericAlloc()移至更底层的函数PyObject_Init()PyObject_INIT()。这使得passPyType_FromSpec()创建的类型的行为类似于托管代码中的其他类。

静态分配的类型不受影响。

在绝大多数情况下,应该没有副作用。但是,在分配实例后手动增加引用计数的类型(也许可以解决错误)现在可能会变得不朽。为了避免这种情况,这些类需要在实例释放期间在类型对象上调用 Py_DECREF。

要将这些类型正确移植到 3.8 中,请应用以下更改:

Example:

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函数都会减少类型的引用计数。

Example:

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
}

(由 Eddie Elizondo 在bpo-35810中贡献。)

  • Py_DEPRECATED()宏已为 MSVC 实现。现在必须将宏放在符号名称之前。

Example:

Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);

(由 Zackery Spytz 在bpo-33407中贡献。)

(由bpo-32388中的 Antoine Pitrou 提供。)

  • PyCode_New()在第二个位置具有一个新参数(* posonlyargcount *)以支持 PEP 570,指示仅位置参数的数量。

  • 现在,函数PyNode_AddChild()PyParser_AddToken()接受两个附加的int参数* end_lineno end_col_offset *。

  • 常规 Windows 发行版中不再包含用于允许 MinGW 工具直接针对python38.dll链接的libpython38.a文件。如果需要此文件,则可以使用gendefdlltool工具生成该文件,它们是 MinGW binutils 软件包的一部分:

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目录。

(由 Steve Dower 在bpo-37351中贡献。)

CPython 字节码更改

  • pass将展开堆栈的逻辑移到编译器中,简化了解释器循环。现在,编译器发出显式指令,用于调整值的堆栈并调用breakcontinuereturn的清理代码。

已删除操作码BREAK_LOOPCONTINUE_LOOPSETUP_LOOPSETUP_EXCEPT。添加了新的操作码ROT_FOURBEGIN_FINALLYCALL_FINALLYPOP_FINALLY。更改了END_FINALLYWITH_CLEANUP_START的行为。

(由 Mark Shannon,Antoine Pitrou 和 Serhiy Storchaka 在bpo-17611中贡献。)

  • 添加了新的操作码END_ASYNC_FOR,用于处理在async for循环中 await 下一个项目时引发的异常。 (由 Serhiy Storchaka 在bpo-33041中贡献。)

  • MAP_ADD现在期望值是堆栈中的第一个元素,而键则是第二个元素。进行了此更改,以便始终按 PEP 572的建议在字典理解中的值之前对键进行评估。 (由 JörnHeissler 在bpo-35224中贡献。)

演示和工具

添加了一个基准脚本,用于计时各种访问变量的方式:Tools/scripts/var_access_benchmark.py。 (由 Raymond Hettinger 在bpo-35884中贡献。)

以下是自 Python 3.3 以来的性能改进摘要:

Python version                       3.3     3.4     3.5     3.6     3.7     3.8
--------------                       ---     ---     ---     ---     ---     ---

Variable and attribute read access:
    read_local                       4.0     7.1     7.1     5.4     5.1     3.9
    read_nonlocal                    5.3     7.1     8.1     5.8     5.4     4.4
    read_global                     13.3    15.5    19.0    14.3    13.6     7.6
    read_builtin                    20.0    21.1    21.6    18.5    19.0     7.5
    read_classvar_from_class        20.5    25.6    26.5    20.7    19.5    18.4
    read_classvar_from_instance     18.5    22.8    23.5    18.8    17.1    16.4
    read_instancevar                26.8    32.4    33.1    28.0    26.3    25.4
    read_instancevar_slots          23.7    27.8    31.3    20.8    20.8    20.2
    read_namedtuple                 68.5    73.8    57.5    45.0    46.8    18.4
    read_boundmethod                29.8    37.6    37.9    29.6    26.9    27.7

Variable and attribute write access:
    write_local                      4.6     8.7     9.3     5.5     5.3     4.3
    write_nonlocal                   7.3    10.5    11.1     5.6     5.5     4.7
    write_global                    15.9    19.7    21.2    18.0    18.0    15.8
    write_classvar                  81.9    92.9    96.0   104.6   102.1    39.2
    write_instancevar               36.4    44.6    45.8    40.0    38.9    35.5
    write_instancevar_slots         28.7    35.6    36.1    27.3    26.6    25.7

Data structure read access:
    read_list                       19.2    24.2    24.5    20.8    20.8    19.0
    read_deque                      19.9    24.7    25.5    20.2    20.6    19.8
    read_dict                       19.7    24.3    25.7    22.3    23.0    21.0
    read_strdict                    17.9    22.6    24.3    19.5    21.2    18.9

Data structure write access:
    write_list                      21.2    27.1    28.5    22.5    21.6    20.0
    write_deque                     23.8    28.7    30.1    22.7    21.8    23.5
    write_dict                      25.9    31.4    33.3    29.3    29.2    24.7
    write_strdict                   22.9    28.4    29.9    27.5    25.2    23.1

Stack (or queue) operations:
    list_append_pop                144.2    93.4   112.7    75.4    74.2    50.8
    deque_append_pop                30.4    43.5    57.0    49.4    49.2    42.5
    deque_append_popleft            30.8    43.7    57.3    49.7    49.7    42.8

Timing loop:
    loop_overhead                    0.3     0.5     0.6     0.4     0.3     0.3

在运行python.org的 macOS 64 位版本的英特尔®酷睿™i7-4960HQ 处理器上测量了基准。基准脚本以纳秒为单位显示计时。

Python 3.8.1 中的重大更改

由于重大安全问题,不再支持asyncio.loop.create_datagram_endpoint()的* reuse_address *参数。这是因为 UDP 中套接字选项SO_REUSEADDR的行为。有关更多详细信息,请参见loop.create_datagram_endpoint()的文档。 (由bpo-37228中的 Kyle Stanley,Antoine Pitrou 和 Yury Selivanov 贡献。)

Python 3.8.2 中的重大更改

修复了ignore回调为shutil.copytree()的回归。现在,参数类型分别为 str 和 List [str]。 (由 Manuel Barkhau 和 Giampaolo Rodola 在bpo-39390中贡献。)

Python 3.8.3 中的重大更改

future模块中将来标志的常量值将更新,以防止与编译器标志冲突。以前PyCF_ALLOW_TOP_LEVEL_AWAITCO_FUTURE_DIVISION冲突。 (由 Batuhan Taskaya 在bpo-39562中贡献)