暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Python 3.12中的最佳新功能和修复

云原生数据库 2023-05-27
300

Python编程语言每年发布新版本,上半年发布功能锁定的测试版,年底发布正式版。

Python 3.12 beta 1刚刚发布。鼓励开发人员在非生产代码中尝试这个最新版本,既可以验证它是否与您的程序兼容,也可以了解您的代码是否能从这个最新版本中的新功能集和性能提升中受益。

下面是Python 3.12中最重要的新功能的概述以及它们对Python开发人员的意义。

更好的错误消息 

在最近的Python版本中,错误消息变得更加精确(显示在行中的确切位置)和详细(提供更好的关于可能出错的建议)。Python 3.12带来了额外的增强功能:

对于缺少的模块,现在的建议中包括来自标准库的模块("您是否忘记导入X?")。

对于常见的导入语法错误,现在提供更好的错误建议;例如,import p from m 会返回一个错误提示,询问您是否想要使用 from m import p。

对于给定模块的导入错误,现在的建议中包括来自导入的模块的命名空间中的建议。

在类实例内部引发NameError时,建议中也会在名称前面加上self.(例如,name 'speed' is not defined. Did you mean 'self.speed'?)。这是因为在类实例中省略self作为实例变量的常见错误来源。

对Linux perf性能分析工具的支持

广泛使用的Linux性能分析工具perf可以与Python一起工作,但只返回Python运行时中C级别的信息。实际的Python程序函数的信息不会显示出来。

Python 3.12启用了一个可选择的模式,允许perf收集有关Python程序的详细信息。这个可选择的模式可以在环境级别或在Python程序中使用sys.activate_stack_trampoline函数来设置。

更快的调试/性能监控 

对Python程序运行调试器或附加调试器可以让您看到程序的运行情况,并深入了解其运行过程。但这也会带来性能损耗。在通过调试器或性能分析工具运行程序时,程序的运行速度可能会慢上一个数量级。

PEP 669为代码对象事件提供了挂钩,这些事件可以供性能分析工具和调试器附加使用,例如函数的开始或结束。工具可以注册一个回调函数,以便在触发此类事件时触发。虽然进行性能分析或调试仍会有一定的性能损耗,但这种损耗会大大降低。

缓冲区协议的双下划线方法 

Python的缓冲区协议提供了一种访问由许多Python对象(如bytes或bytearray)包装的原始内存区域的方法。但大多数与缓冲区协议的交互是通过C扩展来进行的。直到现在,Python代码无法知道给定对象是否支持缓冲区协议,也无法将代码类型注释为与该协议兼容。

PEP 688为对象实现了新的双下划线方法,允许Python代码与缓冲区协议一起工作。这使得在Python中编写公开其数据缓冲区的对象变得更加容易,而无需使用C语言编写这些对象。__buffer__方法用于分配新内存或简单访问现有内存,它返回一个memoryview对象。__release_buffer__方法用于释放缓冲区所使用的内存。

目前,PEP 688方法没有办法指示给定缓冲区是否为只读的,这在处理像bytes这样的不可变对象的数据时非常有用。但如果需要,可以随时添加这个功能。

类型提示改进 

Python的类型提示语法从Python 3.5开始引入,它允许静态分析工具在代码运行之前捕获各种错误。随着每个新版本的发布,Python的类型提示功能也得到不断改进,覆盖范围更广、更精细。

TypedDict 

在Python 3.12中,您可以使用TypedDict来作为函数中用于提示关键字参数的类型来源。在这方面,使用了在3.11版本中引入的可变长度通用类型。以下是相关PEP中的示例:

    class Movie(TypedDict):
    name: str
    year: int


    def foo(**kwargs: Unpack[Movie]) -> None: ...

    在这个示例中,foo函数可以接受与Movie内容匹配的关键字参数,比如name:str和year:int。这在对不带默认值的可选关键字参数进行类型提示的函数中非常有用。

    类型参数语法

    类型参数语法提供了一种更清晰的方式来指定泛型类、函数或类型别名中的类型。以下是从PEP中摘取的一个示例:

      # the old method 


      from typing import TypeVar


      _T = TypeVar("_T")


      def func(a: _T, b: _T) -> _T:
      ...


      # the new type parameter method


      def func[T](a: T, b: T) -> T:
      ...

      使用新的方法时,不需要导入TypeVar。可以直接使用func[T]的语法来表示泛型类型引用。还可以指定类型边界,比如一个给定类型是否属于一组类型之一,尽管这样的类型本身不能是泛型。一个示例是func[T: (str,int)]。

      最后,新的@override装饰器可以用于标记覆盖父类方法的方法,以确保在重构(重命名或删除)父类方法时,对其子类也进行相应的更改。

      性能改进 

      随着Python 3.11的推出,一系列相关项目开始着手改进Python的性能,每个新版本都带来了显著的性能提升。尽管Python 3.12的性能改进不如之前那么引人注目,但仍值得注意。

      内联推导式 

      推导式是一种语法,可以快速构造列表、字典和集合。现在,推导式是通过内联方式构造,而不是通过临时对象。这种改进在实际案例中的速度提升约为11%,在微基准测试中甚至可以提升两倍。

      不朽对象 

      Python中的每个对象都有一个引用计数,用于跟踪其他对象对其的引用次数,包括None等内置对象。PEP 683允许将对象视为"不朽",使其引用计数永远不会改变。

      将对象标记为不朽在长期运行中对Python有其他重要的影响。它使得实现多核扩展更加容易,并且可以实现其他优化(比如避免写时复制),这些优化在之前很难实现。

      更小的对象大小 

      在早期版本的Python中,对象的基本大小为208字节。在过去几个Python版本中,对象进行了多次重构,使其更小,这不仅允许更多的对象存在于内存中,还有助于提高缓存的局部性。截至Python 3.12,对象的基本大小现在是96字节,不到以前的一半。

      子解释器 

      Python一直期待的一个功能是子解释器,即在单个Python进程内同时运行多个解释器实例,每个解释器实例都有自己的全局解释器锁(GIL)。这将是Python在并行性方面迈出的重要一步。

      然而,Python 3.12只包含了使子解释器成为可能的CPython内部机制。目前还没有面向最终用户的子解释器接口。预计Python 3.13将引入一个名为"interpreters"的标准库模块来提供子解释器的功能。

      其他变化 

      除了前面讨论的重大改进之外,Python 3.12还引入了许多其他细微的变化。以下是一个快速查看。

      不稳定的API 

      一个重要的项目是对CPython内部结构的重构,特别是其API集合,以减少暴露给外部的低级函数。Python 3.12引入了不稳定的API层级,这是一组被明确标记为可能在版本之间发生变化的API集合。它不打算被大多数C扩展使用,而是为调试器或JIT编译器等低级工具使用。

      标准库的废弃和移除 

      在3.11版本中,许多早已被标为过时(所谓的dead batteries)的标准库模块已被标记为在Python 3.12和3.13中将被移除。在3.12版本中,最大的移除是distutils模块,因为setuptools早已取代了它。其他在此版本中移除的模块包括asynchat、asyncore(均被asyncio替代)和smtpd。

      垃圾回收 

      Python的垃圾回收机制(GC)过去可以在分配对象时运行。从Python 3.12开始,GC仅在Python字节码循环中的"eval breaker"机制之间运行,也就是在执行一个字节码和下一个字节码之间。它还在调用CPython的信号处理程序检查机制时运行。这样可以使GC定期运行于运行时间外的长时间调用到C扩展上。


      文章转载自云原生数据库,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论