2020 年 python2 停止维护,公司代码规范也鼓励使用 python3.6+版本,而随着 Python 版本的不断更新,许多旧的语法在可读性与效率上都已经有更好的替代了。当然,大部分的重要特性,例如装饰器、生成器、async 等,相信大家都非常熟悉了,这里就面向一些使用率稍微少一些、日常所见代码中不太常见的能用得上的语法做一个汇总,仅供参考。

日常的自用 Python 脚本没有太大的工程压力,能紧跟更新步伐、尝试新的特性。但是语法糖用的好就是效率提升,用的不好就是可读性灾难,有些语法的出现也伴随着种种的争议,用更新的语法不代表就能写出更好的代码。

翻看语言的更新日志确实蛮有意思

通过语法的更新变化还有变化带来的争议,也能窥透语言的设计哲学、汇聚浓缩在一个特定点上的社区开发经验。选择合适自己的、保持对代码精简可读的追求才是最重要。

那么就从老到新,理一理那些有意思的小 feature 吧。可能有漏掉有趣的点、也可能有解释不到位的地方,欢迎各位大佬更正补充。

Python 3.0-3.6

PEP 3132 可迭代对象解包拓展

Python3.0 引入,加强了原本的星号运算符(*),让星号运算符能够智能地展开可迭代对象。

>>> a, *b, c = range(5)
>>> a
0
>>> c
4
>>> b
[1, 2, 3]

隐式赋值也同样适用

>>> for a, *b in [(1, 2, 3), (4, 5, 6, 7)]:
>>>     print(b)
[2, 3]
[5, 6, 7]

注意双星号(**)不能用相同语法展开字典

人畜无害,用处也不大的一个 feature

PEP 465 矩阵乘法运算符

Python3.5 引入,顾名思义,使用@符号。直接支持 numpy、pandas 等使用。

>>> a = numpy.array([1, 2, 3])
>>> b = numpy.array([10, 20, 30])
>>> a @ b
140>>> c = numpy.array([[10, 15], [20, 25], [30, 35]])
>>> d = numpy.array([[4, 5, 6], [7, 8, 9]])
>>> c @ d
array([[145, 170, 195],[255, 300, 345],[365, 430, 495]])

矩阵乘法运算符的魔术方法为__matmul__()__rmatmul__()__imatmul__()三个

本身用处不大,但是提供了一个额外的操作符使用空间,可以用来重载来进行类似距离计算之类的用途。

>>> from math import sqrt>>> class Point:
>>>     def __init__(self, x, y):
>>>         self.x = x
>>>         self.y = y
>>>
>>>     def __matmul__(self, value):
>>>         x_sub = self.x - value.x
>>>         y_sub = self.y - value.y
>>>         return sqrt(x_sub**2 + y_sub**2)
>>>
>>> a = Point(1, 3)
>>> b = Point(4, 7)
>>> print(a @ b)
5

争议主要存在于:作为矩阵乘法来说@操作符没有直观联系、影响可读性,不如直接使用 matmul

PEP 3107/484/526 函数注解/类型提示/变量注解

Python3.0 引入函数注解、3.5 引入 typing,让 python 也能享受静态类型的福利。可以说是 py3 中个人最喜欢的 feature,使用简单、效果强大,直接让开发效率以及代码可维护性直线增长。

# 参数后加:即可标注类型,函数结构定义后接->即可标注返回类型
def get_hello(name: str) -> str:return f"Hello, {name}!"

如上进行标记之后 IDE 便能自动读取参数、返回类型,直接出联想爽快如 java。

而 PEP 484 Typing 则是极大的扩充了类型定义语法,支持别名、泛型、Callable、Union 等等。非常推荐直接阅读 PEP。

https://www.python.org/dev/peps/pep-0484/

下面就是一个泛型的例子

from typing import TypeVar, Iterable, TupleT = TypeVar('T', int, float, complex)
Vector = Iterable[Tuple[T, T]]def inproduct(v: Vector[T]) -> T:return sum(x*y for x, y in v)def dilate(v: Vector[T], scale: T) -> Vector[T]:return ((x * scale, y * scale) for x, y in v)vec = []  # type: Vector[float]

随后在 3.6 引入了众望所归的变量注解(PEP 526),使用也很简单,直接在变量后添加冒号和类型即可,搭配函数注解一起食用体验极佳

pi: float = 3.142# 也同样支持Union等
from typing import Uniona: Union[float,None] =1.0

3.7 中又引入了延迟标记求值(PEP 563),让 typing 支持了前向引用、并减轻了标注对程序启动时间的影响,如虎添翼。

