关注微信公众号:K哥爬虫,QQ交换群:808574309,继续分享爬虫进阶、JS/安卓逆向等技术干货!
前几天,也就是 10 月 4 日,Python 公布了 3.10.0 版本,什么?3.9 之后竟然不是 4.0?(手动狗头)其实龟叔(Guido van Rossum,吉多·范罗苏姆,Python 之父)早在去年 9 月就说了:
- 3.9 之后的版本为 3.10;事实上,它曾经存在(在 Github Master 主分支中)。
- 如果有版本 4,从 3 到 4 的过渡更像从 1 到 2,而不是从 2 到 3。
相比 Python 3.9,Python 3.10 次要的新性能如下:
PEP 634 - PEP 636:构造模式匹配
在本次诸多的更新中,Structural Pattern Matching 构造模式匹配,match-case
语句无疑是最让人兴奋的性能,也就相似于 Java、C、Go 等其余语言中的 switch-case
语句,具体用法能够参考:PEP 636
来看一个简略的例子:
def http_error(status): match status: case 400: print("Bad request") case 404: print("Not found") case 418: print("I'm a teapot") case _: print("Something's wrong with the internet")http_error(418) # I'm a teapothttp_error(500) # Something's wrong with the internet
以上代码中,最初一个 case
中的 _
并不作为变量名,而示意一种非凡的模式,在后面的 case
中都未命中的状况下,该 case
会是最初的保障,能确保命中,它相当于 Java、C、Go 等语言中的 default
分支:
public class HttpError { public static void main(String args[]){ int status = 500; switch(status){ case 400: System.out.println("Bad request"); case 404: System.out.println("Not found"); case 418: System.out.println("I'm a teapot"); default: System.out.println("Something's wrong with the internet"); } }}// Something's wrong with the internet
match-case
语法反对可变参数 *args
和 **rest
。
*args
的用法与 Python 函数中的可变参数是一个用法,容许传入多个参数:
def create_user(command): match command.split(): case ["quit"]: quit() case ["create", user]: print("create", user) case ["create", *user]: for u in user: print("create", u) case _: print("command '{command}' not understood")create_user("create user1")create_user("create user2 user3 user4")# create user1# create user2# create user3# create user4
**rest
会匹配到字典中所有的 key
和 value
:
def get_dict(dic): match dic: case {**rest}: print("get dict:", rest) case _: print("parameter not understood")get_dict({"400": "Bad request", "404": "Not found", "418": "I'm a teapot"})# get dict: {'400': 'Bad request', '404': 'Not found', '418': "I'm a teapot"}
须要留神的是,构造模式匹配在面对不同的对象时,匹配的规定也有所不同。
当匹配对象是列表(list)或者元组(tuple)的时候,须要长度和元素值都匹配,能力命中:
def create_user(param): match param: case ("quit"): quit() case ("create", user): print("create", user) case ("create", *user): for u in user: print("create", u) case _: print("command '{command}' not understood")create_user(("create", "user1", "user2"))# create user1# create user2
当匹配对象是一个字典(dict)的时候,只有 case 表达式中的 键(key)在字典对象中存在即可命中,以下示例中,很可能会认为会执行第二个 case,但实际上执行了第一个 case:
def if_action(dic): match dic: case {"action": action}: print("action: %s, no object" % action) case {"action": action, "object": _}: print("action: %s, have object" % action)if_action({"action": "create", "object": "user1"})# action: create, no object
当匹配对象是类对象(class)的时候,匹配的规定和字典(dict)相似,只有对象类型和对象的属性满足条件即可命中,以下示例中,很可能会认为会执行第二个 case,但实际上执行了第一个 case:
class Info: def __init__(self, name, age): self.name, self.age = name, agedef get_info(people): match people: case Info(name="Bob"): print("case 1") case Info(name="Bob", age="20"): print("case 2")people = Info(name="Bob", age="20")get_info(people)# case 1
PEP 604:新型联结运算符(Union Types)
Python 是个弱类型语言,然而在 Python 3 中反对了定义传参和返回类型的写法:
def test(a: int) -> int: return a**2
通常一个参数和返回值只能是一个类型,在 C/C++,Java,Go 等动态语言里,不可能返回两种类型,或者传参应用两种类型,然而在 Python 里能够:
def test(a: str or int) -> str or int: return a**2
这里的 or 写法看着十分不难受,所以在 Python 3.5 的时候引入了 typing 模块,举荐应用 Uinon 的写法:
from typing import Uniondef test(a: Union[str, int]) -> Union[str, int]: return a**2
在本次 Python 3.10.0 更新中,PEP 604 容许将联结类型(Union Types)写为 X | Y:
def test(a: str | int) -> str | int: return a**2
新的运算符也能够用作 isinstance()
和 issubclass()
的第二个参数:
print(isinstance(5, int | str)) # Trueprint(isinstance(None, int | None)) # Trueprint(issubclass(bool, int | float)) # Trueprint(isinstance(42, None | str)) # False
PEP 626:谬误调试准确到行
在 PEP 626 中,报错提醒能够准确到具体行,提醒更加具体,在以前的版本中,谬误音讯个别会指向下一行,而不是理论谬误所在的地位,当初能够指向错误代码所在的确切地位。
错误代码示例 1:
li = [1, 2, 3
之前版本报错:
File "D:\python3Project\test.py", line 5 ^SyntaxError: unexpected EOF while parsing
Python 3.10 版本报错:
File "D:\python310Project\test.py", line 4 li = [1, 2, 3 ^SyntaxError: '[' was never closed
错误代码示例 2:
expected = {"name": "Bob", "age": 20some_other_code = foo()
之前版本报错:
File "D:\python3Project\test.py", line 2 some_other_code = foo() ^SyntaxError: invalid syntax
Python 3.10 版本报错:
File "D:\python310Project\test.py", line 1 expected = {"name": "Bob", "age": 20 ^SyntaxError: '{' was never closed
PEP 618:zip() 可选长度查看
zip()
是 Python 中的内置函数,用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,而后返回由这些元组组成的列表。
在以前的版本中,如果各个迭代器的元素个数不统一,则返回列表长度与最短的对象雷同,示例如下:
a = [1, 2, 3]b = [4, 5, 6]c = [4, 5, 6, 7, 8]zipped1 = zip(a, b)zipped2 = zip(a, c) # 元素个数与最短的列表统一print([z for z in zipped1]) # [(1, 4), (2, 5), (3, 6)]print([z for z in zipped2]) # [(1, 4), (2, 5), (3, 6)]
在 PEP 618 中,新增了 strict 参数,设置为 True 时,传入 zip()
的两个可迭代项长度必须相等,否则将抛出 ValueError
a = [1, 2, 3]b = [4, 5, 6]c = [4, 5, 6, 7, 8]zipped1 = zip(a, b, strict=True)zipped2 = zip(a, c, strict=True)print([z for z in zipped1])print([z for z in zipped2])
报错:
[(1, 4), (2, 5), (3, 6)]Traceback (most recent call last): File "D:\python310Project\test.py", line 8, in <module> print([z for z in zipped2]) File "D:\python310Project\test.py", line 8, in <listcomp> print([z for z in zipped2])ValueError: zip() argument 2 is longer than argument 1
BPO-12782:容许带括号的上下文管理器
Python 上下文管理器对于关上/敞开文件、解决数据库连贯和很多其余事件都十分有用,在 Python 3.10.0 中,它们的语法将有一点高质量的改良,在 BPO-12782 正式容许带括号的上下文管理器,当初能够用一个 with 语句创立多行,示例如下:
with( open("text1.txt", encoding="utf-8") as f1, open("text2.txt", encoding="utf-8") as f2): print(f1.read(), f2.read())
PEP 613:显式类型别名
PEP 613 应用 TypeAlias 显式标注类型别名,进步可读性。
以前版本,能够看到,x 很容易被搞混:
x = intdef plus_int(a: x, b: x) -> x: return a+b
Python 3.10 中,应用 TypeAlias 表明这是个别名,打消歧义:
from typing import TypeAliasx: TypeAlias = intdef plus_int(a: x, b: x) -> x: return a+b
性能晋升
与所有最新版本的 Python 一样,Python 3.10 也带来了一些性能改良。首先是优化 str()
,bytes()
和 bytearray()
构造函数,它们速度晋升了 30% 左右,代码摘自 BOP-41334:
$ ./python -m pyperf timeit -q --compare-to=../cpython-release2/python "str()"Mean +- std dev: [/home/serhiy/py/cpython-release2/python] 81.9 ns +- 4.5 ns -> [/home/serhiy/py/cpython-release/python] 60.0 ns +- 1.9 ns: 1.36x faster (-27%)$ ./python -m pyperf timeit -q --compare-to=../cpython-release2/python "bytes()"Mean +- std dev: [/home/serhiy/py/cpython-release2/python] 85.1 ns +- 2.2 ns -> [/home/serhiy/py/cpython-release/python] 60.2 ns +- 2.3 ns: 1.41x faster (-29%)$ ./python -m pyperf timeit -q --compare-to=../cpython-release2/python "bytearray()"Mean +- std dev: [/home/serhiy/py/cpython-release2/python] 93.5 ns +- 2.1 ns -> [/home/serhiy/py/cpython-release/python] 73.1 ns +- 1.8 ns: 1.28x faster (-22%)
另一个更值得注意的优化(如果你应用类型正文)是,函数参数及其正文不再在运行时(runtime)计算,而是在编译时计算,这使得创立一个带有参数正文的函数的速度进步了大概 2 倍。
除此之外,Python 外围的各个局部还有更多的优化,你能够在 Python bug tracker 的下列问题中找到更多的细节:BPO-41718、BPO-42927、BPO-43452。
其余扭转
- PEP 623:弃用并筹备删除 PyUnicodeObject 中的 wstr 成员。
- PEP 612:参数标准变量。
- PEP 632:弃用 distutils 模块,举荐应用 setuptools。
- PEP 644:CPython 的规范库仅反对 OpenSSL 1.1.1 或更新版本。
- PEP 624:删除 Py_UNICODE 编码器 API。
- PEP 597:增加可选的 EncodingWarning。