详解Python 3.8的海象算子:大幅提高程序执行效率

点击上方 "程序员小乐"关注, 星标或置顶一起成长

每天凌晨00点00分, 第一时间与你相约

每日英文

Don't cry over the past, it's gone. Don't stress about the future, it hasn't arrived. Live in the present and make it beautiful.

别为过去哭泣,过去已经过去。别为未来焦虑,未来还未到来。要活在当下,还要活得漂亮。

每日掏心话

是不是所有炙热过的年少,都必伴随着一次深入骨髓的经历,恍若没有彻骨地疼过就不叫爱情,好像没有壮怀激烈就算不上青春。

来自:公众号 机器之心 | 责编:乐乐

image
image.gif

程序员小乐(ID:study_tech)第 740 次推文 图片来自 Pexels

往日回顾:【图解】9张图彻底搞懂堆排序

正文

前几个月发布的 Python 3.8 包含了一项重要的新功能,即海象算子。如果合理运用,该算子能有效地提升 Python 程序的执行效率。本文将对海象算子的作用和效果进行介绍,并会通过示例演示其使用方法和不适用的场景。本文作者为软件工程师 Animesh Gaitonde。

image
image.gif

自我开始学习 Python 以及利用它的能力以来,我就一直是这门编程语言的死忠粉。Python 句法简单,易于掌握,而且有助于提升代码库的可读性和可维护性。相比于 C、C++、Java 或 Ruby 等其它高级语言,使用 Python 实现一个算法所需的代码量能少 5 倍之多。

最近,Python 社区发布了该语言的 3.8 版本。作为 Python 语法糖的爱好者,我探索了发布说明,关注到了其中一个独特的算子。这个算子被称为「海象算子(Walrus Operator)」或「命名表达式算子(Named Expression operator)」,符号为「:=」。

海象算子

这个新算子(:=)能让我们为表达式中的一个变量赋值。这个符号看起来颇有些类似于海象的眼睛和犬齿。

我们先来看看下面一段代码:

countries = [“India”, “USA”, “France”, “Germany”]``if len(countries) < 5:`` print ("Length of countries is " + len(countries))

在上面的代码段中,我们两次调用了函数 len()。我们可以避免重复计算以提升可读性吗?当然可以,我们可对这段代码进行如下改进:

country_size = len(countries)``if country_size < 5:

print ("Length of countries is " + country_size)

还有进一步改进的空间吗?我们可以不用单独一行来给「country_size」赋值吗?

if country_size := len(countries) < 5 :
  print ("Length of countries is " + country_size)

image.gif

这就是 Python 3.8 引入的海象算子的用武之地。我们可以在 if 语句之中直接执行声明和赋值操作。我们下面进一步探索该算子的能力。

代码行数与复杂度的平衡

先看看以下示例

powers = [get_count(), get_count()**2, get_count()**3]

def get_count():
  "Fetches count of records from a database"

image.gif

多次调用一个高成本的函数

上面的示例是通过多次调用一个高成本的函数 get_count() 来填充一个列表。

有了海象算子的帮助,我们可以避免多次调用函数 get_count(),其具体的功能是将结果存储到一个变量中,然后我们可在后续的计算中复用同一个变量。下面演示了海象算子的用法:

powers =[result:= get_count(), result**2, result**3]

def get_count():
  "Fetches count of records from a database"

image.gif
  • 使用海象算子避免多次调用函数*

从上面的例子可以看到,海象算子可以减少代码行数,让代码更可读,因此能简化代码审查人员的工作。此外,这也能实现代码行数和代码复杂度的平衡。

解决理解低效的问题

employees = []
for id in employee_ids:
 employee = fetch_employee(id)
 if employee:
   employees.append(employee)

image.gif

基于一个条件填充列表

上面的示例需要多次执行循环。一开始,我们创建一个空列表,然后在 id 列表上迭代并通过检查结果是否有效来填充我们创建的列表。

我们可以简化上面的代码,将其浓缩为一行:

employees = [result for id in employee_ids if (result:= fetch_employee(id))]

image.gif

使用海象算子避免低效理解

文件分块处理

在处理大文件时,我们会将文件分块读取。每当读取一个分块时,都会检查它的值,并且该值也是 while 循环的终止条件。

chunk = file.read(256)

while chunk:
   process(chunk)
   chunk = file.read(256)

image.gif

我们可以在 while 循环表达式中读取数据以及为要读取的数据赋值。由此我们就能避免在 while 循环之外显式地声明变量。如下示例:

while chunk := file.read(256) :

  process(chunk)

image.gif

正则表达式匹配

正则表达式匹配是一个两步式过程。第一步是检查是否有匹配,第二步是提取匹配的部分。

obj = re.match(info).group(1) if re.match(info) else None

image.gif

正则表达式匹配

从上面的代码可以观察到,我们在一次匹配中重复计算了 re.match(info)。这会减慢该程序的执行速度,而且数据量越大减慢得越明显。上面的代码可以重写为如下形式,从而避免重复计算:

obj = match.group(1) if match:= re.match(info) else None

image.gif

使用 := 的正则表达式匹配

不能使用海象算子的地方

为变量赋值

a = 5 # 有效
a := 5 # 无效

image.gif
empty_list = [] # 有效
empty_list := [] # 无效

image.gif

如上所示,我们不能使用 := 替代 =。海象算子只能是一个表达式的一部分。

加法/减法赋值

a += 5 # 有效
a :+=5 # 无效

image.gif

在 lambda 函数中为表达式赋值

(lambda: a:= 5) # 无效
 lambda: (a := 5) # 有效但无用
 (var := lambda: 5) # 有效

image.gif

PEP-572 及其争议

海象算子是作为 PEP-572(Python 改进提议)的一部分而引入的。如果要为 Python 语言引入一项新功能,总是需要经由 PEP 来实现,而且必须得到 Python 的发明者 Guido van Rossum 或他选择的代表的批准。

围绕海象算子的争议非常多,而且由此引发的「战争」导致了 Python 之父 Guido van Rossum 告退,不再担任 Python 社区的终身仁慈独裁者(BDFL)。海象算子的争议点有很多,下面是其中几个:

  • 句法变化问题:开发者们为 := 提议了多种替代方案,比如「表达式 -> NAME」、「NAME -> 表达式」、「{表达式} NAME」等等。少数人建议使用现有的关键字,其他人则使用了新的算子。

  • 后向兼容问题:这个特性无法向后兼容,也无法运行在之前的 Python 版本上。

  • 算子名称问题:人们建议不要使用「海象算子」这样的代号,而是使用「赋值算子」、「命名表达式算子」、「成为算子」等术语,以免人们不明白。

image
image.gif

欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。

欢迎各位读者加入程序员小乐技术群,在公众号后台回复“加群”或者“学习”即可。

猜你还想看

阿里、腾讯、百度、华为、京东最新面试题汇集

Spring的IOC原理(通俗解释)

Java 会走向晦暗吗?Kotlin 会取而代之吗

一次SQL优化的体验

关注「程序员小乐」,收看更多精彩内容

嘿,你在看吗?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容