python3.8-3.10各新版本新特性

目录

      • 3.8
        • [3.8.1 海象运算符(赋值运算符)](#3.8.1 海象运算符(赋值运算符))
        • [3.8.2 f-string](#3.8.2 f-string)
        • [3.8.3 仅限位置形参 [/],[*]](#3.8.3 仅限位置形参 [/],[*])
        • [3.8.4 多进程共享内存](#3.8.4 多进程共享内存)
        • [3.8.5 \pycache](#3.8.5 _pycache_)
        • [3.8.6 asyncio](#3.8.6 asyncio)
        • [3.8.7 dict](#3.8.7 dict)
      • 3.9
        • [3.9.1 字典合并运算符](#3.9.1 字典合并运算符)
        • [3.9.2 字符串对齐方法](#3.9.2 字符串对齐方法)
        • [3.9.3 可选的类型提示](#3.9.3 可选的类型提示)
        • [3.9.4 更好的浮点数支持](#3.9.4 更好的浮点数支持)
        • [3.9.5 更好的异常处理](#3.9.5 更好的异常处理)
        • [3.9.6 更好的装饰器语法](#3.9.6 更好的装饰器语法)
        • [3.9.7 更好的可迭代协议](#3.9.7 更好的可迭代协议)
        • [3.9.8 更好的异步编程支持](#3.9.8 更好的异步编程支持)
        • 3.9.9
        • [3.9.10 更好的注解支持](#3.9.10 更好的注解支持)
        • [3.9.11 标准多项集中的类型标注泛型](#3.9.11 标准多项集中的类型标注泛型)
        • [3.9.12 \import()特性修改](#3.9.12 _import_()特性修改)
        • [3.9.13 新增的模块](#3.9.13 新增的模块)
        • [3.9.14 改进的模块](#3.9.14 改进的模块)
      • 3.10
        • [3.10.1 新的 Union Type表达](#3.10.1 新的 Union Type表达)
        • [3.10.2 zip 可选严格模式](#3.10.2 zip 可选严格模式)
        • [3.10.3 带括号的上下文管理器](#3.10.3 带括号的上下文管理器)
        • [3.10.4 显式类型别名](#3.10.4 显式类型别名)
        • [3.10.5 结构化模式匹配](#3.10.5 结构化模式匹配)
        • [3.10.6 更友好的报错提示](#3.10.6 更友好的报错提示)
        • [3.10.7 distutils 被弃用](#3.10.7 distutils 被弃用)
      • 参考

3.8

3.8.1 海象运算符(赋值运算符)
python 复制代码
s = ' jsadlk '.strip()
def choice():
    if res:=isinstance(s, int): #如果res为真的话赋值给res
        return res
    else:return res
        res = choice()

也可用于循环

python 复制代码
while a:=True:
    print('helloworld')
3.8.2 f-string
python 复制代码
a = '你好'
b = '世界'
print(f'a={a} b={b}')
# a=你好 b=世界

# f-string在3.8中变得更加简洁
a = '你好'
b = '世界'
print(f'{a=} {b=}')
# a=你好 b=世界

还添加了赋值符号!s和!f,制定输入结果格式

python 复制代码
import datetime

time = datetime.datetime.now()
print(f'{time=!s}')
# time=2019-07-30 16:58:00.123412

import math

print(f'{math.pi=!f:.2f}') # 精确到小数点后面两位
3.8.3 仅限位置形参 [/],[*]

新增了一个函数形参语法 / 用来指明某些函数形参必须使用仅限位置而非关键字参数的形式。 这种标记语法与通过 help() 所显示的使用 Larry Hastings 的 Argument Clinic 工具标记的 C 函数相同。在下面的例子中,形参 a 和 b 为仅限位置形参,c 或 d 可以是位置形参或关键字形参,而 e 或 f 要求为关键字形参:

python 复制代码
def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)
python 复制代码
#以下均为合法的调用:
f(10, 20, 30, d=40, e=50, f=60)
# 但是,以下均为不合法的调用:
f(10, b=20, c=30, d=40, e=50, f=60) # b cannot be a keyword argument
f(10, 20, 30, 40, 50, f=60) # e must be a keyword argument

以下均为合法定义

python 复制代码
def name(p1, p2, /, p_or_kw, *, kw):
def name(p1, p2=None, /, p_or_kw=None, *, kw):
def name(p1, p2=None, /, *, kw):
def name(p1, p2=None, /):
def name(p1, p2, /, p_or_kw):
def name(p1, p2, /):
def name(p1, p2): #当然不加的话没有任何影响,和以前的没有区别

下面是有效的定义函数

python 复制代码
def name(p_or_kw, *, kw):
def name(*, kw):

下面是无效的函数定义

python 复制代码
def name(p1, p2=None, /, p_or_kw, *, kw):  # p_or_kw也需要默认值
def name(p1=None, p2, /, p_or_kw=None, *, kw):
def name(p1=None, p2, /):

这种标记形式的一个用例是它允许纯 Python 函数完整模拟现有的用 C 代码编写的函数的行为。 例如,内置的 pow() 函数不接受关键字参数:

python 复制代码
def pow(x, y, z=None, /):
    "Emulate the built in pow() function"
    r = x ** y
    return r if z is None else r%z

另一个用例是在不需要形参名称时排除关键字参数。 例如,内置的 len() 函数的签名为 len(obj, /)。 这可以排除如下这种笨拙的调用形式:

python 复制代码
len(obj='hello')  # The "obj" keyword argument impairs readability

第三个用例是将形参标记为仅限位置形参将允许在未来修改形参名而不会破坏客户的代码。 例如,在 statistics 模块中,形参名 dist 在未来可能被修改。 这使得以下函数描述成为可能:

python 复制代码
def quantiles(dist, /, *, n=4, method='exclusive')
    ...

由于在 / 左侧的形参不会被公开为可用关键字,其他形参名仍可在 **kwargs 中使用:

python 复制代码
>>> def f(a, b, /, **kwargs):
...     print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3)         # a and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}

这极大地简化了需要接受任意关键字参数的函数和方法的实现。例如,下面是collections模块中的代码摘录:

python 复制代码
class Counter(dict):

    def __init__(self, iterable=None, /, **kwds):
        # Note "iterable" is a possible keyword argument
3.8.4 多进程共享内存

multiprocessing模块提供了SharedMemory类,可以在不同的Python进城之间创建共享的内存区域

3.8.5 pycache

__pycache__目录是由 Python3 解释器创建的,用于保存.pyc 文件。这些文件保存着解释器编译.py 文件之后的字节码(byte code)。之前的 Python 版本仅仅只是为每个.py 文件创建一个.pyc 文件,但是新版本会有所变化。

为了支持多版本的 Python,包括一些不是 CPython 的版本(如 PyPy),现在库文件会为每个 Python 版本创建对应的.pyc 文件,格式形如「name.interp-version.pyc」。例如,某个 foo.py 文件在第一次使用的时候会创建一个对应的 pyc 文件,其路径为「pycache/foo.cpython-37.pyc」,这个 pyc 文件会定义使用的 Python 版本。

3.8.6 asyncio

asyncio.run()

已经从暂定状态晋级为稳定 API。 此函数可被用于执行一个 coroutine 并返回结果,同时自动管理事件循环。 例如:

python 复制代码
import asyncioasync
def main():
    await asyncio.sleep(0)
    return 42

asyncio.run(main())

这大致等价于:

python 复制代码
import asyncio
asyn def  main():
    await asyncio.sleep(0)
    return 42

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
    loop.run_until_complete(main())
finally:
    asyncio.set_event_loop(None)
    loop.close()

实际的实现要更复杂许多。 因此 asyncio.run() 应该作为运行 asyncio 程序的首选方式。

3.8.7 dict

现在 dict 和 dictview 可以使用 reversed() 按插入顺序反向迭代。

3.9

3.9.1 字典合并运算符

Python 3.9引入了新的字典合并运算符(|),它可以合并两个字典。下面是一个示例:

python 复制代码
a = {'x': 1, 'y': 2}
b = {'y': 3, 'z': 4}
c = a | b
print(c)  # {'x': 1, 'y': 3, 'z': 4}

在上面的代码中,我们首先定义了两个字典a和b,然后使用|运算符将它们合并成一个新的字典c。注意,如果两个字典中有相同的键,则使用后面的字典中的值。

3.9.2 字符串对齐方法

Python 3.9引入了一种新的字符串对齐方法,它可以在字符串的左侧、右侧或中心添加填充字符。下面是一个示例:

python 复制代码
s = 'hello'
print(s.ljust(10, '-'))  # hello-----
print(s.rjust(10, '-'))  # -----hello
print(s.center(10, '-'))  # --hello---

在上面的代码中,我们使用ljust()方法将字符串s左对齐,并在右侧添加了-字符,使其总长度为10。类似地,rjust()方法将字符串右对齐,而center()方法将字符串居中对齐。

3.9.3 可选的类型提示

Python 3.9引入了一种新的语法,可以将类型提示标记为可选的。下面是一个示例:

python 复制代码
def greet(name: str, *, greeting: str = 'Hello') -> str:
    return f'{greeting}, {name}!'

在上面的代码中,我们定义了一个名为greet()的函数,并使用类型提示指定了参数和返回值的类型。注意,我们使用=符号将greeting参数标记为可选的,并使用*符号将其与name参数分开。

3.9.4 更好的浮点数支持

Python 3.9引入了一些新的浮点数方法和常量,包括math.isqrt()方法和math.tau常量。下面是一个示例:

python 复制代码
import math

x = 16
print(math.isqrt(x))  # 4

print(math.tau)  # 6.283185307179586

在上面的代码中,我们使用math.isqrt()方法计算x的平方根,并使用math.tau常量表示圆周率的两倍。

3.9.5 更好的异常处理

Python 3.9引入了一些新的异常处理机制,包括新的try语法、新的raise语法和新的异常类型。下面是一个示例:

python 复制代码
try:
    # some code that may raise an exception
except SomeException as e:
    # handle the exception
else:
    # execute if no exception is raised
finally:
    # always execute

在上面的代码中,我们使用新的try语法来捕获可能会引发SomeException异常的代码块,并使用except语法处理异常。如果没有异常被引发,则执行else语句块。无论异常是否被引发,finally语句块都会被执行。

3.9.6 更好的装饰器语法

Python 3.9引入了一种新的装饰器语法,它可以在装饰器和函数之间省略括号。下面是一个示例:

python 复制代码
@my_decorator
def my_function():
    print('Hello, world!')

在上面的代码中,我们使用新的装饰器语法将my_decorator装饰器应用于my_function函数,而不需要使用括号。

3.9.7 更好的可迭代协议

Python 3.9引入了一些新的可迭代协议,包括__len__()方法和__getitem__()方法。下面是一个示例:

python 复制代码
class MyList:
    def __init__(self, items):
        self.items = items

    def __len__(self):
        return len(self.items)

    def __getitem__(self, index):
        return self.items[index]

my_list = MyList([1, 2, 3])
for item in my_list:
    print(item)

在上面的代码中,我们定义了一个名为MyList的类,并实现了__len__()方法和__getitem__()方法。这使得我们可以像使用标准列表一样使用my_list对象进行迭代。

3.9.8 更好的异步编程支持

Python 3.9引入了一些新的异步编程支持,包括新的async with语法和新的异步上下文管理器。下面是一个示例:

python 复制代码
class AsyncContextManager:
    async def __aenter__(self):
        print('entering context')
    
    async def __aexit__(self, exc_type, exc, tb):
        print('exiting context')

async def my_coroutine():
    async with AsyncContextManager():
        print('inside context')

asyncio.run(my_coroutine())

在上面的代码中,我们定义了一个名为AsyncContextManager的异步上下文管理器,并使用新的async with语法将其应用于my_coroutine异步函数。这允许我们在异步代码中使用上下文管理器。

3.9.9

更好的模块解析

python 复制代码
# my_package/__init__.py
from .my_module import my_function

# my_package/my_module.py
def my_function():
    print('Hello, world!')

# main.py
from my_package import my_function

my_function()

在上面的代码中,我们定义了一个名为my_package的包,并从my_module模块中导入了my_function函数。我们可以在main.py模块中使用my_function函数,而不需要知道它来自哪个模块。

3.9.10 更好的注解支持

Python 3.9引入了一些新的注解支持,包括新的typing.Annotated类和新的typing.get_origin()函数。下面是一个示例:

python 复制代码
from typing import Annotated

x: Annotated[int, 'positive']
y: Annotated[int, 'negative']

print(x.__metadata__)  # ('positive',)
print(y.__metadata__)  # ('negative',)

import typing

if typing.get_origin(Annotated[int, 'positive']) == int:
    print('Annotated[int, "positive"] is a subclass of int')

在上面的代码中,我们使用Annotated类为变量x和y添加了元数据,并使用typing.get_origin()函数检查Annotated[int, 'positive']是否是int的子类。这使得我们可以更好地描述和处理类型信息。

3.9.11 标准多项集中的类型标注泛型

在类型标注中现在你可以使用内置多项集类型例如 list 和 dict 作为通用类型而不必从 typing 导入对应的大写形式类型名 (例如 List 和 Dict)。 标准库中的其他一些类型现在同样也是通用的,例如 queue.Queue。示例:

python 复制代码
def greet_all(names: list[str]) -> None:
    for name in names:
        print("Hello", name)
3.9.12 import()特性修改

import () 现在会引发 ImportError 而不是 ValueError。

至于原因,在Python的官方文档中有相应的解释:后者曾经会在相对导入超出其最高层级包时发生。

3.9.13 新增的模块

在新增模块方面,zoneinfo模块为标准库引入了IANA 时区数据库。

这是一个基于系统时区数据的实体 datetime.tzinfo 实现

3.9.14 改进的模块

除了新增的模块外,Python3.9还对原有的一些模块进行了改进。

Prasoon举出了他认为比较重要的一项------Random。

名为random.Random.randbytes的方法,可以用于生成随机字节串

此外,还有cancel_futures。

Python3.9将新的 cancel_futures 形参,添加到 concurrent.futures.Executor.shutdown(),可以取消尚未开始运行的所有挂起的 Future,而不必等待它们完成运行再关闭执行器。

3.10

3.10.1 新的 Union Type表达

新版本简化了 Union Type 的使用 ,改为更为简洁的|

python 复制代码
# 旧版
from typing import Uniona: Union[int, str] = 1
# 新版
a: str | int = 1
# 二者完全等价:
Union[int, str] == int | str # True
# 该特性也可用于 isinstance和issubclass

# True
isinstance("FunnySaltyFish", int|str)
# True 
issubclass(str, str|int)
3.10.2 zip 可选严格模式

zip新增可选参数strict, 当该选项为True时,传入zip的两个可迭代项长度必须相等,否则将抛出 ValueError旧版(及不加此参数),当二者长度不等时,以长度较小的为准

python 复制代码
# 旧版(及不加此参数),当二者长度不等时,以长度较小的为准
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

python 复制代码
# ...
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
3.10.3 带括号的上下文管理器

with可以加括号了

python 复制代码
with (CtxManager() as example):
    ...

with (
    CtxManager1(),
    CtxManager2()
):
    ...

with (CtxManager1() as example,
      CtxManager2()):
    ...

with (CtxManager1(),
      CtxManager2() as example):
    ...

with (
    CtxManager1() as example1,
    CtxManager2() as example2
):
    ...

python 复制代码
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.10.4 显式类型别名

使用 TypeAlias 显式标注类型别名,提高可读性

旧的方式:

python 复制代码
x = int
def plus_int(a:x,b:x) -> x:
    return a+b

可以看到,x很容易被搞混新的方式:使用 TypeAlias表明这是个别名

python 复制代码
from typing import TypeAlias
x : TypeAlias = int
def plus_int(a:x,b:x) -> x:
    return a+b
3.10.5 结构化模式匹配

Python 3.10 引入了结构化模式匹配,允许您匹配列表、元组和字典等数据结构中的模式。这可以使代码更简洁易读。例如:

python 复制代码
# 匹配模式
def process_data(data):
    match data:
        case []:
            print('没有数据')
        case [x]:
            print(f'一个项目:{x}')
        case [x, y]:
            print(f'两个项目:{x},{y}')
        case _:
            print('超过两个项目')

subject:这在处理命令行参数的时候特别有用

python 复制代码
"""
    @copyright : [FunnySaltyFish](https://funnysaltyfish.github.io)
    @date : 2021/10/05 21:08:42
"""
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}")

也可以匹配对象:

python 复制代码
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}")

当然也可以匹配字典:

python 复制代码
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岁,喜欢阅读

约束项

python 复制代码
match point:
    case Point(x, y) if x == y:
        print(f"The point is located on the diagonal Y=X at {x}.")
    case Point(x, y):
        print(f"Point is not on the diagonal.")

其他关键特性

  • 类似于解包赋值,元组和列表模式具有完全相同的含义,而且实际上能匹配任意序列。 从技术上说,目标必须为一个序列。 因而,一个重要的例外是模式不能匹配迭代器。 而且,为了避免一个常见的错误,序列模式不能匹配字符串。
  • 映射模式: {"bandwidth": b, "latency": l} 会从一个字典中捕获 "bandwidth" 和 "latency" 值。 与序列模式不同,额外的键会被忽略。 也支持通配符 **rest。 (但 **_ 是冗余的,因而不被允许。)
  • 子模式可使用 as 关键字来捕获:
python 复制代码
case (Point(x1, y1), Point(x2, y2) as p2): ...
  • 与枚举一起使用,命名常量必须为带点号的名称以防止常量被解读为捕获变量:
python 复制代码
from enum import Enumclass Color(Enum):
    RED = 0
    GREEN = 1
    BLUE = 2

match color:
    case Color.RED:
        print("I see red!")
    case Color.GREEN:
        print("Grass is green")
    case Color.BLUE:
        print("I'm feeling the blues :(")
3.10.6 更友好的报错提示

现在,当你的括号、引号未闭合时,python会抛出更加清晰明了的错误

python 复制代码
str = "未闭合的str

File "d:\projects\python\learn\Py310探索.py", line 90
    str = "未闭合的str
          ^
SyntaxError: unterminated string literal (detected at line 90)
python 复制代码
 arr = [1, 2, 2, 3
    
  File "d:\projects\python\learn\Py310探索.py", line 91
    arr = [1, 2, 2, 3
          ^
SyntaxError: '[' was never closed
3.10.7 distutils 被弃用

distutils 被弃用

参考

Python 3.8.0 正式发布,一大波新特性和优化来袭
Python 3.8 - 3.11 版本新特性总结和示例

相关推荐
思则变3 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
漫谈网络3 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
try2find4 小时前
安装llama-cpp-python踩坑记
开发语言·python·llama
博观而约取5 小时前
Django ORM 1. 创建模型(Model)
数据库·python·django
精灵vector7 小时前
构建专家级SQL Agent交互
python·aigc·ai编程
Zonda要好好学习7 小时前
Python入门Day2
开发语言·python
Vertira7 小时前
pdf 合并 python实现(已解决)
前端·python·pdf
太凉7 小时前
Python之 sorted() 函数的基本语法
python
项目題供诗7 小时前
黑马python(二十四)
开发语言·python
晓13138 小时前
OpenCV篇——项目(二)OCR文档扫描
人工智能·python·opencv·pycharm·ocr