作者:Brett Slatkin

翻译:老齐

Python3.8引入了一种叫做海象运算符(walrus)的新语法(译者注: 对于walrus的翻译,目前尚未出现对于Python的专门术语翻译,所以,此处姑且用字面意思“海象”),它其实是一种赋值语句,用于解决Python语言中长期存在的、可能导致代码重复的问题。正常的赋值语句是a=b,读作“a等于b”,而海象赋值语句是a:=b,读作“a walrus /ˈwɔːlrəs/ b”(因为:=看起来像一对眼球和獠牙,类似于海象。注意:此语句还没有适合的中文读法,总不能读作“a海象b”吧)。

海象运算符的优势在于能在不允许赋值的地方(如if语句的条件表达式中)使用赋值变量。海象运算符左侧有个标识符,赋值表达式的值等于分配给这个标识符的值。

例如,假设我有一篮子新鲜水果,我正试图经营一家果汁店。在这里,我定义了篮子里的东西:

fresh_fruit = {

'apple': 10,

'banana': 8,

'lemon': 5,

}

当顾客到柜台点柠檬水时,我需要确保篮子里至少有一个柠檬用来榨果汁。我的操作方法是检索柠檬的数量,然后使用if语句查询非零的值:

def make_lemonade(count):

...

def out_of_stock():

...

count = fresh_fruit.get('lemon', 0)

if count:

make_lemonade(count)

else:

out_of_stock()

这个看似简单的代码问题吸引了过多的关注。count变量仅在if语句的第一个代码块中使用,在if语句上方定义count会使它看起来比实际情况更为重要,好像后面的所有代码(包括else块)都需要访问count变量,然而事实并非如此。

我们获取一个值,检查它是否为非零,然后使用它。这种模式在Python中非常常见。许多程序员试图绕过多次出现count的情况,甚至不惜使用各种损害可读性的招数。现在好了,在Python3.8中增加了海象运算符,可以简化上面的代码。

if count := fresh_fruit.get('lemon', 0):

make_lemonade(count)

else:

out_of_stock()

虽然现在只是少了一行,但可读性提高很多。因为现在可以清楚地看到count只与if语句的第一行相关。赋值表达式首先为count变量赋值,然后在if语句的上下文中使用该值,以确定如何继续控制流程。这两步行为——分配和评估——是海象运算符的基本性质。

柠檬是非常有效的,所以我的柠檬水配方中只需要一个,这意味着非零检查就足够了。不过,如果顾客点了苹果酒,我需要确保至少有四个苹果。在这里,我从fruit_basket字典中获取计数,然后在if语句中使用比较表达式:

def make_cider(count):

...

count = fresh_fruit.get('apple', 0)

if count >= 4:

make_cider(count)

else:

out_of_stock()

这个问题和柠檬水的例子一样,count的赋值会分散对这个变量的注意力。在这里,我还使用了海象运算符来提高代码的清晰度:

if (count := fresh_fruit.get('apple', 0)) >= 4:

make_cider(count)

else:

out_of_stock()

这样做可以收到预期的效果,并使代码缩短了一行。需要注意的是,我需要用圆括号将赋值表达式括起来,以便与if语句中的4进行比较。在柠檬水的例子中不需要使用圆括号,因为赋值表达式本身就是一个非零检查;它不是一个较大表达式的子表达式。与其他表达式一样,应尽量避免使用圆括号把赋值表达式括起来。

有时候会出现一种类似的重复模式,那就是当我需要根据某些条件在封闭范围内分配一个变量,然后在函数中的稍后位置引用该变量。例如,假设客户订购了一些香蕉冰沙。为了制作它们,我需要至少两个香蕉的香蕉片,否则将引发OutOfBananas异常。在这里,我以一种典型的方式来实现这个逻辑:

def slice_bananas(count):

...

class OutOfBananas(Exception):

pass

def make_smoothies(count):

...

pieces = 0

count = fresh_fruit.get('banana', 0)

if count >= 2:

pieces = slice_bananas(count)

try:

smoothies = make_smoothies(pieces)

except OutOfBananas:

out_of_stock()

另一种常见的方法是将pieces=0赋值放入else块:

count = fresh_fruit.get('banana', 0)

if count >= 2:

pieces = slice_bananas(count)

else:

pieces = 0

try:

smoothies = make_smoothies(pieces)

except OutOfBananas:

out_of_stock()

第二种方法可能会让人觉得奇怪,因为这意味着pieces变量出现在了条件语句中两个不同的位置,可以在这两个位置进行初始定义。由于Python的作用域规则,这种分割定义在技术上是可行的,但它的可读性不好,也不优雅。这就是许多人喜欢上面那种结构的原因,在它里面的pieces = 0的赋值在前面出现。

