首页 > 解决方案 > 为什么不允许增加赋值表达式?

问题描述

我最近在阅读有关赋值表达式的PEP 572并偶然发现了一个有趣的用例:

# Compute partial sums in a list comprehension
total = 0
partial_sums = [total := total + v for v in values]
print("Total:", total)

我开始自己探索这段代码,很快发现那:+=不是有效的 Python 语法。

# Compute partial sums in a list comprehension
total = 0
partial_sums = [total :+= v for v in values]
print("Total:", total)

:=我怀疑如何实施明智地排除了可能有一些潜在的原因:+=,但我不确定它可能是什么。如果在 Python 方面更聪明的人知道为什么:+=不可行、不切实际或未实现,请分享您的理解。

标签: python

解决方案


简短版本:海象运算符的添加引起了极大的争议,他们想阻止过度使用,因此他们将其限制在那些提出了强烈激励用例的情况下,而=为所有其他情况留下了方便的工具。

海象操作符有很多事情不会做而它可以做(分配给在序列或映射上查找的事物,分配给属性等),但它会鼓励一直使用它,从而损害典型代码的可读性。当然,您可以选择编写更具可读性的代码,而忽略使用怪异和可怕的标点符号填充废话的机会,但是如果我(和许多人)的 Perl 经验可以作为指导,那么即使现在人们也会使用快捷方式来更快地完成它如果生成的代码是不可读的,即使是他们,一个月后。

还有其他一些小障碍(支持海象的所有增强分配方法将为解释器添加大量新字节码,switch显着扩展 eval 循环,并可能抑制优化/从 CPU 缓存溢出),但从根本上说,您使用列表推导来处理副作用的动机案例是对列表推导的滥用(一种函数构造,与所有函数式编程工具一样,不打算产生副作用),大多数情况下会依赖关于增强赋值表达式。引入此功能的强烈动机是您可以合理地想做并且没有海象就不能做的事情,例如

  1. 正则表达式,替换了这个可怕的、冗长的箭头模式:

    m = re.match(r'pattern', string)
    if m:
        do_thing(m)
    else:
        m = re.match(r'anotherpattern', string)
        if m:
            do_another_thing(m)
        else:
            m = re.match(r'athirdpattern', string)
            if m:
                do_a_third_thing(m)
    

    有了这个干净的测试链:

    if m := re.match(r'pattern', string):
        do_thing(m)
    elif m := re.match(r'anotherpattern', string):
        do_another_thing(m)
    elif m := re.match(r'athirdpattern', string):
        do_a_third_thing(m)
    
  2. 逐块读取文件,替换:

    while True:
        block = file.read(4096)
        if not block:
            break
    

    与清洁:

    while block := file.read(4096):
    

这些是人们真正需要经常做的有用的事情,甚至我发布的“规范”版本也经常以其他方式错误实现(例如应用正则表达式测试两次以避免箭头模式,复制block = file.read(4096)一次之前的循环和一次在end 所以你可以运行while block:,但作为交换,现在continue不能正常工作,并且你冒着块的大小在一个地方而不是另一个地方改变的风险);海象运算符允许更好的代码。

listcomp 累加器不是(很多)更好的代码。itertools.accumulate存在,即使不存在,也可以通过简单的生成器函数或手动循环以其他方式解决该问题。PEP 确实将其描述为一种好处(这就是他们允许海象分配“逃避”理解的原因),但与此范围界定特殊情况相关的讨论比关于添加海象本身的讨论更加分裂;你可以做到,而且它可以说是有用的,但这不是你看到两个选项并立即说“伙计,如果不是因为海象,这将是可怕的”。

只是为了让那些想要证明这一点的人满意,请注意,他们明确阻止了一些可以免费使用的用例(使语法禁止这些用法需要额外的工作),特别是为了防止海象过度使用。例如,您不能这样做:

x := 1

自己在一条线上。完全没有技术上的原因你不能,但他们故意将海象的使用设为语法错误,而无需包裹在某些东西中。(x := 1)工作在顶级水平,但这很烦人,没有人会选择它x = 1,这就是目标。

直到有人提出一个通用的代码模式,它的缺乏:+=使它变得不可行/不必要地丑陋(并且它必须非常普遍和非常丑陋才能证明标点符号填充的怪物是合理的:+=),他们不会考虑它。


推荐阅读