# 3.7前合法
class Tree:def __init__(self, left: 'Tree', right: 'Tree'):self.left = leftself.right = right# 3.7前不合法、3.7后合法
class Tree:def __init__(self, left: Tree, right: Tree):self.left = leftself.right = right

更多的 python 类型检查示例代码:

https://github.com/realpython/materials/tree/master/python-type-checking

静态类型检查对 Python 所带来的副作用主要还是启动时间上的影响,当然大部分场景所带来的便利是远大于这一副作用的。

PEP 498 f-string

Python3.6 引入,应该是用的最多的 feature 之一了,但是看到很多代码里面还是 str.format,就不得不再提一下。

>>> a = 10
>>> #只需要简单的在任意字符串字面量前加个f,就可以用花括号直接引用变量
>>> print(f"a = {a}")
a = 10>>> # 格式化也很方便,使用:即可
>>> pi = 3.14159
>>> print(f"pi = {pi: .2f}")
pi = 3.14

也可以在表达式后接!s 或者!r 来选择用 str()还是 repr()方法转换为字符串。

基本就是 str.format 的语法糖。在 3.8 版本以后,又增加了直接套表达式的功能,输出信息非常方便。

>>> theta = 30
>>> print(f'{theta=}  {cos(radians(theta))=:.3f}')
theta=30  cos(radians(theta))=0.866

PEP 515 数值字面值下划线

Python3.6 引入。输入太长的数字字面值怎么办?

>>> a = 123_456_789
>>> b = 123456789
>>> a == b
True

比较鸡肋…

Python 3.7

PEP 557 数据类 Data Classes

提供了一个方便的 dataclass 类装饰器,直接上代码举例:

from dataclasses import dataclass@dataclass
class InventoryItem:name: strunit_price: floatquantity_on_hand: int = 0def total_cost(self) -> float:return self.unit_price * self.quantity_on_hand

对这个例子,这个类会自动生成以下魔术方法

def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0) -> None:self.name = nameself.unit_price = unit_priceself.quantity_on_hand = quantity_on_hand
def __repr__(self):return f'InventoryItem(name={self.name!r}, unit_price={self.unit_price!r}, quantity_on_hand={self.quantity_on_hand!r})'
def __eq__(self, other):if other.__class__ is self.__class__:return (self.name, self.unit_price, self.quantity_on_hand) == (other.name, other.unit_price, other.quantity_on_hand)return NotImplemented
def __ne__(self, other):if other.__class__ is self.__class__:return (self.name, self.unit_price, self.quantity_on_hand) != (other.name, other.unit_price, other.quantity_on_hand)return NotImplemented
def __lt__(self, other):if other.__class__ is self.__class__:return (self.name, self.unit_price, self.quantity_on_hand) < (other.name, other.unit_price, other.quantity_on_hand)return NotImplemented
def __le__(self, other):if other.__class__ is self.__class__:return (self.name, self.unit_price, self.quantity_on_hand) <= (other.name, other.unit_price, other.quantity_on_hand)return NotImplemented
def __gt__(self, other):if other.__class__ is self.__class__:return (self.name, self.unit_price, self.quantity_on_hand) > (other.name, other.unit_price, other.quantity_on_hand)return NotImplemented
def __ge__(self, other):if other.__class__ is self.__class__:return (self.name, self.unit_price, self.quantity_on_hand) >= (other.name, other.unit_price, other.quantity_on_hand)return NotImplemented

这一条 PEP 也是比较有争议的,主要原因是 Python 其实已经内置了不少的类似模型:collection.namedtupletyping.NamedTupleattrs

但是这条 PEP 的提出还是为了保证方便地创建资料类的同时,保证静态类型检查,而已有的方案都不方便直接使用检查器。

Python 3.8

PEP 572 海象牙运算符

"逼走"了 Guido van Rossum,最有争议的 PEP 之一。首先引入了海象牙运算符:=,代表行内赋值。

# Before
while True:command = input("> ");if command == "quit":breakprint("You entered:", command)# After
while (command := input("> ")) != "quit":print("You entered:", command)

assignment expressions 在进行分支判断时非常好用,写的时候能够舒服很多。本身使用也集中在 if/while 这种场景,虽然让语法变复杂了,但是总体还是可控的,舒适程度大于风险。

海象运算符本身问题不大,但是争议主要存在于 PEP 572 的第二点,对于生成器语义的变化。

在 PEP 572 后,生成器的in后的运算顺序产生了变化,原本是作为生成器输入,结果现在变成了生成器闭包的一部分。

