当前位置: 首页 > 知识库问答 >
问题:

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

鄢选
2023-03-14

PEP 572引入了为Python 3.8实现的赋值表达式(俗称Walrus操作符)。这似乎是一个非常重要的新特性,因为它将允许在理解和lambda函数中进行这种形式的赋值。

赋值表达式的语法、语义学和语法规范到底是什么?

为什么在PEP 379中关于“添加赋值表达式”的类似想法之前遭到拒绝的情况下,引入了这个新的(似乎相当激进的概念)?

共有3个答案

长孙鸿
2023-03-14

现在3.8已经正式发布了,更多的例子和理由。

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

来源:LicensedProfessional的reddit评论

处理匹配的正则表达式

if (match := pattern.search(data)) is not None:
    # Do something with match

不能使用2-arg iter()简单重写的循环

while chunk := file.read(8192):
   process(chunk)

重用计算成本高昂的值

[y := f(x), y**2, y**3]

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

filtered_data = [y for x in data if (y := f(x)) is not None]
席俊
2023-03-14

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

之前:

match = pattern.match(line)
if match:
    return match.group(1)

之后:

if match := pattern.match(line):
    return match.group(1)

之前:

while True:
    data = f.read(1024)
    if not data:
        break
    use(data)

之后:

while data := f.read(1024):
    use(data)

政治公众人物中还有其他好例子。

邹博明
2023-03-14

PEP 572包含许多细节,尤其是第一个问题。我将尝试简要总结/引用政治公众人物计划中最重要的部分:

理由

允许在理解中进行这种形式的赋值,例如列表理解和禁止传统赋值的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) 简化列表理解

例如:

东西=[(lambda y:[y, x/y])(f(x))表示范围内的x(5)]

可以成为:

<代码>填充=[[y:=f(x),x/y]对于范围(5)中的x)]

句法语义学

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

这种命名表达式的值与合并表达式的值相同,但另一个副作用是为目标指定了该值

与常规赋值语句的区别

除了作为表达式而不是语句之外,PEP中还提到了几个区别:表达式分配从右到左,逗号周围有不同的优先级,并且不支持:

  • 多个目标
x = y = z = 0  # Equivalent: (z := (y := (x := 0)))
  • 不分配给单个名称:
# No equivalent
a[i] = x
self.rest = []
  • Iterable包装/开箱
# 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)
 类似资料:
  • 使用上面的代码,错误出现在以下行:这真的很奇怪,因为我确信我的分配是正确的。是否只有Eclipse没有正确解析代码?

  • 本文向大家介绍表达式和语句有什么区别?如何把语句转换为表达式?相关面试题,主要包含被问及表达式和语句有什么区别?如何把语句转换为表达式?时的应答技巧和注意事项,需要的朋友参考一下 简单的说来,表达式(Expression)是语句(Statement)的子集,表达式一定会返回一个值,而语句不会。 比如定义变量、返回语句都属于语句,而逻辑判断、方法调用、赋值都属于表达式。 支持语句的地方都支持表达式,

  • 问题内容: 从文档中: 注意: AngularJS指令属性采用带嵌入式表达式的表达式 或 插值标记。将插值标记嵌入表达式中被认为是 不好的做法 : — AngularJS开发人员指南-插值 我正在寻找一个写得很好的规范答案,可以给读者指出。 问题答案: 从文档中: 为什么混合插值和表达式是不好的做法: 它增加了标记的复杂性 由于插值本身是一个指令,因此不能保证它适用于每个指令。如果另一个指令在插值

  • 问题内容: 我想通过事件参数发生按钮单击事件时分配一些值: 我已将值分配给 。 现在我看到angular.copy()。所以我用angular.copy编写了代码。 两者都在做同样的事情,所以有什么区别?请告诉我和之间的区别。 问题答案: 可以理解,这里 执行了参数的深层复制(参见“克隆”)-本质上是创建一个新对象-而使用赋值运算符只分配 引用 的。 因此,在后一种情况下,如果您要更改某些内容,您

  • 我正在尝试理解语法。考虑以下程序: 在上面的程序中,模式匹配中使用的编译正常。当我尝试在like我得到编译错误: 我试图理解为什么不能在中使用。

  • 问题内容: 我想知道为什么在计算表达式或按位运算时将和提升为值的原因? 问题答案: 因为Java语言规范是这样说的。第5.6.1节定义了用于撤消某些运算符的一元数值提升,并指出: 如果操作数的编译时类型为byte,short或char,则通过扩展基元转换(第5.1.2节)将其提升为int类型的值。 关于二进制数值运算符(“ binary”表示具有两个操作数,如“ +”的运算符)的评估的第5.6.2