对python的LOAD_FAST / STORE_FAST感到困惑 [英] Puzzled with LOAD_FAST/STORE_FAST of python

查看:109
本文介绍了对python的LOAD_FAST / STORE_FAST感到困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我编写一些代码时,我发现了一件有趣的事情:

When I wrote some code, I found a interesting thing:

def test():
  l = []
  for i in range(10):
    def f():pass
    print(f)
    #l.append(f)

test()

import dis
dis.dis(test)

输出是:

<function test.<locals>.f at 0x7f46c0b0d400>
<function test.<locals>.f at 0x7f46c0b0d488>
<function test.<locals>.f at 0x7f46c0b0d400>
<function test.<locals>.f at 0x7f46c0b0d488>
<function test.<locals>.f at 0x7f46c0b0d400>
<function test.<locals>.f at 0x7f46c0b0d488>
<function test.<locals>.f at 0x7f46c0b0d400>
<function test.<locals>.f at 0x7f46c0b0d488>
<function test.<locals>.f at 0x7f46c0b0d400>
<function test.<locals>.f at 0x7f46c0b0d488>
  6           0 BUILD_LIST               0
              3 STORE_FAST               0 (l)

  7           6 SETUP_LOOP              42 (to 51)
              9 LOAD_GLOBAL              0 (range)
             12 LOAD_CONST               1 (10)
             15 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             18 GET_ITER
        >>   19 FOR_ITER                28 (to 50)
             22 STORE_FAST               1 (i)

  8          25 LOAD_CONST               2 (<code object f at 0x7f46c0bd8420, file "ts.py", line 8>)
             28 LOAD_CONST               3 ('test.<locals>.f')
             31 MAKE_FUNCTION            0
             34 STORE_FAST               2 (f)

  9          37 LOAD_GLOBAL              1 (print)
             40 LOAD_FAST                2 (f)
             43 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             46 POP_TOP
             47 JUMP_ABSOLUTE           19
        >>   50 POP_BLOCK
        >>   51 LOAD_CONST               0 (None)
             54 RETURN_VALUE

何时

def test():
  l = []
  for i in range(10):
    def f():pass
    print(f)
    l.append(f)

test()

import dis
dis.dis(test)

输出为:

<function test.<locals>.f at 0x7ff88ffe0400>
<function test.<locals>.f at 0x7ff88ffe0488>
<function test.<locals>.f at 0x7ff88ffe0510>
<function test.<locals>.f at 0x7ff88ffe0598>
<function test.<locals>.f at 0x7ff88ffe0620>
<function test.<locals>.f at 0x7ff88ffe06a8>
<function test.<locals>.f at 0x7ff88ffe0730>
<function test.<locals>.f at 0x7ff88ffe07b8>
<function test.<locals>.f at 0x7ff88ffe0840>
<function test.<locals>.f at 0x7ff88ffe08c8>
  6           0 BUILD_LIST               0
              3 STORE_FAST               0 (l)

  7           6 SETUP_LOOP              55 (to 64)
              9 LOAD_GLOBAL              0 (range)
             12 LOAD_CONST               1 (10)
             15 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             18 GET_ITER
        >>   19 FOR_ITER                41 (to 63)
             22 STORE_FAST               1 (i)

  8          25 LOAD_CONST               2 (<code object f at 0x7ff8900ab420, file "ts.py", line 8>)
             28 LOAD_CONST               3 ('test.<locals>.f')
             31 MAKE_FUNCTION            0
             34 STORE_FAST               2 (f)

  9          37 LOAD_GLOBAL              1 (print)
             40 LOAD_FAST                2 (f)
             43 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             46 POP_TOP

 10          47 LOAD_FAST                0 (l)
             50 LOAD_ATTR                2 (append)
             53 LOAD_FAST                2 (f)
             56 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             59 POP_TOP
             60 JUMP_ABSOLUTE           19
        >>   63 POP_BLOCK
        >>   64 LOAD_CONST               0 (None)
             67 RETURN_VALUE

如果 STORE_FAST 缓存 f ,为什么在第一个代码段中, f 的地址为

If STORE_FAST "cached" the f, why in the first code snippet, the address of f is alternant?

在第二个片段中,它有两个 LOAD_FAST ,结果是正常的。

And in the second snippet, it has two LOAD_FAST , and the result is normal.

LOAD_FAST / STORE_FAST是否做了一些未知的事情?

Is LOAD_FAST/STORE_FAST did some unknow things?

推荐答案

在当前 f 重新声明之后,较旧的函数对象的每个备用迭代都没有引用,因此将其进行垃圾回收,Python可以在下一个重复使用该内存空间迭代。另一方面,列表是引用每个函数的,因此它们永远不会被垃圾回收。

That's happening because in each alternate iteration the older function object after the re-declaration of the current f has no references left, so it is garbage collected and Python can re-use that memory space in next iteration. On the other hand in the second the list is referring to each function so they are never garbage collected.

这是实现相关的东西,CPython的垃圾回收基于引用计数。在PyPy上,输出是不同的:

This is an implementation dependent thing, CPython's garbage collection is based on reference count. On PyPy the output is different:

$ ~/pypy-2.4.0-linux64/bin# ./pypy 
Python 2.7.8 (f5dcc2477b97, Sep 18 2014, 11:33:30)
[PyPy 2.4.0 with GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>> def test():
....     for i in range(10):
....         def f(): pass
....         print f
.... 
>>>> test()
<function f at 0x00007f055c77d5b0>
<function f at 0x00007f055c77d628>
<function f at 0x00007f055c77d6a0>
<function f at 0x00007f055c77d718>
<function f at 0x00007f055c77d790>
<function f at 0x00007f055c77d808>
<function f at 0x00007f055c77d880>
<function f at 0x00007f055c77d8f8>
<function f at 0x00007f055c77d970>
<function f at 0x00007f055c77d9e8>

这篇关于对python的LOAD_FAST / STORE_FAST感到困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