为什么我不能迭代 locals() 并在迭代中使用返回的项目作为键?

Why can't I iterate over locals() and within the iteration use returned item as a key?

我有一个名为 Promotions 的模块,其中包含一些函数,并且我有一个变量,用于存储名称中包含“_promo”的所有函数的列表。

promos = [
    locals()[name] for name in locals() # Iterate over each name in the dictionary returned by locals()
    if name.endswith("_promo") # Select only names that end with the _promo suffix.
    ] 

当我在另一个地方导入促销并要求检索促销时,我得到一个 KeyError

但是,如果我做同样的事情但将 locals() 替换为 globals(),我不会得到 KeyError.

有人知道为什么吗?

编辑: 是不是因为我第二次调用locals()(在locals()[name])我已经不在同一个范围内了?

Is it because the second time I call locals() (in locals()[name]) I am no longer in the same scope?

正是如此。列表理解有它自己的作用域,就像函数一样,但是 locals() 上的迭代器是在外部作用域中创建的。

import inspect

class LoudIterable:
    def __iter__(self):
        print(inspect.currentframe())
        return iter([1, 2])

x = [print(inspect.currentframe()) for i in LoudIterable()]

# <frame at 0x0000021795BFD4B8, file '', line 5, code __iter__>
# <frame at 0x0000021795CF8AF8, file '', line 8, code <listcomp>>
# <frame at 0x0000021795CF8AF8, file '', line 8, code <listcomp>>

您会看到每次迭代都有相同的帧,但是 __iter__ 是在另一个帧中调用的。

当你想到发电机时,这是有道理的。

non_iterable = 2
x = (i for i in non_iterable)

iter 以急切的方式在迭代器上调用,即使我们甚至还没有开始迭代,您会立即看到错误: TypeError: 'int' object is not iterable

无论如何,简单的解决方法是:

promos = [v for k, v in locals().items() if k.endswith("_promo")]