PEP 572引入了为Python 3.8实现的赋值表达式。这似乎是一个非常重要的新功能,因为它将允许在理解和lambda函数中进行这种形式的赋值。
赋值表达式的语法,语义和语法规范究竟是什么? (请注意,我知道人们可以阅读PEP 572,但对于SO来说这仍然是一个有用的参考问题。)
为什么这个新的(看似相当激进的概念)被引入,当PEP 379中的类似想法在"添加一个赋值表达式"之前被拒绝了?
答案 0 :(得分:16)
PEP 572包含许多细节,尤其是第一个问题。我将简要总结/引用PEP的一些最重要部分:
<强>原理强>
在理解中允许这种形式的赋值,例如列表推导和禁止传统赋值的lambda函数。这也可以促进交互式调试,而无需进行代码重构。
语法和语义
在可以使用任意Python表达式的任何环境中,都可以出现命名表达式。其形式为
name := expr
,其中expr
是任何有效的Python表达式,name是标识符。这样的命名表达式的值与合并的表达式相同,附加的副作用是为目标赋值
与常规作业声明的区别
除了作为表达而非声明之外,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)
推荐用例
a)简化列表理解
例如:
stuff = [(lambda y: [y,x/y])(f(x)) for x in range(5)]
可以成为:
stuff = [[y := f(x), x/y] for x in range(5)]
b)获取条件值
例如(在Python 3中):
command = input("> ")
while command != "quit":
print("You entered:", command)
command = input("> ")
可以成为:
while (command := input("> ")) != "quit": print("You entered:", command)
答案 1 :(得分:2)
自3.8正式发布以来,还有更多示例和理由。
命名表达式的结果是编程的重要组成部分,允许使用描述性名称代替更长的表达式,并允许重用。当前,此功能仅以语句形式可用,从而使其在列表推导和其他表达式上下文中不可用。
来源:LicensedProfessional's reddit comment
处理匹配的正则表达式
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]
答案 2 :(得分:1)
我最喜欢的两个例子,赋值表达式可以使代码更简洁,更易于阅读:
if
语句之前:
match = pattern.match(line)
if match:
return match.group(1)
之后:
if match := pattern.match(line):
return match.group(1)
while
语句之前:
while True:
data = f.read(1024)
if not data:
break
use(data)
之后:
while data := f.read(1024):
use(data)