浅析PEP572: 海象运算符


Posted in Python onOctober 15, 2019

现在已经是Python 3.8的最后一个alpha版本,接着就是本月底要发布的的3.8.0 beta 1了。按规定,3.8已经不会再添加(修改)功能了,之前非常有争议的PEP 572的实现已经算是很固定了,我们这篇文章就来先尝个鲜。看看这个新的赋值表达式语法怎么用,何时用。

海象运算符

PEP572的标题是「Assignment Expressions」,也就是「赋值表达式」,也叫做「命名表达式」,不过它现在被广泛的别名是「海象运算符」(The Walrus Operator)。因为:=很像海象「眼睛小,长着两枚长长的牙」这个特点^_^。

语法和语义

我们不详细介绍PEP的内容,直接说应用场景。我觉得它主要可以用在2个地方

赋值给中间变量

这个小标题想了很久,没找到更合适能表达的。不过相信通过2个例子相信大家就能理解了。

首先是一个正则匹配的例子:

pattern = re.compile('s')
data = 'ss'
if pattern.match(data):
  print(pattern.match(data).group(0))

如果能匹配到条件,match 对象才会有group 方法。但是这样写虽然节省到一行代码却让执行变慢了,因为重复地执行了2次re.match(data)。正确的写法是:

match = pattern.match(data)
if match:
  print(match.group(0))

代码也就只能写成这样了,但如果使用赋值表达式:

if (match := pattern.match(data)) is not None:
  print(match.group(0))

本来if这种控制结构语句只是求值表达式,看结果是不是符合条件。而在这里,它做了3件事:

  • 对表达式pattern.match(data)求值
  • 把值的结果赋值给match
  • 把match 作为if的条件,判断它的值是不是None

我对它的理解是: 求值过程中也赋值了新的中间变量,这个(些)中间变量(如这里的match)可以在代码块中被继续使用。

再看一个文件读取的例子:

while 1:
  line = fp.readline()
  if not line:
    break
  print(line)

现在可以直接写成:

while (line := fp.readline()):
  print(line)

这可以说是一种代码风格的改进了。

简化列表解析

列表解析性能好,而且非常 pythonic,但是它应用场景有限,我们看个例子:

results = []
for x in data:
  result = f(x)
  if result:
    results.append(result)

这是一个日常开发里面比较常见的结构。现在是不能用列表解析的,不信的话下面的方案:

results = [
  f(x) for x in data
  if f(x)
]

这个是错误的,每次循环执行了2 次f函数。现在用赋值表达式可以写成:

results = [
  y for x in data
  if (y := f(x))
]

可以用列表解析了!

再看一个PEP提的例子:

stuff = [[y := f(x), x/y] for x in range(5)]

其实又回到了赋值给中间变量这个点,每一项包含了y,以及要用y才能获得结果的x/y。

上面说的就是海象运算符能实现的目的了~

Golang里面的:=

:=并不是Python首创的,Golang里面有一个短变量声明(Short variable declarations)语法:

// ShortVarDecl = IdentifierList ":=" ExpressionList .
i, j := 0, 10
f := func() int { return 7 }

func f(n int) (res int, err error) {
  if _, err := f(n-1); err != nil {
    return
  }
  return
}

:=的作用是替代 var 定义,声明时不需要指定类型。同时由于语言设计,和Python的赋值表达式一样,如上面的例子,f(n-1)的第二个返回值err可以被后面的err != nil使用,用来判断条件是否成立,我非常喜欢!

我对PEP 572的看法

在之前我曾经在知乎回答过「如何看待 PEP 572 ?」这个问题,当时我这么说:

这个PEP 有明确的 Recommended use-cases, 在正确的地方使用,而不是滥用,当然不喜欢的可以不用,用旧的形式。我语言提供了更多特性和选择的机会,但控制权是开发者手里的,就像元类、描述符、dataclass 甚至装饰器等等都是有适用场景的。

有人觉得它不符合Python之禅,其实我个人感觉挺好的呀。现在PEP 572的实现已经合并到Python3.8,试用下来非常赞。

Dustin Ingram在PyCON2019上做了一个《PEP 572: The Walrus Operator》的分享,最后他也说自己不喜欢这个语法,但是他接着说:

You might say well i don't like it, that's totally fine. you don't have to like it if you don't like it then don't write it

