Ale*_*amo 8 python bytecode python-internals
列表推导将其代码直接放在使用它们的函数中,如下所示:
>>> dis.dis((lambda: [a for b in c]))
1 0 BUILD_LIST 0
3 LOAD_GLOBAL 0 (c)
6 GET_ITER
>> 7 FOR_ITER 12 (to 22)
10 STORE_FAST 0 (b)
13 LOAD_GLOBAL 1 (a)
16 LIST_APPEND 2
19 JUMP_ABSOLUTE 7
>> 22 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
而生成器表达式和字典/集合理解主要放在一个单独的嵌套函数中,如下所示:
>>> dis.dis((lambda: {a for b in c}))
1 0 LOAD_CONST 1 (<code object <setcomp> at 0x7ff41a3d59b0, file "<stdin>", line 1>)
3 MAKE_FUNCTION 0
6 LOAD_GLOBAL 0 (c)
9 GET_ITER
10 CALL_FUNCTION 1
13 RETURN_VALUE
>>> dis.dis((lambda: {a for b in c}).func_code.co_consts[1])
1 0 BUILD_SET 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 12 (to 21)
9 STORE_FAST 1 (b)
12 LOAD_GLOBAL 0 (a)
15 SET_ADD 2
18 JUMP_ABSOLUTE 6
>> 21 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
在Python 3中,所有这些都放在嵌套函数中.
为什么代码放在一个单独的嵌套函数中?我依稀记得在很久以前读过一些关于想要修复理解和/或genexpr变量溢出到周围范围的人的事情,这是针对那个还是什么的解决方案?
为什么列表推导的实现与Python 2中的其余部分不同?由于向后兼容性?(我认为在引入生成器表达式之后,我听说过很多关于溢出修复的讨论,但是我可能刚刚读过很旧的讨论,或者其他什么)
the*_*eye 10
是的,你是对的.在Python 3.x中,这是为了修复变量泄漏而引入的.引自Python博客的帖子,据说是由BDFL本人写的,
我们还在Python 3中进行了另一项更改,以改进列表推导和生成器表达式之间的等效性.在Python 2中,列表推导将循环控制变量"泄漏"到周围的范围中:
Run Code Online (Sandbox Code Playgroud)x = 'before' a = [x for x in 1, 2, 3] print x # this prints '3', not 'before'
这是列表推导的原始实现的工件; 多年来它一直是Python"肮脏的小秘密"之一.它起初是一种故意的妥协,使列表理解能够快速地进行,虽然它对于初学者来说不是常见的陷阱,但它偶尔会刺激人们.对于生成器表达式,我们不能这样做.生成器表达式使用生成器实现,生成器的执行需要单独的执行帧.因此,生成器表达式(特别是如果它们在短序列上迭代)的效率低于列表推导.
但是,在Python 3中,我们决定使用与生成器表达式相同的实现策略来修复列表推导的"脏小秘密".因此,在Python 3中,上面的例子(在修改后使用
print(x)
:-)将打印'before',证明列表推导中的'x'暂时阴影但不覆盖周围范围中的'x'.
所有问题都由突出显示的文字回答.
归档时间: |
|
查看次数: |
179 次 |
最近记录: |