Bol*_*ain 14 python scope generator
以下代码返回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是一个有35个条目的OrderedDict(从集合库导入).当我尝试调试时,下面的代码执行没有错误:
(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
Mar*_*ers 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生成器代码对象使用.
在调试器中运行任意表达式时,编译器无法访问您正在调试的命名空间.更重要的是,它不能改变该命名空间来创建闭包.因此,您不能在生成器表达式中使用除全局变量之外的任何内容.
| 归档时间: | 
 | 
| 查看次数: | 1442 次 | 
| 最近记录: |