16

我在 Python 3.3.1 (win7) 中有一个奇怪的 NameError。

编码:

import re

# ...

# Parse exclude patterns.
excluded_regexps = set(re.compile(regexp) for regexp in options.exclude_pattern)

# This is line 561:
excluded_regexps |= set(re.compile(regexp, re.I) for regexp in options.exclude_pattern_ci)

错误:

Traceback (most recent call last):
  File "py3createtorrent.py", line 794, in <module>
    sys.exit(main(sys.argv))
  File "py3createtorrent.py", line 561, in main
    excluded_regexps |= set(re.compile(regexp, re.I) for regexp in options.exclude_pattern_ci)
  File "py3createtorrent.py", line 561, in <genexpr>
    excluded_regexps |= set(re.compile(regexp, re.I) for regexp in options.exclude_pattern_ci)
NameError: free variable 're' referenced before assignment in enclosing scope

请注意,发生错误的第 561 行是上面代码中的第二行。换句话说:re不是一个自由变量。它只是正则表达式模块,可以在第一行完美引用。

在我看来,对的引用re.I导致了问题,但我不明白如何。

4

3 回答 3

19

最有可能的是,您在第 561 行下方re的某个点(可能是无意中)分配给,但在同一个函数中。这会重现您的错误:

import re

def main():
    term = re.compile("foo")
    re = 0

main()
于 2013-05-14T14:16:54.233 回答
10

回溯中的“自由变量”表明这是封闭范围内的局部变量。像这样的东西:

 baz = 5

 def foo():
     def bar():
         return baz + 1

     if False:
          baz = 4

     return bar()

所以 thebaz指的是一个局部变量(值是 4 的那个),而不是(可能也存在的)全局变量。要修复它,请强制baz使用全局:

 def foo():
     def bar():
         global baz
         return baz + 1

这样它就不会尝试将名称解析为 baz 的非本地版本。更好的是,以看起来像局部变量的方式找到您正在使用re的位置(生成器表达式/列表推导是检查的好地方)并将其命名为其他名称。

于 2013-05-14T14:07:49.630 回答
1

其他解释是完美的,但让我添加我刚刚发现的另一个变体。由于 Python 3 更喜欢迭代器而不是“物理”列表,因此必须更加小心:

def foo():
    re = 3
    faulty = filter(lambda x: x%re, range(30))
    del re
    return faulty
list(foo())

过滤器表达式仅在最后一行的 return 语句之后进行评估,特别是 after del re。因此,最后一行因错误而爆炸:

NameError: free variable 're' referenced before assignment in enclosing scope
于 2019-01-10T03:12:42.920 回答