Python 3.8 中的海象运算符,优雅而简洁
概念介绍
:=
可在表达式内部为变量赋值。它被昵称为“海象运算符”因为它很像是 [海象的眼睛和长牙]。

实用价值
「一方面,可以写出优雅而简洁的 Python 代码;另一方面,可以看懂他人的代码。」
演示示例
官网的例子
「看下官网给出的例子:」

通过使用海象表达式,避免len()方法运行两次,从而提高了运行速度。
# 通过使用海象表达式,避免len()方法运行两次,从而提高了运行速度
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
if len(a) > 10:
print(f"List is to long({len(a)} elements, expected <= 10)")
# 改进版
n = len(a)
if n > 10:
print(f"List is to long({n} elements, expected <= 10)")
# 直接使用 海象运算符
if (n := len(a)) > 10:
print(f"List is too long ({n} elements, expected <= 10)")
「类似的例子还有:」
用于是否匹配,提取子分组。
discount = 0.0
if (mo := re.search(r'(\d+)% discount', advertisement)):
discount = float(mo.group(1)) / 100.0
# 以前的写法是这样:
discount = 0.0
mo = re.search(r'(\d+)% discount', advertisement)
if mo:
discount = float(mo.group(1)) / 100.0
运算符也适用于配合 while 循环计算一个值来检测循环是否终止,而同一个值又在循环体中再次被使用的情况:
# Loop over fixed length blocks
while (block := f.read(256)) != '':
process(block)
# 老的写法
while 1:
block = f.read(256)
if block != '':
process(block)
else:
break
另一个值得介绍的用例出现于列表推导式中,在筛选条件中计算一个值,而同一个值又在表达式中需要被使用:
[clean_name.title() for name in names if (clean_name := normalize('NFC', name)) in allowed_names]
文档中也提到了:「请尽量将海象运算符的使用限制在清晰的场合中,以降低复杂性并提升可读性。」
练习的例子
# 2023/5/14 12:30 , @File: test_1.py, @Comment : python3.9.7
# Python 海象运算符 简单介绍
x = 5
if x <= 10:
print("Please enter a number greater than or equal to 10")
print("================================================")
# 海象运算符
if (y := 5) < 10:
print("Please enter a number greater than or equal to 10")
# 2023/5/14 12:35 , @File: test_2.py, @Comment : python3.9.7
num = 10
while num:
print("the number of iterations is " + str(num))
num -= 1
# 海象运算符
print("================================================")
count = 10
while count := count - 1:
print("the number of iterations is " + str(count))
# 2023/5/14 12:39 , @File: test_3.py, @Comment : python3.9.7
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def f(x):
return x ** 2
nums2 = [n for i in nums if (n:=f(i))>10 ]
# 2023/5/14 15:19 , @File: test_6.py, @Comment : python3.9.7
nums = [16, 36, 49, 64]
def f(x):
print('运行了函数f(x)1次。')
return x ** 0.5
print([f(i) for i in nums if f(i) > 5])
print("================================================")
nums2 = [16, 36, 49, 64]
def f2(x):
print('运行了函数f2(x)1次。')
return x ** 0.5
print([n for i in nums if (n := f2(i)) > 5])
#
# 运行了函数f(x)1次。
# 运行了函数f(x)1次。
# 运行了函数f(x)1次。
# 运行了函数f(x)1次。
# 运行了函数f(x)1次。
# 运行了函数f(x)1次。
# 运行了函数f(x)1次。
# [6.0, 7.0, 8.0]
# ================================================
# 运行了函数f2(x)1次。
# 运行了函数f2(x)1次。
# 运行了函数f2(x)1次。
# 运行了函数f2(x)1次。
# [6.0, 7.0, 8.0]
注意事项
-
赋值表达式使用walrus运算符(:=)在单个表达式中同时对变量名进行赋值和计算,从而减少重复。 上面的 if,while,列表推导的例子上都有体现。
-
当赋值表达式是一个较大表达式的子表达式时,它必须用圆括号括起来 # 2023/5/14 12:59 , @File: test_4.py, @Comment : python3.9.7 countries = ["India", "USA", "France"] if len(countries) < 5: print("Length of countries is %d" % len(countries)) # 上面的代码执行会调用len两次,我们改进下: countries2 = ["India", "USA", "France", "United States", "china", "america"] countries_size2 = len(countries2) if countries_size2 < 10: print("Length of countries is %d" % countries_size2) # 海象运算符写法 countries3 = ["India", "USA", "France"] if countries_size3 := len(countries3) < 5: print(countries_size3) # True print("Length of countries is %d" % countries_size3) # 注意下面和上面的写法的区别,用海象得加括号。不然,它会先算后面的比较运算符,然后再海象。 countries3 = ["India", "USA", "France"] if (countries_size4 := len(countries3)) < 5: print("Length of countries is %d" % countries_size4) # Length of countries is 3 # Length of countries is 6 # True # Length of countries is 1 # Length of countries is 3
-
这里有几个地方不允许使用赋值表达式,以避免歧义或用户混淆
「更多信息可以参考:」
https://peps.python.org/pep-0572/#exceptional-cases
参考资料
序号 | 文章链接 | 备注 |
---|---|---|
1 | https://peps.python.org/pep-0572/#rationale | 官方文档 |
2 | https://blog.csdn.net/qq_40244755/article/details/102685199 | 官网例子的解读 |
3 | https://zhuanlan.zhihu.com/p/351140647 |
THE END