以下代码返回NameError: global name 'self' is not defined
。为什么呢?
lengths = [3, 10]
self.fooDict = getOrderedDict(stuff)
if not all(0 < l < len(self.fooDict) for l in lengths):
raise ValueError("Bad lengths!")
请注意,self.fooDict
是一个OrderedDict(从集合库导入),有35个条目。当我尝试调试时,下面的代码执行时没有错误:
(Pdb) len(self.dataDict)
35
(Pdb) all(0 < size < 35 for size in lengths)
True
但下面的debugginf代码给出了原始错误:
(Pdb) baz = len(self.dataDict)
(Pdb) all(0 < size < baz for size in lengths)
NameError: global name 'baz' is not defined
答案 0 :(得分:11)
您遇到了调试器的限制。输入调试器的表达式不能使用非本地作用域值,因为调试器无法创建所需的闭包。
您可以改为创建一个函数来运行您的生成器,从而同时创建一个新的范围:
def _test(baz, lengths):
return all(0 < size < baz for size in lengths)
_test(len(self.dataDict), lengths)
请注意,这也适用于集合和字典理解,在Python 3中也适用于列表推导。
生成器表达式(以及set,dict和Python 3列表推导)在一个新的嵌套命名空间中运行。生成器表达式中的名称baz
不是该命名空间中的本地名称,因此Python必须在其他位置找到它。 在编译时 Python确定从哪里获取该名称。它将从编译器可用的范围中搜索,如果没有匹配,则将名称声明为全局。
这里有两个生成器表达式来说明:
def function(some_iterable):
gen1 = (var == spam for var in some_iterable)
ham = 'bar'
gen2 = (var == ham for var in some_iterable)
return gen1, gen2
在父作用域中找不到名称spam
,因此编译器将其标记为全局:
>>> dis.dis(function.__code__.co_consts[1]) # gen1
2 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 17 (to 23)
6 STORE_FAST 1 (var)
9 LOAD_FAST 1 (var)
12 LOAD_GLOBAL 0 (spam)
15 COMPARE_OP 2 (==)
18 YIELD_VALUE
19 POP_TOP
20 JUMP_ABSOLUTE 3
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
索引12处的操作码使用LOAD_GLOBAL
加载spam
名称。
在函数范围中找到名称ham
,因此编译器会生成字节码,以便从函数中查找名称作为闭包。 同时将名称ham
标记为闭包;为function
生成的代码对变量的处理方式不同,以便在函数返回时仍然可以引用它。
>>> dis.dis(function.__code__.co_consts[3]) # gen2
4 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 17 (to 23)
6 STORE_FAST 1 (var)
9 LOAD_FAST 1 (var)
12 LOAD_DEREF 0 (ham)
15 COMPARE_OP 2 (==)
18 YIELD_VALUE
19 POP_TOP
20 JUMP_ABSOLUTE 3
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>> function.__code__.co_cellvars # closure cells
('ham',)
名称ham
加载了LOAD_DEREF
操作码,功能代码对象将该名称列为闭包。当您反汇编function
时,您会发现其他字节码:
>>> dis.dis(function)
# ....
4 22 LOAD_CLOSURE 0 (ham)
25 BUILD_TUPLE 1
28 LOAD_CONST 3 (<code object <genexpr> at 0x1074a87b0, file "<stdin>", line 4>)
31 MAKE_CLOSURE 0
34 LOAD_FAST 0 (some_iterable)
37 GET_ITER
38 CALL_FUNCTION 1
41 STORE_FAST 2 (gen2)
# ...
其中LOAD_CLOSURE
和MAKE_CLOSURE
字节码为生成器代码对象使用的ham
创建一个闭包。
在调试器中运行任意表达式时,编译器无法访问您正在调试的命名空间。更重要的是,它不能更改该命名空间来创建闭包。因此,除了 globals 之外,你不能在生成器表达式中使用任何东西。