Python 3 新特性
原文链接: https://www.asmeurer.com/python3-presentation/python3-presentation.pdf
包括:
1. 更加灵活的拆包特性 (unpack)
2. 函数输入参数的关键词强制参数 (输入参数的 *
符号)
3. 异常链 (抛出异常时更加完整的异常栈信息)
4. 更加细化的 OSError
类型 (https://www.python.org/dev/peps/pep-3151/)
5. 大多数基础方法都替换成了生成器 (range
、 zip
、 map
、 dict.values
…)
6. 不同基础类型禁止相互比较
7. yield from
语法的支持
8. 异步 i/o - asyncio 库
9. 标准库的修改与加强
10. unicode 和 bytes (逃离字符编码的噩梦吧)
11. __matmul__
和 @
(新的运算符号)
特性 1: 更加灵活的拆包特性 (unpack)
python 2 中可以如此拆包
>>> a, b = range(2)
>>> a
0
>>> b
1
python3 中可以这样
>>> a, b, *rest = range(10)
>>> a
0
>>> b
1
>>> rest
[2, 3, 4, 5, 6, 7, 8, 9]
>>> a, *rest, b = range(10)
>>> *rest, b = range(10)
利用这个特性获取一个文件的首位两行
>>> with open("using_python_to_profit") as f:
... first, *_, last = f.readlines()
>>> first
'Step 1: Use Python 3\n'
>>> last
'Step 10: Profit!\n'
特性 2: 关键词强制参数
>>> def f(a, b, *, option=True): # 这样的调用方式,option 在传参时必须明确写出
... pass
在这种情况下,下面的调用是会报错的
>>> f(1, 2, False) # 会报错
正确的调用方式
>>> f(1, 2, option=False)
这种写法在 python3 的官方库中很常见
这样的好处之一是避免了在未来的版本中,替换了函数输入参数的前后顺序,使用这个函数的代码就会发生异常
另一个好处是,有事参数含义并非很明确,如果调用时不写成 参数名=参数值
的形式,代码的阅读性会变得很差
特性 3: 异常链
Python3 对于异常链保留了更加完整的异常栈信息
一种常见的场景是,代码捕捉到某个异常,进行一些处理后再抛出定义好的异常,例如
def mycopy(source, dest):
try:
shutil.copy2(source, dest)
except OSError:
raise NotImplementedError("automatic sudo injection")
假设 shutil.copy2
出错了,python2 的异常栈信息只会打印
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in mycopy
NotImplementedError: automatic sudo injection
而 python3 会显示
Traceback (most recent call last):
File "<stdin>", line 3, in mycopy
File "/Users/aaronmeurer/anaconda3/lib/python3.3/shutil.py", line 243, in copy2
copyfile(src, dst, follow_symlinks=follow_symlinks)
File "/Users/aaronmeurer/anaconda3/lib/python3.3/shutil.py", line 109, in copyfile
with open(src, 'rb') as fsrc:
PermissionError: [Errno 13] Permission denied: 'noway'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in mycopy
NotImplementedError: automatic sudo injection
同时支持下面的语法格式 (还没怎么见过实际使用)
raise exception from e
特性 4: OSError
类型
- https://www.python.org/dev/peps/pep-3151/
特性 5: 大多数基础方法都替换成了生成器
range
、zip
、map
、dict.values
…- 避免了由于代码编写不当造成的大量内存使用
特性 6: 不同基础类型禁止相互比较
Python3 不在提供诸如 'one' > 2
这种语法的支持,这样的写法在大多数情况下都是意义不明的,而且 Python3 禁止这种语法可以使得潜在的 bug 更少
里一个例子是下面的代码,在 Python3 也会报错
>>> sorted(['1', 2, '3'])
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: '<' not supported between instances of 'int' and 'str'
特性 7: yield from
语法的支持
yield from
语法的支持,是 python 正规语法对协程(coroutine)的支持,在这之前都是依赖第三方包来实现这一概念 (greenlet 等),对协程概念不了解的可以搜索相关帖子
特性 8: 异步 i/o - asyncio 库
这绝对是 Python 最难理解的概念之一了,官方示例如下
import asyncio
async def main():
print('Hello ...')
await asyncio.sleep(1)
print('... World!')
# Python 3.7+
asyncio.run(main())
如果一个程序是完全从头通过 asyncio 来实现的,使用起来还 “相对” 简单;但如果想在已有代码的某一部分上使用这一技术,至少以我的技术水平觉得是非常别扭的。
特性 9: 标准库的修改与加强
比如 Type hint 特性原来依赖第三方包,现在已经是官方支持;说实话这一部分我了解的比较少,一般是需要的时候去查看官方文档
特性 10: unicode 和 bytes
Python 2 中,str
类型的行为更像是 bytes
,而 unicode
类型来表示非 ascii 码的字符串数据。Python 3 中,str
就是以 unicode
编码的字符串,而 bytes
就是单纯的 bytes
类型
特性 11: __matmul__
和 @
Python 3 添加了新的运算符号 @
,只要一个类实现了 __matmul__
方法即可。
例如 numpy 的点乘,Python2 的写法是
>>> a = np.array([[1, 0], [0, 1]])
>>> b = np.array([[4, 1], [2, 2]])
>>> np.dot(a, b)
array([[4, 1],
[2, 2]])
而 Python3 可以写成
>>> a = np.array([[1, 0], [0, 1]])
>>> b = np.array([[4, 1], [2, 2]])
>>> a @ b
array([[4, 1],
[2, 2]])