浅析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实现115网盘自动下载的方法
Sep 30 Python
Python中给List添加元素的4种方法分享
Nov 28 Python
python中的随机函数小结
Jan 27 Python
python在文本开头插入一行的实例
May 02 Python
python按修改时间顺序排列文件的实例代码
Jul 25 Python
OpenCV Python实现拼图小游戏
Mar 23 Python
python实现扫雷小游戏
Apr 24 Python
python 实现任务管理清单案例
Apr 25 Python
关于pycharm 切换 python3.9 报错 ‘HTMLParser‘ object has no attribute ‘unescape‘ 的问题
Nov 24 Python
python 如何获取页面所有a标签下href的值
May 06 Python
总结Pyinstaller打包的高级用法
Jun 28 Python
 分享一个Python 遇到数据库超好用的模块
Apr 06 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使用imagick模块实现图片缩放、裁剪、压缩示例
2014/04/17 PHP
php smarty模板引擎的6个小技巧
2014/04/24 PHP
PHP中使用imagick实现把PDF转成图片
2015/01/26 PHP
解决laravel(5.5)访问public报错的问题
2019/10/12 PHP
调整小数的格式保留小数点后两位
2014/05/14 Javascript
js父页面中使用子页面的方法
2016/01/09 Javascript
AngularJS ng-change 指令的详解及简单实例
2016/07/30 Javascript
使用jQuery Ajax 请求webservice来实现更简练的Ajax
2016/08/04 Javascript
js实现弹窗居中的简单实例
2016/10/09 Javascript
Angular指令之restict匹配模式的详解
2017/07/27 Javascript
JavaScript实现图片本地预览功能【不用上传至服务器】
2017/09/20 Javascript
vue.js 微信支付前端代码分享
2018/02/10 Javascript
js使用文件流下载csv文件的实现方法
2019/07/15 Javascript
js+HTML5 canvas 实现简单的加载条(进度条)功能示例
2019/07/16 Javascript
基于layui table返回的值的多级嵌套的解决方法
2019/09/19 Javascript
vue elementUI 表单校验的实现代码(多层嵌套)
2019/11/06 Javascript
vue 根据选择条件显示指定参数的例子
2019/11/09 Javascript
Vue 路由间跳转和新开窗口的方式(query、params)
2019/12/25 Javascript
JavaScript自定义超时API代码实例
2020/04/30 Javascript
在antd Table中插入可编辑的单元格实例
2020/10/28 Javascript
JavaScript 异步时序问题
2020/11/20 Javascript
js用正则表达式筛选年月日的实例方法
2021/01/04 Javascript
[40:19]2018完美盛典CS.GO表演赛
2018/12/17 DOTA
详解Python nose单元测试框架的安装与使用
2017/12/20 Python
应用OpenCV和Python进行SIFT算法的实现详解
2019/08/21 Python
用pytorch的nn.Module构造简单全链接层实例
2020/01/14 Python
python3爬取torrent种子链接实例
2020/01/16 Python
CSS3使用transition属性实现过渡效果
2018/04/18 HTML / CSS
采用专利算法搜索最廉价的机票:CheapAir
2016/09/10 全球购物
外语专业毕业生个人的自荐信
2013/11/19 职场文书
房屋改造计划书
2014/01/10 职场文书
公关活动策划方案
2014/05/25 职场文书
学习教师敬业奉献模范事迹材料思想汇报
2014/09/19 职场文书
《乌鸦喝水》教学反思
2016/02/19 职场文书
导游词之峨眉乐山/兵马俑/北京故宫御花园
2019/09/03 职场文书
MySQL中使用or、in与union all在查询命令下的效率对比
2021/05/26 MySQL