且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

嵌套生成器表达式-意外结果

更新时间:2023-01-19 15:46:16

生成器表达式创建各种 function ;一个只有一个参数,最外面的是可迭代的.

这里是 units ,并且在生成生成器表达式时绑定为生成器表达式的参数.

所有其他名称都是本地名称(例如 a b ),全局变量或闭包. tens 被视为一个全局变量,因此每次推进生成器时都会对其进行查找.

结果,在第3行将 units 绑定到生成器,在最后一行上遍历生成器表达式时,将查找 tens .

将生成器编译为字节码并检查该字节码时,您会看到以下信息:

 >>>导入dis>>>genexp_bytecode = compile('((a + b代表a以b为单位,以十为单位)','< file>','single')>>>dis.dis(genexp_bytecode)1 0 LOAD_CONST 0(0x10f013ae0处的<代码对象< genexpr&gt ;,文件< file>",第1行>)3 LOAD_CONST 1('< genexpr>')6 MAKE_FUNCTION 09 LOAD_NAME 0(单位)12 GET_ITER13 CALL_FUNCTION 1(1个位置,0个关键字对)16个PRINT_EXPR17 LOAD_CONST 2(无)20 RETURN_VALUE 

MAKE_FUNCTION 字节码将生成器表达式代码对象变成一个函数,然后立即调用它,并传入 iter(units)作为参数.此处完全未引用 tens 名称.

这已记录在原始生成器PEP 中:

仅最外面的for表达式立即被求值,另一个表达式推迟到生成器运行为止:

  g =(如果exp4为exp2,则exp1为var2,如果exp4为exp2,则为exp1中的var1的tgtexp) 

等效于:

  def __gen(bound_exp):对于bound_exp中的var1:如果exp2:对于exp3中的var2:如果exp4:产生tgtexpg = __gen(iter(exp1))del __gen 

,并在生成器表达式参考中:

当为生成器对象调用 __ next __()方法时(与普通生成器相同的方式),对生成器表达式中使用的变量进行延迟计算.但是,最左边的 for 子句会被立即求值,这样,在处理生成器表达式的代码中,它产生的错误就可以在任何其他可能的错误之前看到.随后的 for 子句可能无法立即求值,因为它们可能取决于先前的for循环.例如:(x * y表示范围内的x(10)表示bar(x)中的y).

PEP有一个很好的部分,它鼓励为什么名称(除了最外面的可迭代名称)绑定得晚,请参见解决方案