在以下 Python 代码中:
keyboards = [3, 1]
drivers = [5, 2, 8]
upper_limit = 10
sums = [k + d for k in keyboards for d in drivers if (k + d) <= upper_limit]
我想将 k+d
的结果存储在列表推导中,以便在列表推导中引用它。在 Python3 中可以吗?
我知道我们可以做到以下几点:
sums = []
for k in keyboards:
for d in drivers:
s = k + d
if s <= upper_limit:
sums.append(s)
但我希望避免附加的副作用操作。
如果您使用的是 Python 3.8 或更新版本,则可以使用 assignment operator (又名 海象运算符)在列表推导中创建一个新的本地名称并分配给它。对于您的具体示例,您将在 <=
的左侧操作数中执行此操作比较:
sums = [
s
for k in keyboards
for d in drivers
if (s := k + d) <= upper_limit
]
请注意,您必须在此处的赋值周围使用括号,因为海象运算符具有 the lowest precedence of all Python operators ;如果没有括号,您将分配 k + d <= upper_limit
的结果至 s
, 所以一个 bool 值。
考虑到 s
将在周围范围内可见,名称s
将具有与 sums
相同的范围有;函数内部的局部,如果在模块级别运行列表理解,则为全局。 k
和 d
,另一方面,在列表理解循环中是局部的,在理解之外是不可见的。
演示:
>>> keyboards = [3, 1]
>>> drivers = [5, 2, 8]
>>> upper_limit = 10
>>> [s for k in keyboards for d in drivers if (s := k + d) <= upper_limit]
[8, 5, 6, 3, 9]
>>> s
9
>>> k
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'k' is not defined
在早期的 Python 版本中,只有 for
的目标中的名称循环可用于在列表理解中分配一个新名称,因此如果您需要“本地”变量来引用计算,则需要找到添加额外循环的方法。
因此在 Python 3.7 或更早版本中,您可以在计算 k + d
的单个元素元组上添加另一个循环。 :
sums = [
s
for k in keyboards
for d in drivers
for s in (k + d,)
if s <= upper_limit
]
(k + d,)
是 single-element tuple ,所以 for s in (k + d,)
在 keyboards
上的每次迭代只执行一次和 drivers
, 有效分配 k + d
至 s
.
您还可以使用生成器表达式来生成 k + d
两个嵌套的总和 for
循环,然后迭代该表达式的结果:
sums = [
s
for s in (
k + d
for k in keyboards
for d in drivers
)
if s <= upper_limit
]
在后一种情况下,您可以先将该表达式存储为一个单独的变量:
s_calc = (k + d for k in keyboards for d in drivers)
sums = [s for s in s_calc if s <= upper_limit]
有了这些选项,s
始终局限于理解循环,在 sums
处不可见范围级别。它不会从理解表达式中“流血”。
后面选项的演示:
>>> [s for k in keyboards for d in drivers for s in (k + d,) if s <= upper_limit]
[8, 5, 6, 3, 9]
>>> [s for s in (k + d for k in keyboards for d in drivers) if s <= upper_limit]
[8, 5, 6, 3, 9]
>>> s_calc = (k + d for k in keyboards for d in drivers)
>>> [s for s in s_calc if s <= upper_limit]
[8, 5, 6, 3, 9]