":=" 语法和赋值表达式:什么和为什么?

新手上路,请多包涵

PEP 572 引入了为 Python 3.8 实现的赋值表达式(俗称 海象运算符)。这似乎是一个非常重要的新功能,因为它将允许在理解和 lambda 函数中使用这种形式的赋值。

赋值表达式的句法、语义和文法规范究竟是什么?

为什么要引入这个新的(并且看似相当激进的概念),而 PEP 379 中关于“添加赋值表达式”的类似想法之前被拒绝了?

原文由 Chris_Rands 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 431
1 个回答

PEP 572 包含许多细节,尤其是第一个问题。我将尝试简明扼要地总结/引用 PEP 中一些最重要的部分:

基本原理

允许在推导式中使用这种形式的赋值,例如列表推导式和禁止传统赋值的 lambda 函数。这也可以方便交互式调试,而无需进行代码重构。

推荐的用例示例

a) 获取条件值

例如(在 Python 3 中):

 command = input("> ")
while command != "quit":
    print("You entered:", command)
    command = input("> ")

可以变成:

 while (command := input("> ")) != "quit":
    print("You entered:", command)

同样,来自 文档

在此示例中,赋值表达式有助于避免调用 len() 两次:

 if (n := len(a)) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

b) 简化列表理解

例如:

stuff = [(lambda y: [y,x/y])(f(x)) for x in range(5)]

可以变成:

stuff = [[y := f(x), x/y] for x in range(5)]

语法和语义

在可以使用任意 Python 表达式的任何上下文中,都可以出现 命名表达式。这是 name := expr 的形式,其中 expr 是任何有效的 Python 表达式,名称是标识符。

这种命名表达式的值与合并的表达式相同,具有附加的副作用,即目标被赋予该值

与常规赋值语句的区别

除了是表达式而不是语句之外,PEP 中还提到了几个不同之处:表达式赋值从右到左,围绕逗号有不同的优先级,并且不支持:

  • 多个目标
x = y = z = 0  # Equivalent: (z := (y := (x := 0)))

  • 不分配给单个名称:
 # No equivalent
a[i] = x
self.rest = []

  • 可迭代的打包/拆包
# Equivalent needs extra parentheses

loc = x, y  # Use (loc := (x, y))
info = name, phone, *rest  # Use (info := (name, phone, *rest))

# No equivalent

px, py, pz = position
name, phone, email, *other_info = contact

  • 内联类型注解:
 # Closest equivalent is "p: Optional[int]" as a separate declaration
p: Optional[int] = None

  • 不支持增强赋值:
 total += tax  # Equivalent: (total := total + tax)

原文由 Chris_Rands 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题