海象运算符也可以用一行代码来缩短这个例子。这个小变化消除了对count变量的任何强调。现在,很明显,除了if语句之外,pieces也很重要:

pieces = 0

if (count := fresh_fruit.get('banana', 0)) >= 2:

pieces = slice_bananas(count)

try:

smoothies = make_smoothies(pieces)

except OutOfBananas:

out_of_stock()

使用海象运算符还可以提高在条件语句中分别在两个分支中的pieces复制的可读性。当count定义不再位于if语句之前时,跟踪pieces变量变得更容易:

if (count := fresh_fruit.get('banana', 0)) >= 2:

pieces = slice_bananas(count)

else:

pieces = 0

try:

smoothies = make_smoothies(pieces)

except OutOfBananas:

out_of_stock()

初学Python的程序员经常遇到的一个难题是缺少灵活的switch/case语句,与此类功能近似的一般做法是使用多个if、elif和else语句的深度嵌套。

例如,假设我想实现一个优先级系统,这样每个客户都可以自动获得最好的果汁,而不必预定。在这里,我设置这样的流程,让它先供应香蕉冰沙,然后供应苹果酒,最后供应柠檬水:

count = fresh_fruit.get('banana', 0)

if count >= 2:

pieces = slice_bananas(count)

to_enjoy = make_smoothies(pieces)

else:

count = fresh_fruit.get('apple', 0)

if count >= 4:

to_enjoy = make_cider(count)

else:

count = fresh_fruit.get('lemon', 0)

if count:

to_enjoy = make_lemonade(count)

else:

to_enjoy = 'Nothing'

像这样难看的结构在Python代码中司空见惯,幸运的是,海象运算符提供了一个优雅的解决方案,它几乎可以像switch/case语句的专用语法一样通用:

if (count := fresh_fruit.get('banana', 0)) >= 2:

pieces = slice_bananas(count)

to_enjoy = make_smoothies(pieces)

elif (count := fresh_fruit.get('apple', 0)) >= 4:

to_enjoy = make_cider(count)

elif count := fresh_fruit.get('lemon', 0):

to_enjoy = make_lemonade(count)

else:

to_enjoy = 'Nothing'

使用海象运算符版本只比原来的版本短五行,但是由于嵌套和缩进的减少,可读性有了很大提高。如果在你的代码中看到像上面那样丑陋的代买,我建议你尽量使用海象运算符重写。

初学Python的程序员常常遇到的另一个挫折是缺少do/while循环构造。例如,假设我想在新水果到货时将果汁装入瓶中,直到没有剩余的水果为止。在这里,我用while循环实现这个逻辑:

def pick_fruit():

...

def make_juice(fruit, count):

...

bottles = []

fresh_fruit = pick_fruit()

while fresh_fruit:

for fruit, count in fresh_fruit.items():

batch = make_juice(fruit, count)

bottles.extend(batch)

fresh_fruit = pick_fruit()

这里存在重复,先后执行了两次fresh_fruit = pick_fruit(),一个在循环前设置初始条件,另一个在循环结束时补充到货的水果列表。

在这种情况下,改进代码复用的策略是使用loop-and-a-half(如果出现这种情况,需要立即退出并跳过循环体中的任何剩余语句)。这消除了多余的行,但它也破坏了while循环,使其成为一个愚蠢的无限循环。现在,循环的所有流控制都依赖于break条件语句:

bottles = []

while True: # Loop

fresh_fruit = pick_fruit()

if not fresh_fruit: # And a half

break

for fruit, count in fresh_fruit.items():

batch = make_juice(fruit, count)

bottles.extend(batch)

海象运算符消除了对loop-and-a-half的需要。方法是:允许重新设置fresh_fruit变量,然后每次都通过while循环有条件地求值。此解决方案简短易读,应该是代码中的首选方法:

bottles = []

while fresh_fruit := pick_fruit():

for fruit, count in fresh_fruit.items():

batch = make_juice(fruit, count)

bottles.extend(batch)

在许多其他情况下,可以使用还有海象运算符的赋值表达式来消除冗余。通常,当你发现自己在许多行中多次重复同一个表达式或赋值时,应该考虑使用海象运算符来提高可读性。

牢记

赋值表达式使用walrus运算符(:=)在单个表达式中同时对变量名进行赋值和计算,从而减少重复。

当赋值表达式是一个较大表达式的子表达式时,它必须用圆括号括起来。

