我最近阅读了PEP572中关于赋值表达式的内容,偶然发现了一个有趣的用例:
# 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方面更明智的人知道为什么:+=
是不可行的或不切实际的,或者没有实现,请分享你的理解。
3条答案
按热度按时间sbdsn5lh1#
简短版本:添加walrus操作符引起了极大的争议,他们希望阻止过度使用,所以他们将其限制在那些提出了“强”激励用例的情况下,而
=
则是所有其他情况下的方便工具。有很多事情海象操作员不会做,但它 * 可以 * 做(赋值给在序列或Map中查找到的东西,赋值给属性,等等),但这会鼓励一直使用它,损害典型代码的可读性。当然,你可以选择编写可读性更强的代码,忽略使用奇怪的、可怕的、充满标点符号的废话的机会,但如果我(和许多人)使用Perl的经验可以作为指导,那么即使一个月后生成的代码甚至对他们来说都无法阅读,人们现在也会使用快捷方式来更快地完成它。
还有其他一些小的障碍在路上(用walrus支持所有扩展赋值方法会给解释器添加大量新的字节码,显著扩展eval循环的
switch
和potentially inhibiting optimizations/spilling from CPU cache),但从根本上说,您使用列表解析来解决副作用的动机是对列表解析的误用(一种函数式构造,像所有函数式编程工具一样,不希望有副作用),大多数情况下都依赖于扩充赋值表达式。引入这个特性的强烈动机是你可以合理地想做的事情,而没有海象就做不到,例如:1.正则表达式,取代了这个可怕的,冗长的箭头模式:
通过这一系列的测试
1.按块阅读文件,替换:
与清洁:
这些都是有用的事情,人们确实需要做一些频率,甚至“规范”的版本,我张贴往往是错误的实现在其他方面(例如,应用regex测试两次以避免箭头模式,在循环之前复制
block = file.read(4096)
一次,在循环结束时复制一次,以便您可以运行while block:
,但作为交换,现在continue
无法正常工作,并且冒着块的大小在一个地方改变而在另一个地方不改变的风险);海象运营商允许更好的编码。列表组件累加器不是存在(更)好的代码.
itertools.accumulate
,即使没有,也可以通过简单的生成器函数或手动滚动循环以其他方式解决这个问题。(这就是为什么他们允许海象赋值语句“逃脱”解析),但是,与增加海象本身的讨论相比,关于这一范围界定特例的讨论甚至更加分歧;你可以这么做,而且可以说是有用的,但这并不是你看到两个选项后马上说“伙计,如果没有海象,这将是可怕的”。为了满足那些想要证明这一点的人,请注意,他们明确地屏蔽了一些本来可以免费使用的用例(语法禁止这些用法需要额外的工作),特别是为了防止海象的过度使用。
没有技术上的原因你不能,但是他们 * 故意 * 使它成为一个语法错误的海象被使用而不被 Package 在一些东西。
(x := 1)
工作在顶级,但是它足够烦人没有人会选择它超过x = 1
,这就是目标。除非有人提出一种通用代码模式,其中
:+=
的缺失使其变得不可行/不必要地丑陋(而且必须是 * 真的 * 通用和 * 真的 * 丑陋,才能证明:+=
这个充满标点符号的怪物是合理的),否则他们不会考虑它。mum43rcc2#
itertools模块提供了许多机制来实现相同的结果,而不会使语言膨胀:
6uxekuva3#
1.我的理解是,理解效率的一个主要部分是原始可迭代对象中每个元素的计算都可以并行执行,如果你要计算一个累计,那就必须串行执行。
1.我们已经有了
sum(values)
,那么在这个用例中添加了什么呢?1.如果您需要更通用的用例,
functools
有reduce
。