热烈欢迎Python3.7的到来


今年六月底的时候,经过多轮测试和评估审核,Python 官方终于发布了 Python3.7 的正式版,增强了多处特性功能。本次更新,主要是为了解决编程过程中遇到的难点和痛点,所以我们应该多多学习和关注。

热烈欢迎Python3.7的到来


1. 主要特性

新版本中共新增了9PEP 标准,并没有特别惊艳的改变,下面主要介绍一些语法和写法上的新变化。

  • PEP 539
    • 新增 CPython 中用于线程本地存储的 C-API
  • PEP 545
    • 官方文档中新增日文、法文、韩文翻译版本,就是没有中文
  • PEP 552
    • 优化 pyc 文件
  • PEP 553
    • 新增内置函数 breakpoint(),该函数在调用时自动进入调试器
  • PEP 557
    • 新增内置模块dataclasses,可大幅简化类实例属性的初始化定义
  • PEP 560
    • 新增支持类型模块和泛型
  • PEP 562
    • 支持在模块定义 __getattr____dir__
  • PEP 563
    • 推迟对注释语句的分析从而优化 Python 的类型提示
  • PEP 564
    • time 内置函数支持纳秒
  • PEP 565
    • 重新在 __main__ 中默认显示 DeprecationWarning
  • PEP 567
    • 新增 contextvars模块,可实现上下文变量解决变量线程安全

另外还有三处发生了变动,**[1] 避免使用 ASCII 作为默认文本编码,强制 UTF-8 编码运行[2] 字典对象的 keys 按插入顺序排列,现在是官方语言规范[3] 多方面的显著性能优化**,可见对应该版本主要是对编程中的痛点和性能做了优化和改进。


2. 特性详解

  • PEP-553 内置断点支持

以前使用 pdb 的时候,需要导入pdb模块(import pdb)之后设置 pdb.set_trace(),现在使用内置的 breakpoint() 函数可以快速中断。同时,breakpoint() 可以使用任意的调试工具,这也方便了在调试代码时的扩展。你可以通过 PYTHONBREAKPOINT=0 环境变量禁用这个功能。

  • PEP-562 限制访问模块的属性

我们之前在编写 Python 模块时,通常无法限制使用者使用内部的属性,比较典型的例子是在管理失效警告时。新的语法通过对模块添加 __getattr____dir__,可以实现限制访问/提醒失效目的。

假如需要失效部分方法时,我们需要在使用之前进行提醒,这里可以使用 __getattr__ d 方法对其进行操作。

# lib.py

from warnings import warn

deprecated_names = ["old_function", ...]

def _deprecated_old_function(arg, other):
    ...

def __getattr__(name):
    if name in deprecated_names:
        warn(f"{name} is deprecated", DeprecationWarning)
        return globals()[f"_deprecated_{name}"]
    raise AttributeError(f"module {__name__} has no attribute {name}")
# main.py

from lib import old_function
# Works, but emits the warning

同样,__dir__也可以用在类似的用途上。

# lib.py

deprecated_names = ['old_function', ...]
__all__ = ['new_function_one', 'new_function_two', ...]

def new_function_one(arg, other):
    ...

def new_function_two(arg, other):
    ...

def __dir__():
    return sorted(__all__ + deprecated_names)
# main.py

import lib
dir(lib)
# ['new_function_one', 'new_function_two', 'old_function', ...]
  • PEP-564 支持 nanosecond 的时间函数

为了方便对 nanosecond 的操作,提供了 6 个新增的函数,分别为 clock_gettime_ns()clock_settime_ns()monotonic_ns()perf_counter_ns()process_time_ns()time_ns()。基本上是在原有函数的基础上添加 _ns 结尾标记,用法也基本相同。

  • PEP-557 数据类装饰器

在新版本中添加了@dataclass装饰器,利用该装饰器可以减少数据类型定义的代码行数。这个特性可能是 3.7.0 以后比较常用的了,是从其他语言借鉴过来的,这里简单演示下用法。

假如,我们要封装一个类对象,在之前我们的代码可能要这么写。

class Article(object):
    def __init__(self, _id, author_id, title, text, tags=None,
                 created=datetime.now(), edited=datetime.now()):
    self._id = _id
    self.author_id = author_id
    self.title = title
    self.text = text
    self.tags = list() if tags is None else tags
    self.created = created
    self.edited = edited

    if type(self.created) is str:
       self.created = dateutil.parser.parse(self.created)

    if type(self.edited) is str:
       self.edited = dateutil.parser.parse(self.edited)

    def __eq__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return (self._id, self.author_id) == (other._id, other.author_id)

    def __lt__(self, other):
        if not isinstance(other, self.__class__):
            return NotImplemented
        return (self._id, self.author_id) < (other._id, other.author_id)

    def __repr__(self):
        return '{}(id={}, author_id={}, title={})'.format(
                self.__class__.__name__, self._id, self.author_id, self.title)

大量的初始化属性要定义默认值,可能还需要重写一堆魔法方法,来实现类实例之间的排序、去重等功能。如果使用dataclass进行改造,可以写成这个样子。这种语法使代码更加简练清晰,也更符合面向对象思想的语法方式,用过 SQLAlchemy 的同学肯定觉得很像 ORM 写法。

@dataclass(order=True)
class Article(object):
    _id: int
    author_id: int
    title: str = field(compare=False)
    text: str = field(repr=False, compare=False)
    tags: List[str] = field(default=list(), repr=False, compare=False)
    created: datetime = field(default=datetime.now(), repr=False, compare=False)
    edited: datetime = field(default=datetime.now(), repr=False, compare=False)

    def __post_init__(self):
       if type(self.created) is str:
           self.created = dateutil.parser.parse(self.created)

       if type(self.edited) is str:
           self.edited = dateutil.parser.parse(self.edited)

3. 扩展补充

  • 性能改进

部分Python3性能都进行了提升,不过都不如关于函数调用的改进最为明显。通过添加LOAD_METHODCALL_METHOD两个opcode,函数调用进行了较大提升。基本上对于2.7版本而言,大部分的性能已经超过,只有少数指标仍旧落后于Python2.7

  • 其他内容

其他的内容,PEP-538PEP-540 均是关于 Python 对于 UTF-8 环境的支持,其中 538 主要影响了 *nix 系统下的 UTF-8 字符串显示,PEP-540 主要是扩大了默认 UTF-8 编码的范围,比如 sys.getfilesystemencoding() 等将会返回 UTF-8 。这些问题一般用户并不会遇到,因此我这里不做更多描述,有兴趣的可以去看下具体的内容即可。PEP-552 扩展了 pyc 文件的格式,更好的支持 pyc 缓存,感觉作用不大,这里也不做太多介绍。PEP-539 定义了一套新的 Thread Soecific Storage API,提升对跨平台的支持性,这里也不做介绍了。


文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !
  目录