4

好的,所以我在一个工具的配置脚本是exec'd python 脚本的环境中工作。exec 调用是这样的:

外部.py:

exec(open("inner.py").read(), globals(), {})

现在,我想在exec'd 脚本中做一些相对基本的迭代。在这种情况下,当某些值不在白名单中时进行工作:

内部.py:

items = (
  'foo/bar',
  'foo/baz',
  'foof',
  'barf/fizz',
)

whitelist = (
  'foo/',
)

for key in items:
  try:
    # Not terribly efficient, but who cares; computers are fast.
    next(True for prefix in whitelist if key.startswith(prefix))

  # Do some work here when the item doesn't match the whitelist.
  except StopIteration:
    print("%10s isn't in the whitelist!" % key)

运行python inner.py产生预期的结果:

      foof isn't in the whitelist!
 barf/fizz isn't in the whitelist!

这是奇怪的部分:运行python outer.py似乎表明解释器对生成器的范围感到困惑:

Traceback (most recent call last):
  File "outer.py", line 1, in <module>
    exec(open("inner.py").read(), globals(), {})
  File "<string>", line 15, in <module>
  File "<string>", line 15, in <genexpr>
NameError: global name 'key' is not defined

其他一些注意事项:

  • 你可以在循环print(key)内很好(在生成器运行之前)。for

  • 将空字典替换locals()为解决execouter.py问题,但该代码超出了我的控制范围。

  • 我正在运行 OS X 构建的 Python 2.7.2 (Mountain Lion)。

4

2 回答 2

5

确实狡猾。

文档

如果将两个单独的对象作为全局变量和局部变量给出,则代码将像嵌入到类定义中一样被执行。

(请注意,当您exec(..., globals(), locals())在模块级别运行时,这不适用,因为globals() is locals(),即不是两个单独的对象)。

这表明您可以通过运行以下脚本简单地重现问题:

class A(object):

  items = (
    'foo/bar',
    'foo/baz',
    'foof',
    'barf/fizz',
  )

  whitelist = (
    'foo/',
  )

  for key in items:
    try:
      # Not terribly efficient, but who cares; computers are fast.
      next(True for prefix in whitelist if key.startswith(prefix))
      # Found!
      print(key)
    except StopIteration:
      pass

“好的,但为什么我会在这里收到错误消息?”

So glad you asked. The answer is here.

于 2013-04-07T19:17:27.217 回答
1

为什么不在那里添加一个内部 for 循环:

for key in items:
    for prefix in whitelist:
        if key.startswith(prefix):
            print(key)

我很确定你不会得到那个错误,而且它更简单/更容易阅读。

于 2013-04-07T19:12:06.270 回答