Py学习  »  Python

Python 3.8 新运算符 := 让我们懒出新高度

Python猫 • 1 周前 • 350 次点击  


背景

Python 的语法风格确实是懒人福音,真是做到了多写一行都是罪。就拿 Python-3.8 版本来说吧,为了少写一行代码,直接搞出了一个新的运算符 `:= `。

先给结论!这个运算符不是必要的。也就是说没有它我们也能写程序,只是有了它之后我们的代码可以更加简洁。

下面我就来说一下这个运算符的故事!


阶段 一

这个阶段大家做事都中规中矩,代码上直抒胸臆。给个例子吧。假设我们有一个函数,它是用来处理列表的,它会在处理之前检查一下列表的长度,当长度大于 7 时直接退出。阶段一这个时候的代码看起来如下。

def fun(lst=None):    """    Parameters:        lst: 列表        Return:        None    """    #     if len(lst) > 7:        print(f"len(lst) = {len(lst)}  gt 7 , not supported .")        return         # 其它逻辑

这里有一个小小的问题,就是 `len(lst)` 在命中 if 的语句时候它还会在 print 语句里面再被计算一次。如果计算本身的开销就比较高,少计算一次就非常有吸引力了,阶段二就是向这个方向进化的。


阶段二

阶段二的写法也是非常直接,只要保存一下第一次计算的结果,第二次的时候直接取结果,这样就不用再计算一次了。上代码

def fun(lst=None):    """    Parameters:        lst: 列表        Return:        None    """    #     n = len(lst)    if n > 7:        print(f"len(lst) = {n}  gt 7 , not supported .")        return         # 其它逻辑

阶段二的写法也不是完全没有可以改进的地方,我们看 n 其实只在 if 块里面有用到,但是它的声明位置是在 if 之外的。这个就给人一种,这个 n 非常重要后面的代码还会用到它的感觉。也就是说这种写法没有办法表现出 n 就是一个临时变量

好在这种语义已经可以在 Python-3.8 这个版本中表达了,不过我们要借助全新的运算符 `:=` 来实现。 详细的请看阶段三。


阶段三

阶段三是真正的做到了形与意合,并且没有什么学习成本,语法上可以说是一看就懂,我直接上代码。

def fun(lst=None):    """    Parameters:        lst: 列表        Return:        None    """    #         if (n:= len(lst)) > 7:        print(f"len(lst) = {n}  gt 7 , not supported .")        return         # 其它逻辑

现在从词法上看,就能非常明确地知道 n 只在 if 语句内起作用。由于阶段三只是阶段二的语法糖,也就是说从作用域上来讲 n 在 if 语句之后还是可以正常访问,这个应该就是唯一美中不足的地方了吧。



为什么说  :=  是语法糖

这一点是从官方文档上不能直接看出来的,需要我们去看 fun 函数两种不同写法,编译出来的字节码。

In [1]: import dis
In [2]: def fun(lst=None): ...: """ ...: Parameters: ...: lst: 列表 ...: ...: Return: ...: None ...: """ ...: # ...: ...: if (n:= len(lst)) > 7: ...: print(f"len(lst) = {n} gt 7 , not supported .") ...: return ...:
In [3]: dis.dis(fun) 1 0 RESUME 0
11 2 LOAD_GLOBAL 1 (NULL + len) 14 LOAD_FAST 0 (lst) 16 PRECALL 1 20 CALL 1 30 COPY 1 32 STORE_FAST 1 (n) 34 LOAD_CONST 1 (7) 36 COMPARE_OP 4 (>) 42 POP_JUMP_FORWARD_IF_FALSE 21 (to 86)
12 44 LOAD_GLOBAL 3 (NULL + print) 56 LOAD_CONST 2 ('len(lst) = ') 58 LOAD_FAST 1 (n) 60 FORMAT_VALUE 0 62 LOAD_CONST 3 (' gt 7 , not supported .') 64 BUILD_STRING 3 66 PRECALL 1 70 CALL 1 80 POP_TOP
13 82 LOAD_CONST 4 (None) 84 RETURN_VALUE
11 >> 86 LOAD_CONST 4 (None) 88 RETURN_VALUE
In [4]: def fun(lst=None): ...: """ ...: Parameters: ...: lst: 列表 ...: ...: Return: ...: None ...: """ ...: # ...: n = len(lst) ...: if n > 7: ...: print(f"len(lst) = {n} gt 7 , not supported .") ...: return ...:
In [5]: dis.dis(fun) 1 0 RESUME 0
10 2 LOAD_GLOBAL 1 (NULL + len) 14 LOAD_FAST 0 (lst) 16 PRECALL 1 20 CALL 1 30 STORE_FAST 1 (n)
11 32 LOAD_FAST 1 (n) 34 LOAD_CONST 1 (7) 36 COMPARE_OP 4 (>) 42 POP_JUMP_FORWARD_IF_FALSE 21 (to 86)
12 44 LOAD_GLOBAL 3 (NULL + print) 56 LOAD_CONST 2 ('len(lst) = ') 58 LOAD_FAST 1 (n) 60 FORMAT_VALUE 0 62 LOAD_CONST 3 (' gt 7 , not supported .') 64 BUILD_STRING 3 66 PRECALL 1 70 CALL 1 80 POP_TOP
13 82 LOAD_CONST 4 (None) 84 RETURN_VALUE
11 >> 86 LOAD_CONST 4 (None) 88 RETURN_VALUE

可以看到阶段三和阶段二的字节码是一模一样的。


以上是今天的分享,最后推荐一下我的《Python潮流周刊》专栏。试运行付费模式,目前最低价,即将涨价!欢迎订阅。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/169387
 
350 次点击