避免 for 循环变量切入 Python 全局命名空间的方法

3 python scope for-loop namespaces

我想知道是否有办法避免 for 循环变量切入 Python 的全局命名空间?

到目前为止我能想到的唯一解决方案是使用闭包,例如列表理解

例如,对于以下代码:

i = 1
print([i for i in range(5)])
print(i, 'i in global')

j = 1
for j in range(5):
    if j == 4:
        print(j, 'j in for-loop')
print(j, 'j in global')
Run Code Online (Sandbox Code Playgroud)

印刷

[0, 1, 2, 3, 4]
1 i in global
4 j in for-loop
4 j in global
Run Code Online (Sandbox Code Playgroud)

编辑:
我假设 for 循环命名空间属于“全局”类别,与 LEGB 规则中的函数(“本地”)不同,因此可能没有解决方案?顺便说一句,Python 2.x 推导式没有自己的命名空间吗?因为评论中指出Python 2.x会打印“ 4 in global”(我使用的是Python 3.4)

Mat*_*vor 5

forPython 中的循环没有自己的作用域;只有周围范围。因此,表达式中定义的任何变量都for将保留在该范围内。它们只是被添加到全局范围中,因为您在函数之外运行代码。如果将其添加到函数中,您会发现它不会“泄漏”:

def loop():
    for j in range(5):
        pass

>>> loop()
>>> 'j' in globals()
False
Run Code Online (Sandbox Code Playgroud)

在 Python 2.x 中,列表推导式具有完全相同的行为:它们会将迭代变量添加到局部作用域中,因为它们基本上是构造的语法糖for。由于这似乎不断地让人们感到惊讶,因此 Python 3.x 对此进行了更改,以便变量不会添加到本地范围。

另请注意,列表推导式具有不同的语义:它们更接近于 list() 构造函数内的生成器表达式的语法糖,特别是循环控制变量不再泄漏到周围的作用域中。

Python 3.0 的新增功能

循环的范围行为for对于如下模式很有用:

# find line number in file with matching text
for i, line in enumerate(some_file):
    if 'some text' in line:
        break
print('First match found at line {}.'.format(i))
Run Code Online (Sandbox Code Playgroud)