浅析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的Django框架中创建语言文件
Jul 27 Python
Python reduce()函数的用法小结
Nov 15 Python
使用Python+Splinter自动刷新抢12306火车票
Jan 03 Python
对Python 3.5拼接列表的新语法详解
Nov 08 Python
python实现定时发送qq消息
Jan 18 Python
局域网内python socket实现windows与linux间的消息传送
Apr 19 Python
Django后端接收嵌套Json数据及解析详解
Jul 17 Python
Python使用scipy模块实现一维卷积运算示例
Sep 05 Python
使用python实现kNN分类算法
Oct 16 Python
Python模块的制作方法实例分析
Dec 21 Python
详解python中各种文件打开模式
Jan 19 Python
python dict乱码如何解决
Jun 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开发入门教程之面向对象
2006/12/05 PHP
PHP调用wsdl文件类型的接口代码分享
2014/11/19 PHP
PHP单态模式简单用法示例
2016/11/16 PHP
PHP实现多图上传(结合uploadify插件)思路分析
2016/11/30 PHP
javascript 导出数据到Excel(处理table中的元素)
2009/12/18 Javascript
js取滚动条的尺寸的函数代码
2011/11/30 Javascript
ko knockoutjs动态属性绑定技巧应用
2012/11/14 Javascript
jquery的attr方法禁用表单元素禁用输入内容
2014/06/23 Javascript
javascript格式化指定日期对象的方法
2015/04/21 Javascript
JS实现网页Div层Clone拖拽效果
2015/09/26 Javascript
javascript图片预加载完整实例
2015/12/10 Javascript
Javascript函数中的arguments.callee用法实例分析
2016/09/16 Javascript
老生常谈原生JS执行环境与作用域
2016/11/22 Javascript
JavaScript原生编写《飞机大战坦克》游戏完整实例
2017/01/04 Javascript
NodeJS测试框架mocha入门教程
2017/03/28 NodeJs
Bootstrap Table快速完美搭建后台管理系统
2017/09/20 Javascript
详解webpack-dev-server 设置反向代理解决跨域问题
2018/04/18 Javascript
使用Python脚本在Linux下实现部分Bash Shell的教程
2015/04/17 Python
python装饰器初探(推荐)
2016/07/21 Python
python解决方案:WindowsError: [Error 2]
2016/08/28 Python
基于python 二维数组及画图的实例详解
2018/04/03 Python
浅谈django rest jwt vue 跨域问题
2018/10/26 Python
详解Python 解压缩文件
2019/04/09 Python
python实现批量处理将图片粘贴到另一张图片上并保存
2019/12/12 Python
Python实现Word文档转换Markdown的示例
2020/12/22 Python
把富文本的回车转为br标签
2019/08/09 HTML / CSS
捷克浴室和厨房设备购物网站:SIKO
2018/08/11 全球购物
中专自荐信
2013/10/13 职场文书
员工拾金不昧表扬信
2014/01/09 职场文书
公司离职证明标准范本
2014/10/05 职场文书
初中差生评语
2014/12/29 职场文书
2015年学校关工委工作总结
2015/04/03 职场文书
医者仁心观后感
2015/06/17 职场文书
推广普通话宣传标语口号
2015/12/26 职场文书
用golang如何替换某个文件中的字符串
2021/04/25 Golang
设置IIS Express并发数
2022/07/07 Servers