技术标签: 数据分析 编程语言 人工智能 大数据 switch
导读:赋值表达式(assignment expression)是Python 3.8新引入的语法,它会用到海象操作符(walrus operator)。这种写法可以解决某些持续已久的代码重复问题。a = b是一条普通的赋值语句,读作a equals b,而a := b则是赋值表达式,读作a walrus b。
这个符号为什么叫walrus呢?因为把:=顺时针旋转90°之后,冒号就是海象的一双眼睛,等号就是它的一对獠牙。
作者:布雷特·斯拉特金(Brett Slatkin)
来源:大数据DT(ID:hzdashuju)
这种表达式很有用,可以在普通的赋值语句无法应用的场合实现赋值,例如可以用在条件表达式的if语句里面。赋值表达式的值,就是赋给海象操作符左侧那个标识符的值。
举个例子。如果有一筐新鲜水果要给果汁店做食材,那我们就可以这样定义其中的内容:
fresh_fruit = {
'apple': 10,
'banana': 8,
'lemon': 5,
}
顾客点柠檬汁之前,我们先得确认现在还有没有柠檬可以榨汁。所以,要先查出柠檬的数量,然后用if语句判断它是不是非零的值。
def make_lemonade(count):
print(f'Making {count} lemons into lemonade')
def out_of_stock():
print('Out of stock!')
count = fresh_fruit.get('lemon', 0)
if count:
make_lemonade(count)
else:
out_of_stock()
这段代码看上去虽然简单,但还是显得有点儿松散,因为count变量虽然定义在整个if/else结构之上,然而只有if语句才会用到它,else块根本就不需要使用这个变量。所以,这种写法让人误以为count是个重要的变量,if和else都要用到它,但实际上并非如此。
我们在Python里面经常要先获取某个值,然后判断它是否非零,如果是就执行某段代码。对于这种用法,我们以前总是要通过各种技巧,来避免count这样的变量重复出现在代码之中,这些技巧有时会让代码变得比较难懂。Python引入赋值表达式正是为了解决这样的问题。下面改用海象操作符来写:
if count := fresh_fruit.get('lemon', 0):
make_lemonade(count)
else:
out_of_stock()
新代码虽然只省了一行,但读起来却清晰很多,因为这种写法明确体现出count变量只与if块有关。这个赋值表达式先把:=右边的值赋给左边的count变量,然后对自身求值,也就是把变量的值当成整个表达式的值。
由于表达式紧跟着if,程序会根据它的值是否非零来决定该不该执行if块。这种先赋值再判断的做法,正是海象操作符想要表达的意思。
柠檬汁效力强,所以只需要一颗柠檬就能做完这份订单,这意味着程序只需判断非零即可。如果客人点的是苹果汁,那就至少得用四个苹果才行。按照传统的写法,要先从fresh_fruit这个字典里面查出苹果(apple)的数量(count),然后在if语句里,根据这个数量构造条件表达式(count >= 4)。
def make_cider(count):
print(f'Making cider with {count} apples')
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这个值相比较。
刚才柠檬汁的例子没有加括号,因为那时只凭赋值表达式本身的值就能决定if/else的走向:只要表达式的值不是0,程序就进入if分支。但是这次不行,这次要把这个赋值表达式放在更大的表达式里面,所以必须用括号把它括起来。当然,在没有必要加括号的情况下,还是尽量别加括号比较好。
还有一种类似的逻辑也会出现刚才说的重复代码,这指的是:我们要根据情况给某个变量赋予不同的值,紧接着要用这个变量做参数来调用某个函数。
例如,若顾客要点香蕉冰沙,那我们首先得把香蕉切成好几份,然后用其中的两份来制作这道冰沙。如果不够两份,那就抛出香蕉不足(OutOfBananas)异常。下面用传统的写法实现这种逻辑:
def slice_bananas(count):
print(f'Slicing {count} bananas')
return count * 4
class OutOfBananas(Exception):
pass
def make_smoothies(count):
print(f'Making a smoothies with {count} banana slices')
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()
还有一种传统的写法也很常见,就是把if/else结构上方那条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()
这种写法看上去稍微有点儿怪,因为if与else这两个分支都给pieces变量定义了初始值。根据Python的作用域规则,这种分别定义变量初始值的写法是成立的。虽说成立,但这样写看起来比较别扭,所以很多人喜欢用第一种写法,也就是在进入if/else结构之前,先把pieces的初始值给设置好。
改用海象操作符来实现,可以少写一行代码,而且能够压低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()
对于在if与else分支里面分别定义pieces变量的写法来说,海象操作符也能让代码变得清晰,因为这次不用再把count变量放到整个if/else块的上方了。
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/else结构里面继续嵌套if/else结构,或者使用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循环来实现:
FRUIT_TO_PICK = [
{'apple': 1, 'banana': 3},
{'lemon': 2, 'lime': 5},
{'orange': 3, 'melon': 2},
]
def pick_fruit():
if FRUIT_TO_PICK:
return FRUIT_TO_PICK.pop(0)
else:
return []
def make_juice(fruit, count):
return [(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()
print(bottles)
这种写法必须把fresh_fruit = pick_fruit()写两次,第一次是在进入while循环之前,因为我们要给fresh_fruit设定初始值,第二次是在while循环体的末尾,因为我们得把下一轮需要处理的水果列表填充到fresh_fruit里面。
如果想复用这行代码,可以考虑loop-and-a-half 模式。这个模式虽然能消除重复,但是会让while循环看起来很笨,因为它成了无限循环,程序只能通过break语句跳出这个循环。
FRUIT_TO_PICK = [
{'apple': 1, 'banana': 3},
{'lemon': 2, 'lime': 5},
{'orange': 3, 'melon': 2},
]
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)
print(bottles)
有了海象操作符,就不需要使用loop-and-a-half模式了,我们可以在每轮循环的开头给fresh_fruit变量赋值,并根据变量的值来决定要不要继续循环。这个写法简单易读,所以应该成为首选方案。
FRUIT_TO_PICK = [
{'apple': 1, 'banana': 3},
{'lemon': 2, 'lime': 5},
{'orange': 3, 'melon': 2},
]
bottles = []
while fresh_fruit := pick_fruit():
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)
print(bottles)
在其他一些场合,赋值表达式也能缩减重复代码。总之,如果某个表达式或赋值操作多次出现在一组代码里面,那就可以考虑用赋值表达式把这段代码改得简单一些。
要点
赋值表达式通过海象操作符(:=)给变量赋值,并且让这个值成为这条表达式的结果,于是,我们可以利用这项特性来缩减代码。
如果赋值表达式是大表达式里的一部分,就得用一对括号把它括起来。
虽说Python不支持switch/case与do/while结构,但可以利用赋值表达式清晰地模拟出这种逻辑。
关于作者:布雷特·斯拉特金(Brett Slatkin),Google首席软件工程师,他是Google Surveys的联合技术创始人,也是PubSubHubbub协议的共同创造者之一。此外,Slatkin还发布了Google的第一个云计算产品——App Engine。早在15年前,Slatkin就开始在工作中使用Python管理Google大量的服务器群。他拥有纽约哥伦比亚大学计算机工程专业学士学位。
本文摘编自《Effective Python:编写高质量Python代码的90个有效方法》(原书第2版),经出版方授权发布。
延伸阅读《Effective Python》(原书第2版)
点击上图了解及购买
转载请联系微信:DoctorData
推荐语:Python编程进阶必读,基于Python3.8,新增31条建议!掌握Pythonic编程方式,写出高质量代码|进阶到编程高手的程序员修炼之道和代码整洁之道。
划重点????
干货直达????
更多精彩????
在公众号对话框输入以下关键词
查看更多优质内容!
PPT | 读书 | 书单 | 硬核 | 干货 | 讲明白 | 神操作
大数据 | 云计算 | 数据库 | Python | 可视化
AI | 人工智能 | 机器学习 | 深度学习 | NLP
5G | 中台 | 用户画像 | 1024 | 数学 | 算法 | 数字孪生
据统计,99%的大咖都关注了这个公众号
????
文章浏览阅读3.5k次,点赞3次,收藏10次。前言:作为一个前端,怎么能仅仅只会写代码,然后打包代码给后端部署呢?不!咱要自立自强!本篇文章为笔者实践过程的笔记,如果有小伙伴跟我一样是服务器小白,可以作为参考借鉴,同时,如果有错误之处,欢迎各位大佬指正。使用背景:腾讯云轻量应用服务器,镜像为CentOS 7.6 64bit,应用镜像为宝塔linux面板 7.6.0。开始攻克!!!第一步:安装宝塔面板步骤:【概要】→【镜像信息】→【重置应用】。按照图片标识的步骤即可。安装成功:可在【概要】→【镜像信息】查看。获取宝塔登录的账号以及密码:_腾讯宝塔tomcat配置域名
文章浏览阅读1.1k次。看了个算法题目,觉得有趣,就换成了java版本的。 原文地址:blog.csdn.net/ns_code/article/details/21409663 题目: Write a method to decide if two strings are anagrams or..._互为变位词
文章浏览阅读989次。localhost:proj.android mxhd4$ ./build_native.sh NDK_ROOT = /Users/mxhd4/Movies/android-ndk-r9cCOCOS2DX_ROOT = /Users/mxhd4/Movies/2.0.4/cocos2d-2.0-x-2.0.4/test_cocos2dx_mac/proj.android/../..AP
文章浏览阅读693次,点赞2次,收藏13次。c语言单项链表_abc.117.con
文章浏览阅读8.9k次。从codeaurora下载android code,编译时出错make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/libstagefright_intermediates/OMXCodec.o] Error 1的解决办法:I managed to solve those problems above using charging
文章浏览阅读365次。During the lockdown, I watched and re-watched copious amounts of television. I turned around and saw that people were *gasp* learning new skills. So it occurred to me — why not combine the two for som..._python entity_extract
文章浏览阅读1.5k次。将项目打包好并上传到服务器,打开服务器命令行界面,cd到项目包目录下,debug模式运行项目java -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n -jar 项目包运行成功后,去到Eclipse点击小强,Debug Configurations–>Remote Java Applicati...
文章浏览阅读205次。量子力学已经是现代物理学的基础学科之一,其影响力越来越大!巨大的影响力迫使着人们了解它,可量子世界中的种种奇异现象却挑战着常人的逻辑底线。甚至 让许多物理爱好者也摸不着头脑, 以至于玻尔(量子物理学家)说到“如果一个人第一次听到量子物理而不感到困惑,那他一定是没有听懂”!薛定谔薛定谔的猫 只是帮助人们理解量子世界 的一种思想实验!薛定谔的猫是193...
文章浏览阅读172次。gitub网址:https://github.com/Bilibili/ijkplayer1.编译环境 ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)” apt-get install git apt-get install yasm2.设置Linux环境变量_jjdxm_ijkplayer直播
文章浏览阅读2.2w次,点赞2次,收藏13次。1.选型,我选的是三星m2 970 22*80固态硬盘,网上找了些资料,觉得三星靠谱2.拆机,将底部的所有螺丝去下,用卡片沿着边沿滑动,不要硬拆3.装固态,在左下角位置将固态装上,另一边螺丝锁紧(笔记本没有带m2螺丝,需要自己购买)4.装机,盖上面板,螺丝锁上5.制作U盘pe系统,去系统之家下载个旗舰版或专业版win10系统6.启动按F2 bios更改uefi为legacy,将识别出的固..._小新增加磁盘
文章浏览阅读712次。原文出处:http://blog.csdn.net/wangqing_12345/article/details/51207548 1、QIODevice 直接继承自QObject QIODevice类是输入/输出设备的基类。 QIODevice为设备提供了公共实现和抽象接口用于读写块数据。 QIODevice是一个抽象类,不能被实例化。 被Q3Socket,Q3SocketDevice_qt io操作 readall
文章浏览阅读537次。32位进程需要32位SOS。 32位SOS仅适用于32位WinDbg。加载扩展要加载扩展,有2个命令。一个是.loadby,另一个是.load。对于.loadby,请使用相对路径;对于.load,请使用完整路径。对于.loadby,有5个选项:.loadby sos mscorsvr.loadby sos mscorwks.loadby sos clr.loadby sos coreclr.loadby sos 其中mscorsvr确实很旧(.NET CLR 1,服务器版本),mscor_windbg+sos