簡體   English   中英

如何避免推導式中 Python 賦值表達式的泄漏

[英]How to Avoid Leaking of Python Assignment Expressions in Comprehensions

Effective Python一書中,作者建議使用賦值表達式來避免理解中的冗余,例如:

def fun(i):
    return 2 * i

result = {x: y for x in [0, 1, 2, 3] if (y := fun(x)) > 3}

代替

result = {x: fun(x) for x in [0, 1, 2, 3] if fun(x) > 3}

result的值為{2: 4, 3: 6}

作者指出

如果推導式在推導式的值部分使用海象運算符並且沒有條件,它會將循環變量泄漏到包含范圍中。 [...] 最好不要泄漏循環變量,因此我建議僅在推導式的條件部分使用賦值表達式。

但是,在上面的示例中, y在程序結束時設置為 6。 因此,賦值表達式中的變量泄漏了,盡管它是在條件中定義的。

列表推導式也會發生同樣的事情:

>>> _ = [(x, leak) for x in range(4) if (leak := 2 * x) > 3]
>>> leak
6

甚至對於生成器表達式:

>>> it = ((x, leak) for x in range(4) if (leak := 2 * x) > 3)
>>> next(it)
(2, 4)
>>> leak
4
>>> next(it)
(3, 6)
>>> leak
6

我錯過了什么? 有什么方法可以完全避免在推導式中的賦值表達式泄漏?

在 Python 中,不可能泄漏循環變量

與 C 或 Java 等其他語言不同,Python 在iffor塊中沒有單獨的作用域。 因此,當您在if語句、 for循環或列表推導式中使用:=運算符時,分配的變量將在整個函數或類定義的其余部分都在范圍內。 這也意味着在每個for循環之后,循環變量仍將在范圍內並包含循環最后一次迭代的值。

如果Effective Python的作者認為這是一件壞事,我不同意他的觀點。 “泄漏”循環變量非常有用! 考慮以下示例:

while line := f.readLine():
    if 'Kilian' in line:
        break

print('This is the first line that contains your name: ', line)

但是,此規則有一個例外:在列表推導式中進行的隱式賦值有自己的作用域:

>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

這個例外可能是您的困惑的根源。 這只是一種特殊情況,在列表推導式中使用:=時不適用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM