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