值得收藏的python语法总结

python2早已在 2020 年停止维护,随着Python版本的不断更新迭代,很多旧的语法在可读性与效率上都已经有更好的替代了。当然,大部分的重要特性,例如装饰器、生成器、async等,相信大家都已经了然于心,本文小编就对一些用的稍微少一些、日常看到的代码中不太常见,但是能用得上的语法做一个简单的总结,供大家参考,如果大家有什么不同的见解,还望各位大佬们多多指导、补充。

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

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

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

Python 3.0-3.6

PEP 3132 可迭代对象解包拓展

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

Python学习交流1裙 815624229 ###
Python学习交流2裙 279199867 ###
>>> 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。

下面就是一个泛型的例子

from typing import TypeVar, Iterable, Tuple

T = 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 Union

a: Union[float,None] =1.0

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

3.7前合法
class Tree:
    def __init__(self, left: 'Tree', right: 'Tree'):
        self.left = left
        self.right = right

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

静态类型检查对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: str
    unit_price: float
    quantity_on_hand: int = 0

    def 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 = name
    self.unit_price = unit_price
    self.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.namedtuple、typing.NamedTuple、attrs等 ;

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

Python 3.8

PEP 572 海象牙运算符

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

Before
while True:
    command = input("> ");
    if command == "quit":
        break
    print("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 x

result_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 x

result_list = func_data()
print(list(result_list))

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

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

关于这个PEP,知乎上有难得一见的有价值讨论,这部分范例代码也引用自此。

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 :

    case :

    case :

    case _:

是不是感觉熟悉又臭名昭著的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")

结语

语言的发展是由技术的进步、工程的需求凝结出的结晶,从中透露出的是满满的代码设计哲学。充分了解语法,可以让开发变得顺畅舒适;理解了语法背后的原因与争议,则可以开拓计算机科学领域的视野。与时俱进,深入了解各种新兴技术,才是真正的极客~

Original: https://www.cnblogs.com/hahaa/p/16400588.html
Author: 轻松学Python
Title: 值得收藏的python语法总结

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/810128/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • python使用numpy求两个数组的并集交集差集(图像)

    import numpy as np array1=np.array([3,2,-1,100]) array2=np.array([0,-5,100,20]) "&quo…

    Python 2023年8月2日
    052
  • 科学计算和数据分析

    *案例目的 科学计算(Scientific Computing),泛指使用计算机科学基于数学建模和数值分析技术,解决科学工程领域中问题的过程,科学计算是计算机科学,数学和工程的交叉…

    Python 2023年9月4日
    040
  • python字典dict与json数据转换

    JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。现在的接口请求request params和response body,…

    Python 2023年8月1日
    048
  • Python实战项目:并夕夕版飞机大战(源码分享)(文章较短,直接上代码)

    ✌ 作者简介:信年✘ ✌,大家可以叫我 ❤信年❤ ,一位精通五门语言的博主 ✌ 🏆 CSDN博客专家认证、华为云享专家、阿里云专家博主 、掘金创作榜No.1 📫 如果文章知识点有错…

    Python 2023年9月21日
    039
  • python如何利用百度_练习项目20:使用python制作游戏(中)

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 上一篇教程,我们通过实现一个敌机由上至下的循环过程,初步了解了pygame这个模块的使用。 接下来,我们进行第二阶段,真正的实现一个通…

    Python 2023年9月25日
    051
  • scrapy框架初识1

    目录 scrapy框架介绍: scrapy框架的基本使用: scrapy数据解析操作: ​scrapy持久化存储: 将爬取到的数据一份存储到本地一份存储到数据库,如何实现? scr…

    Python 2023年10月1日
    061
  • 目标需要分解,行动需要激励

    我们平时常常出现的情形:1.凡事必须看到结果才行动,看不到结果前,别人说的再好,也觉得那都是别人想象的,自己看不到结果前,绝对不行动;2.在做事情时,还没开始行动前,总是想着是不是…

    Python 2023年6月15日
    054
  • 电话机器人源码支持独立部署+图文介绍

    电销机器人五大核心技术 一、语音识别(ASR) 语音识别技术,也被称为自动语音识别Automatic Speech Recognition,其能够将人类的语音中的词汇内容转换为计算…

    Python 2023年11月8日
    036
  • vue项目的首屏优化策略

    虽然标题是vue项目的首屏优化策略,但是里面绝大部分的方法,对于其他语言写成的单页应用同样适用 首屏进入时,直接加载和首屏相关路由,其他全部路由组件实现懒加载,即打开该路由时再去加…

    Python 2023年8月22日
    046
  • bootstrap + django的简单后台管理系统

    文章目录 登录页面 * Form和MiddleForm的书写 HTML代码: 信息管理页面 * 母版HTML代码 管理员信息 – 各种功能页面 Ajax数据传输 * J…

    Python 2023年8月3日
    097
  • 吴恩达深度学习笔记——DAY2

    目录 一、梯度下降法 二、向量化(Vectorization) 三、Python 中的广播(Broadcasting in Python) 一、梯度下降法 梯度下降法在测试集上,通…

    Python 2023年8月28日
    054
  • python

    python学习:Python爬虫编程基础5天速成(2021全新合集)Python入门+数据分析_哔哩哔哩_bilibili 目录 pycharm最新版如何设置自动换行 时间戳: …

    Python 2023年8月12日
    082
  • 【Linux】Linux调试器-gdb使用及git命令行

    大家好我是沐曦希💕 文章目录 一.预备知识 * 1.背景 2.Linux默认行为 3.debug和release区别 二.使用 三.使用git命令行 一.预备知识 1.背景 程序的…

    Python 2023年9月16日
    062
  • 还在担心CC攻击? 让我们来了解它, 并尽可能将其拒之服务之外.

    还在担心CC攻击? 让我们来了解它, 并尽可能将其拒之服务之外. CC攻击是什么? 基本原理 CC原名为ChallengeCollapsar, 这种攻击通常是攻击者通过大量的代理机…

    Python 2023年6月12日
    081
  • Pandas+Pyecharts | 山东省高考考生数据分析可视化

    文章目录 🏳️‍🌈 1. 导入模块 🏳️‍🌈 2. Pandas数据处理 * 2.1 读取数据 2.2 行数据填充,重置列索引,去除前2行 🏳️‍🌈 3. Pyecharts可视化…

    Python 2023年8月7日
    060
  • 开始使用DataGrip —— 激活

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Python 2023年6月9日
    067
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球