我觉得说的非常好,没人强制你必须使用它~

好了,本文就给大家介绍到这里,希望对大家有所帮助!

Python 相关文章推荐
python根据出生日期获得年龄的方法
Mar 31 Python
用PyQt进行Python图形界面的程序的开发的入门指引
Apr 14 Python
使用C语言扩展Python程序的简单入门指引
Apr 14 Python
python3 模拟登录v2ex实例讲解
Jul 13 Python
Python优先队列实现方法示例
Sep 21 Python
python构建深度神经网络(DNN)
Mar 10 Python
python判断一个集合是否为另一个集合的子集方法
May 04 Python
Python+OpenCv制作证件图片生成器的操作方法
Aug 21 Python
python使用pyecharts库画地图数据可视化的实现
Mar 25 Python
Django实现任意文件上传(最简单的方法)
Jun 03 Python
pycharm 2020 1.1的安装流程
Sep 29 Python
python实现经典排序算法的示例代码
Feb 07 Python
Python 导入文件过程图解
Oct 15 #Python
Python3.8对可迭代解包的改进及用法详解
Oct 15 #Python
Python 3.8正式发布,来尝鲜这些新特性吧
Oct 15 #Python
Python3安装pip工具的详细步骤
Oct 14 #Python
python区分不同数据类型的方法
Oct 14 #Python
django中瀑布流写法实例代码
Oct 14 #Python
python 中Arduino串口传输数据到电脑并保存至excel表格
Oct 14 #Python
You might like
新手学习PHP的一些基础知识分享
2011/07/27 PHP
php命令行(cli)下执行PHP脚本文件的相对路径的问题解决方法
2015/05/25 PHP
PHP实现的装箱算法示例
2018/06/23 PHP
PHP序列化的四种实现方法与横向对比
2018/11/29 PHP
javascript 日历提醒系统( 兼容所有浏览器 )
2009/04/07 Javascript
javascript 写类方式之六
2009/07/05 Javascript
js与jquery中获取当前鼠标的x、y坐标位置的代码
2011/05/23 Javascript
原生javascript兼容性测试实例
2013/07/01 Javascript
IE与FireFox的JavaScript兼容问题解决办法
2013/12/31 Javascript
用javascript将数据导入Excel示例代码
2014/09/10 Javascript
JavaScript中变量声明有var和没var的区别示例介绍
2014/09/15 Javascript
textarea 在浏览器中固定大小和禁止拖动的实现方法
2016/12/03 Javascript
js手机号批量滚动抽奖实现代码
2020/04/17 Javascript
JS模拟超市简易收银台小程序代码解析
2017/08/18 Javascript
Vue-Router基础学习笔记(小结)
2018/10/15 Javascript
vue设计一个倒计时秒杀的组件详解
2019/04/06 Javascript
深入浅析vue-cli@3.0 使用及配置说明
2019/05/08 Javascript
简述pm2常用命令集合及配置文件说明
2019/05/30 Javascript
vue实例的选项总结
2020/06/09 Javascript
微信小程序实现canvas分享朋友圈海报
2020/06/21 Javascript
vue-router路由懒加载及实现的3种方式
2021/02/28 Vue.js
vue实现可移动的悬浮按钮
2021/03/04 Vue.js
Python的Flask框架中SQLAlchemy使用时的乱码问题解决
2015/11/07 Python
Python列表和元组的定义与使用操作示例
2017/07/26 Python
Python datetime和unix时间戳之间相互转换的讲解
2019/04/01 Python
Pandas之DataFrame对象的列和索引之间的转化
2019/06/25 Python
用python写测试数据文件过程解析
2019/09/25 Python
Python中base64与xml取值结合问题
2019/12/22 Python
Python语法之精妙的十个知识点(装B语法)
2020/01/18 Python
pytorch对梯度进行可视化进行梯度检查教程
2020/02/04 Python
python3操作注册表的方法(Url protocol)
2020/02/05 Python
护理学中专毕业生求职信
2013/11/11 职场文书
幼儿园校车司机的岗位职责
2014/01/30 职场文书
学生会招新策划书
2014/02/14 职场文书
2016年社区中秋节活动总结
2016/04/05 职场文书
用Python简陋模拟n阶魔方
2021/04/17 Python