浅析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之文件的读写和文件目录以及文件夹的操作实现代码
Aug 28 Python
获取python文件扩展名和文件名方法
Feb 02 Python
分享Pycharm中一些不为人知的技巧
Apr 03 Python
在Python中使用turtle绘制多个同心圆示例
Nov 23 Python
关于tf.nn.dynamic_rnn返回值详解
Jan 20 Python
python实现门限回归方式
Feb 29 Python
tensorflow常用函数API介绍
Apr 19 Python
Python函数__new__及__init__作用及区别解析
Aug 31 Python
python获取linux系统信息的三种方法
Oct 14 Python
python实现在列表中查找某个元素的下标示例
Nov 16 Python
tensorflow2.0教程之Keras快速入门
Feb 20 Python
python通过新建环境安装tfx的问题
May 20 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
探讨Smarty中如何获取数组的长度以及smarty调用php函数的详解
2013/06/20 PHP
兼容PHP和Java的des加密解密代码分享
2014/06/26 PHP
PHP实现搜索地理位置及计算两点地理位置间距离的实例
2016/01/08 PHP
php实现的简单中文验证码功能示例
2017/01/03 PHP
PHP中include和require的区别实例分析
2017/05/07 PHP
php unlink()函数使用教程
2018/07/12 PHP
php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
2020/02/15 PHP
JS OOP包机制,类创建的方法定义
2009/11/02 Javascript
jQuery 跨域访问问题解决方法
2009/12/02 Javascript
jQuery 自动增长的文本输入框实现代码
2010/04/02 Javascript
简单实用的反馈表单无刷新提交带验证
2013/11/15 Javascript
jQuery中each()方法用法实例
2014/12/27 Javascript
浅谈javascript中onbeforeunload与onunload事件
2015/12/10 Javascript
jQuery实现滚动鼠标放大缩小图片的方法(附demo源码下载)
2016/03/05 Javascript
基于jQuery的select下拉框选择触发事件实例分析
2016/11/18 Javascript
JavaScript实现简易的天数计算器实例【附demo源码下载】
2017/01/18 Javascript
详解从Vue.js源码看异步更新DOM策略及nextTick
2017/10/11 Javascript
vue 项目如何引入微信sdk接口的方法
2017/12/18 Javascript
关于jquery中attr()和prop()方法的区别
2018/05/28 jQuery
JavaScript相等运算符的九条规则示例详解
2019/10/20 Javascript
Django基础知识与基本应用入门教程
2018/07/20 Python
在Django中实现添加user到group并查看
2019/11/18 Python
python爬虫爬取监控教务系统的思路详解
2020/01/08 Python
python3爬取torrent种子链接实例
2020/01/16 Python
python suds访问webservice服务实现
2020/06/26 Python
Python 求向量的余弦值操作
2021/03/04 Python
详解css3 object-fit属性
2018/07/27 HTML / CSS
让IE9以下版本的浏览器兼容HTML5的方法
2014/03/12 HTML / CSS
《蚕姑娘》教学反思
2014/04/15 职场文书
个人授权委托书格式
2014/08/30 职场文书
房屋维修申请报告
2015/05/18 职场文书
排球赛新闻稿
2015/07/17 职场文书
2016年感恩教师节校园广播稿
2015/12/18 职场文书
基于Redis实现分布式锁的方法(lua脚本版)
2021/05/12 Redis
详解JS数组方法
2021/11/20 Javascript
常用的文件对应的MIME类型汇总
2022/04/26 HTML / CSS