尽管在Python中不能用switch/case语句和do/while循环,但是通过使用海象运算符的赋值表达式可以更清楚地模拟它们的功能。

python范围运算符_Python的海象运算符相关推荐

  1. python海象运算符_Python 中海象运算符的三种用法

    首发于微信公众号:<Python编程时光> 系列导读 Python 版本发展非常快,如今最新的版本已经是 Pyhton 3.9,即便如此,有很多人甚至还停留在 3.6 或者 3.7,连 3 ...

  2. Python 炫技操作:海象运算符的三种用法

    作者 | 明哥 来源 |  Python编程时光(ID:Cool-Python) Python 版本发展非常快,如今最新的版本已经是 Pyhton 3.9,即便如此,有很多人甚至还停留在 3.6 或者 ...

  3. 很多人不知道的Python 炫技操作:海象运算符的三种用法

    Python 炫技操作--海象运算符的三种用法 1. 第一个用法:if/else 2. 第二个用法:while 3. 第三个用法:推导式 Python 版本发展非常快,如今最新的版本已经是 Pyhto ...

  4. python关系运算符中表示不等于的关系运算符_Python学习之------运算符表达式(关系运算符,逻辑运算符,三元表达式,成员关系)...

    @详细看Python学习手册第121页. 1,算术运算符(加减乘除) 2,关系运算符(又叫比较运算符 > < == != >= <=) xy,x>=y    大小比较,返 ...

  5. python中的运算符_Python中的运算符

    说完常用的数据类型,再来说下运算符.运算符用于将各种类型的数据进行运算,让静态的数据跑起来. 编程语言中的运算大致分为以下几个大类: 算术运算, 用于加减乘除等数学运算 赋值运算,用于接收运算符或方法 ...

  6. python 复数幂_python基础学习——运算符(1)

    python非常显著的一个特点是计算能力超级强,支持各种计算,本文主要介绍几大常用的运算符在python中的应用方法:包括7大运算符:算术运算符.比较运算符.赋值运算符.逻辑运算符.成员运算符.身份运 ...

  7. python 按位运算符_Python按位运算符

    python 按位运算符 Python bitwise operators are used to perform bitwise calculations on integers. The inte ...

  8. python不等于运算符_Python不等于运算符

    python不等于运算符 Python not equal operator returns True if two variables are of same type and have diffe ...

  9. python百分号转义_python 转义字符、运算符、列表。。。。

    1.转义字符 \n :表示换行 2.如何查看数据类型的函数type() 练习:helloworld strintfloatboolnonetype print(type('hello world')) ...

最新文章

  1. Python 字符串处理(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)
  2. 动态编译MySQL plugin
  3. Android根据URL下载文件保存到SD卡
  4. SQL 導入導出大全
  5. django系列 - 安装和新建项目
  6. EPUB PDF DOCX格式转换及主流格式电子书制作终极攻略(内含用WORD制作精美EPUB方法)...
  7. Django搭建个人博客之制作app并配置相关环境
  8. android 拷贝大文件,不用数据线,手机和电脑互传大文件
  9. 【AE】缺少Color属性或方法解决办法
  10. 程序员突破年薪50万的唯一门坎-文档写作能力(一)
  11. UI设计书籍推荐,这三本好书你不能错过
  12. Spring IOC介绍
  13. 结庐在人境,而无车马喧
  14. uniapp——操作成功返回首页
  15. 《C++ Primer Plus》学习笔记-string类和标准模板库
  16. 全连接神经网络(FCNN)
  17. 方舟服务器 mod文件夹,方舟mod文件夹应该放在哪 | 手游网游页游攻略大全
  18. 2020-10-1 交换机通过CRT保存配置-telnet
  19. cocos2d-x动画加速与减速
  20. 2009年世界顶级杀毒软件排名

热门文章

  1. [UE4.4.x] 虚幻4 安卓打包
  2. 阿里发布天猫精灵X1 探索人机交互新大陆
  3. 利用DEDE正则批量查找替换数据库的自定义内容
  4. scp在Linux主机之间copy不用输入密码
  5. 关于C/C++中的几个关键字(C基础)
  6. 山西计算机应用基本技能,计算机应用基本技能 山西省对口高考题库
  7. android m在哪下载地址,android m预览版SDK下载地址 android m预览版SDK下载网址
  8. 神经网络特征图计算_GNNFiLM:基于线性特征调制的图神经网络
  9. word2016开机后首次打开非常慢_5款iPhone实测 iOS 13.4.1运行速度:升级后表现更糟糕?...
  10. python编写脚本pdf_你用 Python 写过哪些有趣的脚本?