unittest

增加了 --durations 命令行选项,显示 N 个最慢的测试用例:

  1. python3 -m unittest --durations=3 lib.tests.test_threading
  2. .....
  3. Slowest test durations
  4. ----------------------------------------------------------------------
  5. 1.210s test_timeout (Lib.test.test_threading.BarrierTests)
  6. 1.003s test_default_timeout (Lib.test.test_threading.BarrierTests)
  7. 0.518s test_timeout (Lib.test.test_threading.EventTests)
  8.  
  9. (0.000 durations hidden. Use -v to show these durations.)
  10. ----------------------------------------------------------------------
  11. Ran 158 tests in 9.869s
  12.  
  13. OK (skipped=3)

(由 Giampaolo Rodola 在 gh-48330 [https://github.com/python/cpython/issues/48330] 中贡献。)

uuid

性能优化

CPython 字节码的改变

演示和工具

弃用

  • argparse: argparse.BooleanOptionalAction 的 type, choices 和 metavar 形参已被弃用并将在 3.14 中移除。 (由 Nikita Sobolev 在 gh-92248 [https://github.com/python/cpython/issues/92248] 中贡献。)

  • ast: 以下 ast 特性自 Python 3.8 起已在文档中声明弃用,现在当运行时如果它们被访问或使用将发出 DeprecationWarning,并将在 Python 3.14 中移除:

    • ast.Num

    • ast.Str

    • ast.Bytes

    • ast.NameConstant

    • ast.Ellipsis

请改用 ast.Constant。 (由 Serhiy Storchaka 在 gh-90953 [https://github.com/python/cpython/issues/90953] 中贡献。)

使用 importlib.resources.abc 类代替:

(由 Jason R. Coombs 和 Hugo van Kemenade 在 gh-93963 [https://github.com/python/cpython/issues/93963] 中贡献。)

当由于使用 multiprocessingconcurrent.futures 而出现此警告时的解决办法是使用其他的 multiprocessing 启动方法如 "spawn""forkserver"

计划在 Python 3.13 中移除

模块 (参见 PEP 594 [https://peps.python.org/pep-0594/]):

  • aifc

  • audioop

  • cgi

  • cgitb

  • chunk

  • crypt

  • imghdr

  • mailcap

  • msilib

  • nis

  • nntplib

  • ossaudiodev

  • pipes

  • sndhdr

  • spwd

  • sunau

  • telnetlib

  • uu

  • xdrlib

其他模块:

API:

改用 importlib.resources.files()。 参见 importlib-resources: Migrating from Legacy [https://importlib-resources.readthedocs.io/en/latest/using.html#migrating-from-legacy] (gh-106531 [https://github.com/python/cpython/issues/106531])

计划在 Python 3.14 中移除

  • argparse: argparse.BooleanOptionalAction 的 type, choices 和 metavar 形参已被弃用并将在 3.14 中移除。 (由 Nikita Sobolev 在 gh-92248 [https://github.com/python/cpython/issues/92248] 中贡献。)

  • ast: 以下特性自 Python 3.8 起已在文档中声明弃用,现在当运行时如果它们被访问或使用时将发出 DeprecationWarning,并将在 Python 3.14 中移除:

    • ast.Num

    • ast.Str

    • ast.Bytes

    • ast.NameConstant

    • ast.Ellipsis

请改用 ast.Constant。 (由 Serhiy Storchaka 在 gh-90953 [https://github.com/python/cpython/issues/90953] 中贡献。)

使用 importlib.resources.abc 类代替:

(由 Jason R. Coombs 和 Hugo van Kemenade 在 gh-93963 [https://github.com/python/cpython/issues/93963] 中贡献。)

Python 3.15 中的待移除功能

计划在 Python 3.16 中移除

  • 导入系统:

    • 当设置 __spec__.loader 失败时在模块上设置 __loader__ 的做法已被弃用。 在 Python 3.16 中,__loader__ 将不会再被设置或是被导入系统或标准库纳入考虑。
  • array:

    • 'u' 格式代码 (wchar_t) 自 Python 3.3 起已在文档中弃用并自 Python 3.13 起在运行时弃用。 对于 Unicode 字符请改用 'w' 格式代码 (Py_UCS4)。
  • asyncio:

  • builtins:

    • 对布尔类型 ~True~False 执行按位取反的操作自 Python 3.12 起已被弃用,因为它会产生奇怪和不直观的结果 (-2 and -1)。 请改用 not x 来对布尔值执行逻辑否操作。 对于需要对下层整数执行按位取反操作的少数场合,请显式地将其转换为 int (~int(x))。
  • shutil:

    • ExecError 异常自 Python 3.14 起已被弃用。 它自 Python 3.4 起就未被 shutil 中的任何函数所使用,现在是 RuntimeError 的一个别名。
  • symtable:

  • sys:

  • tarfile:

    • 未写入文档也未被使用的 TarFile.tarfile 属性自 Python 3.13 起被弃用。

计划在未来版本中移除

以下API将会被移除,尽管具体时间还未确定。

移除

asynchat 和 asyncore

configparser

distutils

ensurepip

  • ensurepip 中移除了捆绑的 setuptools wheel,并停止在由 venv 创建的环境中安装 setuptools。

pip (>= 22.1) 不再要求在环境中安装 setuptools。 基于 setuptools (和基于 distutils) 的包仍然可通过 pip install 来使用,因为 pip 将在它用于构建包的构建环境中提供 setuptools

在默认情况下由 venv 创建或通过 ensurepip 初始化的环境将不再提供 easy_install, pkg_resources, setuptoolsdistutils 包,因为它们是 setuptools 包的组成部分。 对于在运行时依赖这些包的项目,应当将 setuptools 项目声明为依赖项之一并单独安装(通常是使用 pip)。

(由 Pradyun Gedam 在 gh-95299 [https://github.com/python/cpython/issues/95299] 中贡献。)

enum

ftplib

gzip

hashlib

importlib

imp

要进行迁移,请参考以下对照表:

imp

importlib

imp.NullImporter

None 插入到 sys.path_importer_cache

imp.cache_from_source()

importlib.util.cache_from_source()

imp.find_module()

importlib.util.find_spec()

imp.get_magic()

importlib.util.MAGIC_NUMBER

imp.get_suffixes()

importlib.machinery.SOURCE_SUFFIXES, importlib.machinery.EXTENSION_SUFFIXESimportlib.machinery.BYTECODE_SUFFIXES

imp.get_tag()

sys.implementation.cache_tag

imp.load_module()

importlib.import_module()

imp.new_module(name)

types.ModuleType(name)

imp.reload()

importlib.reload()

imp.source_from_cache()

importlib.util.source_from_cache()

imp.load_source()

见下文

imp.load_source() 替换为:

  1. import importlib.util
  2. import importlib.machinery
  3.  
  4. def load_source(modname, filename):
  5. loader = importlib.machinery.SourceFileLoader(modname, filename)
  6. spec = importlib.util.spec_from_file_location(modname, filename, loader=loader)
  7. module = importlib.util.module_from_spec(spec)
  8. # 模块将总是被执行而不缓存在 sys.modules 中。
  9. # 取消对下一行的注释以缓存此模块。
  10. # sys.modules[module.__name__] = module
  11. loader.exec_module(module)
  12. return module
  • 已移除 imp 的函数和属性并且没有替代选项:

    • 未写入文档的函数:

      • imp.init_builtin()

      • imp.load_compiled()

      • imp.load_dynamic()

      • imp.load_package()

    • imp.lock_held(),imp.acquire_lock(),imp.release_lock(): 加锁方案在 Python 3.3 中已改为模块级锁。

    • imp.find_module() 常量: SEARCH_ERROR, PY_SOURCE, PY_COMPILED, C_EXTENSION, PY_RESOURCE, PKG_DIRECTORY, C_BUILTIN, PY_FROZEN, PY_CODERESOURCE, IMP_HOOK

io

locale

smtpd

sqlite3

  • 以下未写入文档的 sqlite3 特性,在 Python 3.10 中已被弃用,现在已被移除:

    • sqlite3.enable_shared_cache()

    • sqlite3.OptimizedUnicode

如果必须使用共享缓存,请在以 URI 模式打开数据库时使用 cache=shared 查询参数。

sqlite3.OptimizedUnicode 文本工厂函数自 Python 3.3 起已成为 str 的一个别名。 之前将文本工厂设为 OptimizedUnicode 的代码可以显式地使用 str,或者依赖同样为 str 的默认值。

(由 Erlend E. Aasland 在 gh-92548 [https://github.com/python/cpython/issues/92548] 中贡献。)

ssl

unittest

  • 移除了许多早已弃用的 unittest 特性:

已弃用的别名

方法名

弃用于

failUnless

assertTrue()

3.1

failIf

assertFalse()

3.1

failUnlessEqual

assertEqual()

3.1

failIfEqual

assertNotEqual()

3.1

failUnlessAlmostEqual

assertAlmostEqual()

3.1

failIfAlmostEqual

assertNotAlmostEqual()

3.1

failUnlessRaises

assertRaises()

3.1

assert_

assertTrue()

3.2

assertEquals

assertEqual()

3.2

assertNotEquals

assertNotEqual()

3.2

assertAlmostEquals

assertAlmostEqual()

3.2

assertNotAlmostEquals

assertNotAlmostEqual()

3.2

assertRegexpMatches

assertRegex()

3.2

assertRaisesRegexp

assertRaisesRegex()

3.2

assertNotRegexpMatches

assertNotRegex()

3.5

您可以使用 https://github.com/isidentical/teyit 来自动更新你的单元测试。

  • 未写入文档且已不可用的 TestCase 方法 assertDictContainsSubset。 (在 Python 3.2 中已弃用。)

  • 未写入文档的 TestLoader.loadTestsFromModule 形参 use_load_tests。 (自 Python 3.5 起已弃用并会被忽略。)

  • TextTestResult 类的一个别名: _TextTestResult。 (在 Python 3.2 中已弃用。)

(由 Serhiy Storchaka 在 gh-89325 [https://github.com/python/cpython/issues/89325] 中贡献。)

webbrowser

xml.etree.ElementTree

zipimport

其他事项

移植到 Python 3.12

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

Python API 的变化

  1. 1,0-1,18: STRING 'f"start {1+1} end"'

而新版本将生成:

  1. 1,0-1,2: FSTRING_START 'f"'
  2. 1,2-1,8: FSTRING_MIDDLE 'start '
  3. 1,8-1,9: OP '{'
  4. 1,9-1,10: NUMBER '1'
  5. 1,10-1,11: OP '+'
  6. 1,11-1,12: NUMBER '1'
  7. 1,12-1,13: OP '}'
  8. 1,13-1,17: FSTRING_MIDDLE ' end'
  9. 1,17-1,18: FSTRING_END '"'

此外,支持 PEP 701 [https://peps.python.org/pep-0701/] 所需的改变还可能会导致一些细微的行为改变。 这些变化包括:

  • 在对一些无效 Python 字符如 ! 进行分词时相应词元的 type 属性已从 ERRORTOKEN 变为 OP

  • 不完整的单行字符串现在也会像不完整的多行字符串一样引发 tokenize.TokenError

  • 某些不完整或无效的 Python 代码现在会引发 tokenize.TokenError 而不是在执行分词时返回任意的 ERRORTOKEN 词元。

  • 在同一文件中混合使用制表符和空格作为缩进不再受到支持而是会引发 TabError

  • 现在 threading 模块会预期 _thread 模块具有 _is_main_interpreter 属性。 它是一个不带参数的函数并会在当前解释器为主解释器时返回 True

任何提供了自定义 _thread 模块的库或应用程序都应当提供 _is_main_interpreter()。 (参见 gh-112826 [https://github.com/python/cpython/issues/112826]。)

构建变化

  • Python 不再使用 setup.py 来构建共享的 C 扩展模块。 头文件和库等编译参数在 configure 脚本中检测。 扩展将由 Makefile 来构建。 大多数扩展使用 pkg-config 并回退为手动检测。 (由 Christian Heimes 在 gh-93939 [https://github.com/python/cpython/issues/93939] 中贡献。)

  • 现在需要用带有两个形参的 va_start(),如 va_start(args, format), 来构建 Python。 现在将不会再调用单个形参的 va_start()。 (由 Kumar Aditya 在 gh-93207 [https://github.com/python/cpython/issues/93207] 中贡献。)

  • 现在如果 Clang 编译器接受 ThinLTO 选项则 CPython 会将其作为默认的链接时间优化策略。 (由 Donghee Na 在 gh-89536 [https://github.com/python/cpython/issues/89536] 中贡献。)

  • Makefile 中添加了 COMPILEALL_OPTS 变量以覆盖 make install 中的 compileall 选项 (默认值: -j0)。 并将 3 条 compileall 命令合并为单条命令以便一次性构建所有优化级别 (0, 1, 2) 的 .pyc 文件。 (由 Victor Stinner 在 gh-99289 [https://github.com/python/cpython/issues/99289] 中贡献。)

  • 为 64 位 LoongArch 添加了平台三选项:

    • loongarch64-linux-gnusf

    • loongarch64-linux-gnuf32

    • loongarch64-linux-gnu

(由 Zhang Na 在 gh-90656 [https://github.com/python/cpython/issues/90656] 中贡献。).)

  • PYTHON_FOR_REGEN 现在需要 Python 3.10 或更新版本。

  • 现在需要有 autoconf 2.71 和 aclocal 1.16.4 才能重新生成 !configure。 (由 Christian Heimes 在 gh-89886 [https://github.com/python/cpython/issues/89886] 中贡献。)

  • 来自 python.org 的 Windows 版本和 macOS 安装程序现在使用 OpenSSL 3.0。

C API 的变化

新的特性

代码对象构造器:

  • PyUnstable_Code_New() (由 PyCode_New 改名而来)

  • PyUnstable_Code_NewWithPosOnlyArgs() (由 PyCode_NewWithPosOnlyArgs 改名而来)

代码对象的额外存储 ( PEP 523 [https://peps.python.org/pep-0523/]):

  • PyUnstable_Eval_RequestCodeExtraIndex() (由 PyEvalRequestCodeExtraIndex 改名而来)

  • PyUnstable_Code_GetExtra() (由 PyCodeGetExtra 改名而来)

  • PyUnstable_Code_SetExtra() (由 PyCodeSetExtra 改名而来)

原有名称将继续可用直到对应的 API 发生改变。

(由 Petr Viktorin 在 gh-101101 [https://github.com/python/cpython/issues/101101] 中贡献。)

(由 Petr Viktorin 在 gh-103509 [https://github.com/python/cpython/issues/103509] 中贡献。)

现在当一个类的 __call__() 方法被重新赋值时,该类的 Py_TPFLAGS_HAVE_VECTORCALL 旗标将被移除。 这使得 vectorcall 可以安全地用于可变类型(即没有不可变旗标 Py_TPFLAGS_IMMUTABLETYPE 的堆类型)。 未重载 tp_call 的可变类型现在继承了 Py_TPFLAGS_HAVE_VECTORCALL 旗标。 (由 Petr Viktorin 在 gh-93274 [https://github.com/python/cpython/issues/93274] 中贡献。)

新增了 Py_TPFLAGS_MANAGED_DICTPy_TPFLAGS_MANAGED_WEAKREF 旗标。 这将允许扩展类以更少的记录消耗来支持对象 __dict__ 和弱引用,占用更少内存并加快访问速度。

这意味着 vectorcall 调用协议的传入端和传出端现在都可以在 受限 API 中使用。 (由 Wenzel Jakob 在 gh-98586 [https://github.com/python/cpython/issues/98586] 中贡献。)

  • PEP 683 [https://peps.python.org/pep-0683/]: 引入了 永生对象,它允许对象绕过引用计数,并对 C-API 进行相应修改:

      • PyIMMORTAL_REFCNT: 定义对象的引用计数
      • 为永生对象。
    • PyIsImmortal 检测一个对象是否具有永生引用计数。

      • PyObject_HEAD_INIT 这将把引用计数初始化为
      • PyIMMORTAL_REFCNT 当配合 Py_BUILD_CORE 使用时。
      • SSTATE_INTERNED_IMMORTAL 一个针对内部 unicode 对象的标识符
      • 为永生对象。
      • SSTATE_INTERNED_IMMORTAL_STATIC 一个针对内部 unicode
      • 为永生且静态的对象
      • sys.getunicodeinternedsize 这将返回总计的 unicode
      • 被管理的对象。现在 refleak.py 需要这样才能正确地追踪引用计数和分配的块

(由 Eddie Elizondo 在 gh-84436 [https://github.com/python/cpython/issues/84436] 中贡献。)

移植到 Python 3.12

  • 基于 Py_UNICODE* 表示形式的旧式 Unicode API 已被移除。 请迁移到基于 UTF-8 或 wchar_t* 的 API。

  • PyArg_ParseTuple() 等参数解析函数不再支持基于 Py_UNICODE* 的格式(例如 u, Z 等)。 请迁移到其他 Unicode 格式如 s, z, esU

  • tp_weaklist 对于所有静态内置类型将始终为 NULL。 这是 PyTypeObject 上的一个内部专属字段,但我们还是要指出这一变化以防有人碰巧仍然直接访问到该字段。 为避免出现中断,请考虑改用现有的公共 C-API,或在必要时使用(仅限内部使用的)宏 PyObjectGET_WEAKREFS_LISTPTR()

  • 现在这个内部专用的 PyTypeObject.tp_subclasses 可能不是一个有效的对象指针。 为了反映这一点我们将其类型改为 void*。 我们提到这一点是为了防止有人碰巧直接访问到这个内部专用字段。

要获取子类的列表,可调用 Python 方法 __subclasses__() (例如使用 PyObject_CallMethod())。

创建具有重载了 tp_new 的元类的类的做法已被弃用,在 Python 3.14+ 中将被禁止。 请注意这些函数会忽略元类的 tp_new,从而可能导致不完整的初始化。

请注意 PyType_FromMetaclass() (在 Python 3.12 中新增) 已禁止创建具有重载了 tp_new (在 Python 中为 __new__() ) 的元类的类。

由于 tp_new 重载了PyType_From* 函数的几乎所有内容,因此两者互不兼容。 现有的行为 — 在创建类型的一些步骤中忽略元类 — 通常都是不安全的,因为(元)类会假定 tp_new 已被调用。 目前还没有简单通用的绕过方式。 以下办法之一可能对你有用:

  • 如果你控制着元类,请避免在其中使用 tp_new:

    • 如初始化可被跳过,则可以改在 tp_init 中完成。

    • 如果元类不需要从 Python 执行实例化,则使用 Py_TPFLAGS_DISALLOW_INSTANTIATION 旗标将其 tp_new 设为 NULL。 这将使其可被 PyType_From* 函数接受。

  • 避免使用 PyType_From* 函数:如果不需要 C 专属的特性(槽位或设置实例大小),请通过 调用 元类来创建类型。

  • 如果你 知道 可以安全地跳过 tp_new,就使用 Python 中的 warnings.catch_warnings() 过滤掉弃用警告。

这也避免了扩展程序在不支持(或尚未被加载)的子解释器中运行的情况。 请参阅 gh-104668 [https://github.com/python/cpython/issues/104668] 了解更多信息。

  • PyLongObject 对其内部字段进行了修改以提高性能。 虽然 PyLongObject 的内部字段是私有的,但某些扩展模块会使用它们。 内部字段不应再被直接访问,而应改用以 PyLong_… 打头的 API 函数。 新增了两个 暂定 API 函数用于高效访问适配至单个机器字的 PyLongObject 的值:

  • 通过 PyMem_SetAllocator() 设置的自定义分配器现在必须是线程安全的,无论内存域是什么。 没有自己的状态的分配器,包括“钩子”将不会受影响。 如果你的自定义分配器还不是线程安全的且你需要指导则请创建一个新的 GitHub 问题并抄送给 @ericsnowcurrently

弃用

Py_InitializeFromConfig() API 应当改为使用 PyConfig。 (由 Victor Stinner 在 gh-77782 [https://github.com/python/cpython/issues/77782] 中贡献。)

现在只需包括 Python.h 即可获得其内容,如果找不到请添加 Py 前缀:

Python.h 上有几个项目没有暴露:

  • T_OBJECT (使用 Py_T_OBJECT_EX)

  • T_NONE (之前未写入文档,并且相当怪异)

  • 不进行任何操作的宏 WRITE_RESTRICTED

  • RESTRICTEDREAD_RESTRICTED 宏,等同于 Py_AUDIT_READ

  • 在某些配置中, Python.h 未包含 。使用 offsetof() 时,应手动将其包含在内。

已被弃用的头文件将继续以原来的名称提供原来的内容。 你的旧代码可以保持不变,除非额外的包括指令和无命名空间宏会给你带来很大困扰。

(由 Petr Viktorin 在 gh-47146 [https://github.com/python/cpython/issues/47146] 中贡献,基于 Alexander Belopolsky 和 Matthias Braun 在先前的工作。).)

计划在 Python 3.14 中移除

Py_InitializeFromConfig() API 应与 PyConfig 一起使用。

Py_InitializeFromConfig() API 应与 PyConfig 一起使用。

Python 3.15 中的待移除功能

计划在未来版本中移除

以下 API 已被弃用,将被移除,但目前尚未确定移除日期。

移除