Python3.9 新特性note

Python语法官方文档

背景

偶然在网上看到一篇文章Python 疑难问题:[] 与 list() 哪个快?为什么快?快多少呢?提到python3.9为list()实现了更快的vectorcall协议,提升了使用list()创建列表的速度,恍然:啊!python都更新到3.9了呀。想起昨天看到的一篇文章,java都已经更新到14了。技术更新是如此之快,我的学习进度如此之慢!

概述

通过研究3.9新特性,了解下之前没有了解/使用的基础知识。

特性一:字典合并与更新运算符

旧:
Python3字典合并的几种方法

dict.update and {**d1,**d2}

use:

>>> d1 = {"user":"12311"}
>>> d2 = {"name":"lalalala"}
>>> d3 = {}
>>> d3.update(d1)
>>> print(d3)
{'user': '12311'}
>>> d3.update(d2)
>>> print(d3)
{'user': '12311', 'name': 'lalalala'}
>>> d4 = dict(d1,**d2)
>>> print(d4)
{'user': '12311', 'name': 'lalalala'}

新:

合并(|) 更新(|=)

use:

>>> x = {"key1": "value1 from x", "key2": "value2 from x"}
>>> y = {"key2": "value2 from y", "key3": "value3 from y"}
>>> x | y
{'key1': 'value1 from x', 'key2': 'value2 from y', 'key3': 'value3 from y'}
>>> y | x
{'key2': 'value2 from x', 'key3': 'value3 from y', 'key1': 'value1 from x'}

特性二:新增用于移除前缀和后缀的字符串方法

增加了 str.removeprefix(prefix)str.removesuffix(suffix) 用于方便地从字符串移除不需要的前缀或后缀。

如何理解?看代码实现清晰明了

def removeprefix(self: str, prefix: str, /) -> str:
    if self.startswith(prefix):
        return self[len(prefix):]
    else:
        return self[:]

def removesuffix(self: str, suffix: str, /) -> str:
    # suffix='' should not call self[:-0].
    if suffix and self.endswith(suffix):
        return self[:-len(suffix)]
    else:
        return self[:]

endwith(suffix[, start[, end]])可传入元组

PEP 616 -- String methods to remove prefixes and suffixes中提到suffix参数可为元组

suffix 为字符串:

name = "123nanana"
print(name.endwith("na"))
>>>True

suffix 为元组:

>>> name3 = "fsdsfs"
>>> if name3.endswith(("mixin","test")): print("123333")
... else: print("4444444444444")
...
4444444444444

特性三:标准多项集中的类型标注泛型

了解这个特性之前,我们先了解以下type hint是什么?先看下这篇文章全面理解Python中的类型提示(Type Hints),python其实和php有点像,都是弱类型语言,不像java必须指定类型(变量,返回值,传入值等)

type hint总结

可添加的类型,参阅官方文档

优点

  1. 易于理解代码,在调用函数时能更快知道输入和输出的数据类型
  2. 易于重构
  3. 易于使用库
  4. Type Linters尽早捕获错误,但是在更复杂的情况(如 嵌套函数)是检测不出来的
  5. 验证运行数据 可使用pydantic在业务逻辑运行之前自动检查,而不需要type assert
from datetime import datetime
from typing import List
from pydantic import BaseModel, ValidationError

class User(BaseModel):
    id: int
    name = 'John Doe'
    signup_ts: datetime = None
    friends: List[int] = []

external_data = {'id': '123', 'signup_ts': '2017-06-01 12:22',
                 'friends': [1, 2, 3]}
user = User(**external_data)

try:
    User(signup_ts='broken', friends=[1, 2, 'not number'])
except ValidationError as e:
    print(e.json())

使用

Python 3.5+版本
通用标准:

  • 使用语句将信息附加到变量或函数参数中。
  • ->运算符用于将信息附加到函数/方法的返回值中。

Python 3.6示例

from typing import List

class A(object):
    def __init__() -> None:
         self.elements : List[int] = []

   def add(element: int) -> None:
         self.elements.append(element)
  1. 强制你导入所有类型依赖项,即使它们根本不在运行时使用。
  2. 在类型提示中,会使用到复合类型,例如List[int]。而为了构造这些复杂类型,解释器在首次加载此文件时需要执行一些操作。

这两个问题在Python 3.7中得到解决!

from __future__ import annotations---加入该语句,将不再构造复合类型

Python2.7+版本

由于作者没用过2.7版本,本文不作赘述。

  1. 可用类型注释
  2. 类型库可作为pypi包使用