temp_list = ["abc","bcd"]
result_list = (x for x in range(len(temp_list)))
print(list(result_list))# 等价于
# Before
temp_list = ["abc", "bcd"]def func_data(data: int):for x in range(data):yield xresult_list = func_data(len(temp_list))
print(list(result_list))# After
temp_list = ["abc", "bcd"]def func_data():for x in range(len(temp_list)):yield xresult_list = func_data()
print(list(result_list))

这样的修改目的是配合海象牙运算符增加代码可读性,但无疑是带破坏性的修改,且让运行顺序变得迷惑,让一些老代码出现难以发现的 bug。

python 社区在激烈辩论后,这一部分的修改被成功撤销,只保留了海象牙运算符。

PEP 570 仅限位置形参

在函数形参处新增一个/语法,划分非关键字与关键字形参。例如

def f(a, b, /, c, d, *, e, f):print(a, b, c, d, e, f)# 以下调用均合法
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

/语法的添加让调用函数时可以在可读性与简洁之间自由选择,可以选择强制不接受关键字参数、不需要形参名称时也可以省略。同时也让接受任意参数函数的实现变得方便了许多,例如:

class Counter(dict):def __init__(self, iterable=None, /, **kwds):# Note "iterable" is a possible keyword argument

这条本来也有其他方案,例如装饰器实现、def fn(.arg1, .arg2, arg3):def fn(a, (b, c), d):等,这里就不一一展开了,推荐阅读 PEP 原文。

Python 3.9

PEP 584 字典合并运算符

在此之前,要想合并两个字典的画风是这样的

a={'a':1,'b':2}
b={'c':3}a.update(b)# 或者是
c = {**a, **b}

但自从有了|之后,可以变成这样

a |= b
c = a | b

当然这个操作符也伴随着一些争议,大概是这样:

反方:合并不符合交换律 正方:python 字典合并本身就不符合交换律,特别是 python3.6 之后统一到有序字典后,相比合并应该更类似于拼接

反方:类似管道写法进行多次合并效率低,反复创建和销毁临时映射 正方:这种问题在序列级联时同样会出现。如果真出现了合并大量字典的使用场景,应当直接显式循环合并

反方:|操作符容易和位运算混淆。运算符行为强依赖于变量种类,这在 python 是非常不利于可读性的 正方:确实有这个问题,但是|已经很混乱了(位运算、集合操作、__or__()魔术方法重载),所以还是先规范变量命名吧

即将到来的 Python 3.10

PEP 617 / bpo-12782 括号内的上下文管理

这一条是针对with语法(PEP 343)的小变动,让一个with可以管理多个上下文。使用也很简单

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

比较实用,避免了 with 下面接 with 产生不必要缩进的尴尬。值得注意的是,这一条语法变动是新的非 LL(1)文法 CPython PEG 解析器所带来的副产物。所以 PEP 617 的标题是New PEG parser for CPython

PEP 634 结构化模式匹配 match-case

直接上结构:

match subject:case <pattern_1>:<action_1>case <pattern_2>:<action_2>case <pattern_3>:<action_3>case _:<action_wildcard>

是不是感觉熟悉又臭名昭著的 switch-case 终于来了?当然还是有区别的:

这个写法基本还是 if-elif-else 的语法糖,运行完 case 就自动 break 出来。再加上一些看着不错的模式匹配特性。

def http_error(status):match status:case 400:return "Bad request"case 401 | 403 | 404:return "Not allowed"case 404:return "Not found"case 418:return "I'm a teapot"case _:return "Something's wrong with the Internet"

这样的写法看着就比 if-elif-else 看着清爽了许多。针对元组、类、列表也有不错的支持:

# point is an (x, y) tuple
match point:case (0, 0):print("Origin")case (0, y):print(f"Y={y}")case (x, 0):print(f"X={x}")case (x, y):print(f"X={x}, Y={y}")case _:raise ValueError("Not a point")

结语

Python语言的发展是由技术方面的进步、工程方面的刚需汇聚而成的智慧结晶,身在其中便能体会到来自码农们创造出的代码设计之巧思、学问。只有尽可能多去理解各类语法意义,才能让开发变得流畅;了解语法的构成与其争议,在计算机科学领域的视野才会豁然开朗。与时俱进才是真正的好码神~这篇文章就到这里,如果对你有帮助的话不妨点赞、收藏、转发一下,欢迎在评论区交流以及提出宝贵意见,更多的Python实战技巧,学习资料可以私信与我交流,我会尽我所能的提供帮助!

