说说 Python3.7

昨天 Python 3.7 正式发布,新功能都很棒,简单研究一下。这些新的特性主要包括:

  • 内置断点 breakpoint()
  • 数据类 dataclass
  • 定制访问模块属性
  • 改进了对类型提示的支持
  • 更高精度的定时功能

更便捷的断点调试

之前调试一般有四种方法:

  • 使用 print() 函数来打印变量
  • 导入 pdb 模块,使用 set_trace() 方法来打断点
  • 使用 IPython 调试
  • 使用其他 IDE 进行调试

在 Python 3.7 中,上面第二种调试方法有了更便捷的实现,就是使用新增的 breakpoint() 方法。它会隐式调用 pdb.set_trace(),运行程序时会在断点处暂停,并进入 pdb 调试环境。接着就可以用 pdb 的一些方法来调试了,比如 c 、 p 等。进一步了解可以参考 这里

在不需要断点调试的时候,指定环境变量 PYTHONBREAKPOINT 的值为 0 ,执行脚本过程中就会自动跳过 breakpoint()。就像这样:

$ PYTHONBREAKPOINT=0 python3.7 test.py

该环境变量还可以指定使用 IPython 来调试,比如这样:

$ PYTHONBREAKPOINT=IPython.embed python3.7 test.py

更深度的话我们可以定制 breakpoint() 函数,可以自定义一个函数让 breakpoint() 调用,比如保存断点处的变量,自定义模块bp_utils 如下:

from pprint import pprint
import sys

def print_locals():
caller = sys._getframe(1) # Caller is 1 frame up.
pprint(caller.f_locals)

接着可以这样调用:

$ PYTHONBREAKPOINT=bp_utils.print_locals python3.7 test.py

Data Classes

在平时工作中,如果一个类的初始化参数特别多,写 __init__ 方法会很累。另外,如果不定义 __repr__ 方法,打印类对象的方式很不友好,不能一眼看出这个类是干什么的。比如:

print(SomeClass)
<test.SomeClass at 0x12ba6c310>

所以我们可以定义 __repr__ 方法来使打印的结果更友好,比如打印出这个类的前几个参数。但当我们需要定义的类特别多的时候,每个类都需要手写一遍 __repr__,太麻烦了。再有,当我们需要判断两个对象是否相等,或者对对象去重的时候,目前的解决方案是定义 __eq____gt____lt____hash__ 等方法。当然也需要手写。

但使用 Python 3.7 中新添加的 dataclasses 模块就不一样了,像上述的 __init__ , __repr__ , __eq__ , __hash__ 等方法都会 自动 添加,是不是很方便?例如可以这样写:

from dataclasses import dataclass, field

@dataclass(order=True, hash=True)
class Country:
name: str
population: int
area: float = field(repr=False, compare=False)
coastline: float = 0

def beach_per_person(self):
"""Meters of coastline per person"""
return (self.coastline * 1000) / self.population

这样写之后,再对类实例做打印、比较、去重时就方便多了。

以下部分内容我还没搞懂,先占坑。

Customization of Module Attributes

Typing Enhancements

更精确的时间(纳秒级)

其他特性

有序字典上升至语言规范

asyncawait 成为关键字

asyncio Face Lift

上下文变量

使用 importlib.resources 导入数据文件

开发者相关

-X 命令行参数

  • -X importtime 查看模块导入时间
  • -X dev 开发模式
  • -X utf8 UTF-8 模式

优化

  • 减少调用标准库中的大部分方法的开销
  • 方法调用速度快 20%
  • Python 启动速度减少了 10% ~ 30%
  • 导入 typing 模块速度快 7 倍

参考