啥样的python语法值得收藏?_python象牙符号(1)

# 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 <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看着清爽了许多。

针对元组、类、列表也有不错的支持:

(1)Python所有方向的学习路线(新版)

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。

在这里插入图片描述

(2)Python学习视频

包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。

在这里插入图片描述

(3)100多个练手项目

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里无偿获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值