最新总结:2021那些小众精巧的 Python 语法汇总相关推荐

  1. python编程语法大全-python语法汇总

    广告关闭 2017年12月,云+社区对外发布,从最开始的技术博客到现在拥有多个社区产品.未来,我们一起乘风破浪,创造无限可能. splitstriplen()for variable in range ...

  2. Python基础(2.3w字,无一废话)---最新更新2021.7.18

    ** 如有错误,感谢指正** 如有错误,感谢指正,请私信博主,有辛苦红包,拜"一字之师". 当你越来越漂亮时,自然有人关注你.当你越来越有能力时,自然会有人看得起你.改变自己,你才 ...

  3. 2021年用于图像处理的Python顶级库

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 介绍 正如IDC所指出的,数字信息将飙升至175 ZB,而这些信息中的巨大一部分是图片.数据科学家需要 ...

  4. 【最新】2021年注册测绘师考试测绘案例分析真题及答案解析

    [最新]2021年注册测绘师考试测绘案例分析真题及答案解析 [最新]2022年注册测绘师考试测绘案例分析真题及参考答案 [最新]2021年注册测绘师考试测绘案例分析真题及参考答案 [最新]2020年注 ...

  5. 2018python教程百度云盘_『求老2018男孩Python最新全栈开发全套视频教程』python开发 百度云教程...

    求最新python人工智能视频教程网盘链接 定的事实证明,Python更适合初学者,Python语言并不会让初学者感到晦它突破了传序语言入门困难的语法屏障,初学者在学习Python的同时,还能够锻炼自 ...

  6. 江苏计算机类大专排名,江苏公办大专排名2021最新排名 2021年江苏公办大专排名榜...

    江苏公办大专排名2021最新排名,江苏作为一个教育大省,其省内高校无数,本科院校的师资十分优异,大专院校的师资力量也是十分良好,那么,接下来和小编一起看看"江苏公办大专排名2021最新排名& ...

  7. 最新百度翻译爬虫 获取sign(python爬虫)

    环境: python3 直接上代码: Cookie.User-Agent 填自己的 1.BaiDuTranslateWeb.py import requests import execjs impor ...

  8. python交互式程序设计导论小测验答案_最新网课答案2020学堂在线Python 交互式程序设计导论...

    最新网课答案2020学堂在线Python 交互式程序设计导论 更多相关问题 [填空题] 五代西蜀花鸟画的代表画家是(). [问答题,简答题] 明代插图版画主要有哪几个流派?各派的特点是什么? [填空题 ...

  9. 南昌大学计算机学硕调剂专硕,最新!2021年考研调剂信息!

    原标题:最新!2021年考研调剂信息! 近期发现有些院校公布了21调剂信息,其中包含16所985/211院校! 已发布21调剂信息的院校 学校 学院专业 数量 山东大学 材料学院 2 控制科学与工程学 ...

最新文章

  1. Python——raise引发异常
  2. vim 高亮显示php代码
  3. 【Flink】No key set. This method should not be called outside of a keyed context.
  4. linux service和daemon
  5. UnityWebReqest和WWW,请求web数据打包到Android手机上,报错 Unknown error记录
  6. 学习WPF绝佳的去处……WPF教程,WPF入门教程,WPF视频教程
  7. ZIGBEE协议栈如何低功耗(CC2530+ZIGBEE2.5)
  8. Landsat8遥感数据大气校正
  9. 使用js打印网页局部图片(内容)
  10. Excel分压电阻计算
  11. sql 主键 外键
  12. Matlab的对角阵、三角阵,矩阵变换:矩阵的转置、旋转、翻转、求逆、方阵的行列式、矩阵的秩求解
  13. 【毕业设计】【周记】STGCN模型的改进和可视化
  14. 三、静息状态的神经元外膜
  15. 下列属于计算机应用,计算机的应用领域可大致分为6个方面,下列选项中属于计算机应用领域的是...
  16. 递推和递归:一个自下而上,一个自上而下
  17. Java杂项基础知识点总结
  18. 计算机思维 Computational Thinking(转载)
  19. ios设置中性黑体_iOS - 使用自定义字体-苹方字体
  20. 计算机综合评价论文,关于模糊综合评价记忆计算机英语论文

热门文章

  1. oppo r5 android 7.1,OPPO R5的手机系统是什么?OPPO R5能升级安卓4.4吗?
  2. mysql data masking_Dynamic Data Masking 动态数据脱敏
  3. c语言比php好学吗,php和c语言哪个难
  4. AI当“暖男”:给裸照自动穿上比基尼
  5. 服务器怎么分盘?Windows系统服务器分盘操作方法
  6. python 东方财富接口_Python从东方财富网站获取数据,python,的
  7. 缩放图片至固定大小,尺寸不足以0填充
  8. java中批量下载图片(httpClient)
  9. 地图随意搜---情景地图
  10. HCIA网络基础18-PPPoE