Skip to main content

3.10【2021-10】

🌟新增

官方地址

1、语法 match ... case ()

我还是更喜欢较 switch 语法,一个可读性非常好的语法,在js和java用的超级舒服,终于python也有了

传统写法:

def http_error(status:int) -> str:
    if status == 400:
        return "Bad request"
    elif status == 404:
        return "Not found"
    elif status == 418:
        return "I'm a teapot"
    else:
        return "Something's wrong with the internet"

基础语法:

def http_res(status:int) -> str:
    match status:
case 301 | 302 | 303:
return "3*"
        case 400 | 404 | 418:
            return "Not allowed"
        case _:
            return "Something's wrong with the internet"
def http_error(status:int) -> str:
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the internet"

case _: 类似于其它语言中的 default ,当其他条件都不符合就执行这行。

应用场景:

匹配数组
command = "save 1.txt"
# 试着把command改成 list / copy 1.txt 2.txt 看看效果
match command.split(" "):
case ["list"]:
print("列出文件~")
case ["save", file_name]:
print(f"保存文件到 {file_name}")
case ["copy", source, target]:
print(f"拷贝 {source} -> {target}")
匹配对象
class Person():
pass

class Student(Person):
def __init__(self, id: int) -> None:
self.id = id

class Teacher(Person):
def __init__(self, name: str) -> None:
self.name = name

a = Student(1)
# a = Student(2)
# a = Teacher("FunnySaltyFish")
match a:
case Student(id = 2):
print(f"这是位学生,且id正好是2")
case Student():
print(f"这是学生,id为{a.id}")
case Teacher():
print(f"这是老师, 姓名为{a.name}")

匹配字典
d = {
"name" : "李四", # 张三
"age" : 18,
"hobby" : "阅读"
}
match d:
case {"name":"张三", **args}:
# **收集其他参数
print("这是张三", args) # 这是张三 {'age': 18, 'hobby': '阅读'}
case {"name" : name , "age" : age, "hobby": hobby}:
print(f"我叫{name}, 今年{age}岁, 喜欢{hobby}") #我叫李四,今年18岁,喜欢阅读

配合 * 通配符
import sys

match sys.argv[1:]:
case ["quit"]:
print("exit")
case ["create", user]: # 创建单个用户
print("create", user)
case ["create", *users]: # 批量创建多个用户
for user in users:
print("create", user)
case _:
print("Sorry, I couldn't understand the argv")

2、新的联合类型操作符 “|”

在之前版本中,对于函数参数如果希望类型支持多种,例如同时支持int和float,需要用Union:

from typing import Union

联合操作符 “|”:

  • 类型定义
# 3.9
a: Union[int, str] = 1

# 3.10
a: str | int = 1
# 3.9
typing.List[typing.Union[str, int]]

# 3.10
typing.List[str | int]
list[int|sr]
# 3.9
typing.Dict[str, typing.Union[int, float]]

# 3.10
typing.Dict[str, int | float]
dict[str, int | float]
  • 函数定义
# 3.10
def square(number: int | float) -> int | float:
return number ** 2

# 3.9
def foo(number: Union[ int, float]) -> Union[int, float]:
return number ** 2
# 3.10
def f(list: List[int | str], param: int | None) -> float | str:
pass

# 3.9
def f(list: List[Union[int, str]], param: Optional[int]) -> Union[float, str]
pass
  • 类型判断 isinstanceissubclass
# 3.10
>>> isinstance(1, int | str)
True

# 3.9
>>> isinstance(1, (int,float))
True
# 3.9
issubclass(str, (strint))

# 3.10
issubclass(str, str|int)

3、TypeAlias 显示标注类型别名

新的方式:使用 TypeAlias表明这是个别名

from typing import TypeAlias
x : TypeAlias = int
def plus_int(a:x,b:x) -> x:
return a+b

✴优化

1、更精准的错误提示

expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
38: 4, 39: 4, 45: 5, 46: 5, 47: 5, 48: 5, 49: 5, 54: 6,
some_other_code = foo()

比如这段代码如果你不小心漏掉一个右花括号,运行代码时,在之前的版本中直接提示语法错误:

File "example.py", line 3
some_other_code = foo()
^
SyntaxError: invalid syntax

不仔细检查代码你还真的没法一眼看出来到底哪里语法错误。而在python3.10中,提示变得非常友好而且具体, 直接告诉你"{"没有关闭,这样定位错误就很快了。

File "example.py", line 1
expected = {9: 1, 18: 2, 19: 2, 27: 3, 28: 3, 29: 3, 36: 4, 37: 4,
^
SyntaxError: '{' was never closed

类似地,还有推导式中如果忘记加圆括号时,之前一言不合直接提示语法错误

>>> {x,y for x,y in zip('abcd', '1234')}
File "<stdin>", line 1
{x,y for x,y in zip('abcd', '1234')}
^
SyntaxError: invalid syntax

而现在会告诉你,是不是忘记加圆括号了。

>>> {x,y for x,y in zip('abcd', '1234')}
File "<stdin>", line 1
{x,y for x,y in zip('abcd', '1234')}
^
SyntaxError: did you forget parentheses around the comprehension target?

非常人性化

2、带括号的上下文管理器 with()

以往我们需要同时执行多个上下文时:

传统写法:

with open("xxx.py", mode="w") as f1, open("yyy.py", mode="w") as f2:
    pass

# 或者

with open("xxx.py", mode="w") as f1, \
        open("yyy.py", mode="w") as f2:
    pass

现在:

# 直接使用括号+逗号即可
with ( open("xxx.py", mode="w") as f1, open("yyy.py", mode="w") as f2 ):
pass
# 或者
with (
open("xxx.py", mode="w") as f1,
open("yyy.py", mode="w") as f2,
open("yyy.py", mode="w") as f3,
open("yyy.py", mode="w") as f4
):
pass
import pathlib
p = pathlib.Path()
p1 = p/"text1.txt" # 内容:文本1的内容
p2 = p/"text2.txt" # 内容:文本2的内容
with(
p1.open(encoding="utf-8") as f1,
p2.open(encoding="utf-8") as f2
):
print(f1.read(), f2.read(), sep="\n")

# 文本1的内容
# 文本2的内容

3、zip 可选严格模式

zip新增可选参数strict, 当该选项为True时,传入zip的两个可迭代项长度必须相等,否则将抛出 ValueError

names = ["a","b","c","d"]
numbers = [1,2,3]
z = zip(names,numbers)
for each in z:
print(each)

# ('a', 1)
# ('b', 2)
# ('c', 3)
  • 设置strict为True
# ...
z = zip(names,numbers,strict=True)
# ...

d:\projects\python\learn\Py310探索.py in <module>
3 numbers = [1,2,3]
4 z = zip(names,numbers,strict=True)
----> 5 for each in z:
6 print(each)

ValueError: zip() argument 2 is shorter than argument 1

🗑弃用

1、distutils 被弃用(使用setuptool)

2、需要 OpenSSL 1.1.1 及以上版本

3、移除 Py_UNICODE编码API

4、PyUnicodeObject的wstr被弃用,并将在之后移除