缺点: 长度限制;可能会与typelint产生冲突(通过引入typed-ast parser解决)

重点来啦

到这里,我们已经了解了type hint ,而 标准多项集中的类型标注泛型指的是什么呢?

我们不需要再导入typing的大多数类型(List,Dict),内置多项集类型如list和dict作为通用类型

tuple # typing.Tuple
list # typing.List
dict # typing.Dict
set # typing.Set
frozenset # typing.FrozenSet
type # typing.Type
collections.deque
collections.defaultdict
collections.OrderedDict
collections.Counter
collections.ChainMap
collections.abc.Awaitable
collections.abc.Coroutine
collections.abc.AsyncIterable
collections.abc.AsyncIterator
collections.abc.AsyncGenerator
collections.abc.Iterable
collections.abc.Iterator
collections.abc.Generator
collections.abc.Reversible
collections.abc.Container
collections.abc.Collection
collections.abc.Callable
collections.abc.Set # typing.AbstractSet
collections.abc.MutableSet
collections.abc.Mapping
collections.abc.MutableMapping
collections.abc.Sequence
collections.abc.MutableSequence
collections.abc.ByteString
collections.abc.MappingView
collections.abc.KeysView
collections.abc.ItemsView
collections.abc.ValuesView
contextlib.AbstractContextManager # typing.ContextManager
contextlib.AbstractAsyncContextManager # typing.AsyncContextManager
re.Pattern # typing.Pattern, typing.re.Pattern
re.Match # typing.Match, typing.re.Match

题外话: ...这个是啥?

原文: Python 为什么会有个奇怪的“...”对象?
使用场景:

  1. 扩展切片语法(?不懂,没有示例)
  2. 代替pass
  3. 在type hint中的用法

代表不定长的参数,如Tuple[int,...]表示一个元组,元素是int类型但数量不限
代表不确定的变量类型,如下例子

from typing import TypeVar, Generic

T = TypeVar('T')

def fun_1(x: T) -> T: ...  # T here
def fun_2(x: T) -> T: ...  # and here could be different

fun_1(1)                   # This is OK, T is inferred to be int
fun_2('a')                 # This is also OK, now T is str
  1. 无限循环
    对于列表和字典这样的容器,如果其内部元素是可变对象的话,则存储的是对可变对象的引用。那么,当其内部元素又引用容器自身时,就会递归地出现无限循环引用。
>>> mydict = {"name":"test"}
>>> mydict["name"] = mydict
>>> mydict
{'name': {...}}
>>> mylist = [1,2,3,]
>>> mylist[0] = mylist
>>> mylist
[[...], 2, 3]

特性四: 新的解析器

旧的:LL(1)

新的:基于PEG的新解析器

在 Python 3.10 中,旧解析器将被移除,依赖于它的所有功能也将被移除(主要是 parser 模块,它早已被弃用)。 只有 在 Python 3.9 中,你可以使用命令行开关 (-X oldparser) 或环境变量 (PYTHONOLDPARSER=1) 切换回 LL(1) 解析器。

特性五: 新增zoneinfo模块

在了解这个模块之前,我们有必要深入了解一下datetime---基本的日期和时间类型;而datetime和time之间的关联与区别可以理解为datetime基于time进行了封装;

特点: 引入IANA时区数据库

简介: zoneinfo 模块添加了 zoneinfo.ZoneInfo,这是一个基于系统时区数据的实体 datetime.tzinfo 实现。

特性六: 新增 graphlib模块

用于操作图表结构

其他特性

ast 模块新增 ast.unparse()

ast.unparse() 用于反解析ast.AST对象并产生响应的代码字符串;
ast常用于静态代码检查,代码生成等,如pylint就会用到;

asyncio模块 - 多进程线程

添加了coroutinu shutdown_default_executor(),可为等待 ThreadPoolExecutor 结束关闭的默认执行器安排关闭日程操作;

添加了asyncio.PidfdChildWatcher ,linux专属子监视器实现;

添加了 coroutine asyncio.to_thread()。 它主要被用于在单独线程中运行 IO 密集型函数以避免阻塞事件循环,实质上就相当于是 run_in_executor() 的高层级版本

random 模块

添加了random.Random.randbytes方法生成随机字节串;

结语

大概浏览了3.9的变更,发现有些东西根本没接触过(可能未来会有接触吧...)也不知道作为测试工程师 会应用在什么场景,因此不作记录。

原文地址:https://www.cnblogs.com/Tester_Dolores/p/13926241.html