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

Chr*_*nds 42 python python-3.x python-3.8 python-assignment-expression

PEP 572引入了为Python 3.8实现的赋值表达式.这似乎是一个非常重要的新功能,因为它将允许在理解和lambda函数中进行这种形式的赋值.

赋值表达式的语法,语义和语法规范究竟是什么?(请注意,我知道人们可以阅读PEP 572,但对于SO来说,这似乎仍然是一个有用的参考问题.)

PEP 379中关于"添加赋值表达式" 的类似想法之前被拒绝时,为什么会引入这个新的(看似相当激进的概念)呢?

Chr*_*nds 32

PEP 572包含许多细节,尤其是第一个问题.我将尽可能简洁地总结/引用PEP的一些最重要的部分:

合理

在理解中允许这种形式的赋值,例如列表推导,以及禁止传统赋值的lambda函数.这也可以促进交互式调试,而无需代码重构.

语法和语义

在可以使用任意Python表达式的任何上下文中,都可以出现命名表达式.这是以下形式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表达式,和名称是一个标识符.

这样的命名表达式的值与合并的表达式相同,附加的副作用是为目标赋值

与常规赋值语句的差异

除了作为表达而不是语句之外,PEP中还提到了一些差异:表达式赋值从右到左,在逗号之间具有不同的优先级,并且不支持:

  • 多个目标
command = input("> ")
while command != "quit":
    print("You entered:", command)
    command = input("> ")
Run Code Online (Sandbox Code Playgroud)
  • 分配不是单个名称:
while (command := input("> ")) != "quit":
    print("You entered:", command)
Run Code Online (Sandbox Code Playgroud)
  • 可重复包装/拆包
x = y = z = 0  # Equivalent: (z := (y := (x := 0)))
Run Code Online (Sandbox Code Playgroud)
  • 内联类型注释:
# No equivalent
a[i] = x
self.rest = []
Run Code Online (Sandbox Code Playgroud)

推荐用例

a)简化列表理解

例如:

name := expr

可以变成:

expr

b)获得条件值

例如(在Python 3中):

# 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
Run Code Online (Sandbox Code Playgroud)

可以变成:

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


Jon*_*art 24

我最喜欢的几个例子,其中赋值表达式可以使代码更简洁,更易于阅读:

if 声明

之前:

match = pattern.match(line)
if match:
    return match.group(1)
Run Code Online (Sandbox Code Playgroud)

后:

if match := pattern.match(line):
    return match.group(1)
Run Code Online (Sandbox Code Playgroud)

无限while陈述

之前:

while True:
    data = f.read(1024)
    if not data:
        break
    use(data)
Run Code Online (Sandbox Code Playgroud)

后:

while data := f.read(1024):
    use(data)
Run Code Online (Sandbox Code Playgroud)

PEP中还有其他很好的例子

  • 特别好的例子:它们展示了_C_有时比Python更清晰,更优雅的方面,我认为他们永远都不会解决此问题 (4认同)

Cha*_*ton 7

现在 3.8 已经正式发布,还有一些例子和理由。

命名表达式的结果是编程的一个重要部分,允许使用描述性名称代替更长的表达式,并允许重用。目前,此功能仅在语句形式中可用,因此无法在列表推导式和其他表达式上下文中使用。

来源:LicensedProfessional 的 reddit 评论

处理匹配的正则表达式

if (match := pattern.search(data)) is not None:
    # Do something with match
Run Code Online (Sandbox Code Playgroud)

无法使用 2-arg iter() 重写的循环

while chunk := file.read(8192):
   process(chunk)
Run Code Online (Sandbox Code Playgroud)

重用计算成本高的值

[y := f(x), y**2, y**3]
Run Code Online (Sandbox Code Playgroud)

在理解过滤器子句及其输出之间共享子表达式

filtered_data = [y for x in data if (y := f(x)) is not None]
Run Code Online (Sandbox Code Playgroud)