'NameError: global name is not defined' under pdb, for dictionary that does exist

'NameError: global name is not defined' under pdb, for dictionary that does exist

我在 lambda 函数中遇到了范围问题。我可以成功地将 foo 输出到标准输出,但是在使用包含 lambdamax() 时出现错误 - 请参阅下面的简化代码...

总而言之,我试图在未知数量的一阶键中找到嵌套键 budget 的最大值。

(Pdb) foo = self.some_method()    # some_method() returns a dict, printed in the next step

(Pdb) pp foo

{'1': {'count': 1,
       'extra_data': {'activity-count': 1,
                             'budget': 0,
                             [...MORE KEY-VALUE PAIRS HERE...]
                             'version': 1},
       [...LOTS MORE KEY-VALUE PAIRS HERE...]
       'elements_total': defaultdict(<type 'int'>, {'result': 1, 'another_key': 2}),
       'extra_year_data': defaultdict(<function <lambda> at 0x10e05bd70>, {})}, 

 '2': {'count': 1,
       'extra_data': {'activity-count': 1,
                             'budget': 3,
                             [...MORE KEY-VALUE PAIRS HERE...]
                             'version': 1},
       [...LOTS MORE KEY-VALUE PAIRS HERE...]
       'elements_total': defaultdict(<type 'int'>, {'result': 1, 'another_key': 2}),
       'extra_year_data': defaultdict(<function <lambda> at 0x10e05bd70>, {})}}

(Pdb) max(foo, key=lambda x: foo[x]['extra_data']['budget'])
*** NameError: global name 'foo' is not defined

总而言之,我正在尝试使用 max(foo, key=lambda x: foo[x]['extra_data']['budget']) 在未知数量的一阶键中查找嵌套键 budget 的最大值。

这种情况下的预期结果可能是 2 作为 foo['2']['extra_data']['budget'] = 3foo['1']['extra_data']['budget'] = 0 的值。

错误是否与某些(不相关的)键中有 defaultdict 个事实有关?

您使用 pdb 设置了一个新的 local,但在该调试器会话中使用嵌套作用域的表达式不可见。嵌套范围中的任何表达式,例如用于key参数的lambda,使用当前帧的本地名称,需要是关闭就会有这个问题。

这是调试器和 Python 编译工作方式的限制;只有在需要生成它们的函数是在同一个会话中编译的情况下,才能创建闭包。由于您正在调试的函数是在没有 foo 闭包的情况下编译的,因此 lambda 表达式不能使用它。

您可以将本地绑定到 lambda(使其成为本地而不是闭包):

max(foo, key=lambda x, foo=foo: foo[x]['extra_data']['budget'])

有关 Python 编译器如何创建闭包的详细信息,请参阅 What exactly is contained within a obj.__closure__?

有一个 bug report for Python 3 (however this issue affects Python 2.7 as well as you found out) which suggests a workaround 作为 Martijn 解决方案的替代方案:interactpdb 提示符处将您带入一个交互式会话,其中填充了 globals() and locals() 和您的 lambda 应该可以正常工作。

这会扰乱您的全局范围,但这是我在这种情况下使用 python 2.7:

时使用的快速(脏)解决方法
globals().update(locals())