我想了解如何使用dis(Python字节码的解析器).具体来说,如何解释dis.dis(或dis.disassemble)的输出?
.
这是一个非常具体的例子(在Python 2.7.3中):
dis.dis("heapq.nsmallest(d,3)")
0 BUILD_SET 24933
3 JUMP_IF_TRUE_OR_POP 11889
6 JUMP_FORWARD 28019 (to 28028)
9 STORE_GLOBAL 27756 (27756)
12 LOAD_NAME 29811 (29811)
15 STORE_SLICE+0
16 LOAD_CONST 13100 (13100)
19 STORE_SLICE+1
Run Code Online (Sandbox Code Playgroud)
我看到JUMP_IF_TRUE_OR_POP等等是字节码指令(虽然有趣的是,BUILD_SET这个列表中没有出现,但我希望它可以工作BUILD_TUPLE).我认为右边的数字是内存分配,左边的数字是转到数字......我注意到它们每次几乎增加3(但不完全).
如果我dis.dis("heapq.nsmallest(d,3)")在函数内部换行:
def f_heapq_nsmallest(d,n):
return heapq.nsmallest(d,n)
dis.dis("f_heapq(d,3)")
0 BUILD_TUPLE 26719
3 LOAD_NAME 28769 (28769)
6 JUMP_ABSOLUTE 25640
9 <44> # what is <44> ?
10 DELETE_SLICE+1
11 STORE_SLICE+1
Run Code Online (Sandbox Code Playgroud) 我对python如何实现闭包感兴趣?
为了举例,请考虑这个
def closure_test():
x = 1
def closure():
nonlocal x
x = 2
print(x)
return closure
closure_test()()
Run Code Online (Sandbox Code Playgroud)
这里,该函数closure_test有一个x嵌套函数closure捕获的局部变量。
当我运行该程序时,我得到以下输出
2
Run Code Online (Sandbox Code Playgroud)
当我看到函数的反汇编时closure_test,
2 0 LOAD_CONST 1 (1)
2 STORE_DEREF 0 (x)
3 4 LOAD_CLOSURE 0 (x)
6 BUILD_TUPLE 1
8 LOAD_CONST 2 (<code object closure at 0x7f14ac3b9500, file "<string>", line 3>)
10 LOAD_CONST 3 ('closure_test.<locals>.closure')
12 MAKE_FUNCTION 8 (closure)
14 STORE_FAST 0 (closure)
7 16 LOAD_FAST 0 (closure)
18 RETURN_VALUE
Disassembly of …Run Code Online (Sandbox Code Playgroud) 来自Google样式指南的词法范围:
嵌套的Python函数可以引用封闭函数中定义的变量,但不能赋值给它们.
这两个似乎最初都要检查:
# Reference
def toplevel():
a = 5
def nested():
print(a + 2)
nested()
return a
toplevel()
7
Out[]: 5
# Assignment
def toplevel():
a = 5
def nested():
a = 7 # a is still 5, can't modify enclosing scope variable
nested()
return a
toplevel()
Out[]: 5
Run Code Online (Sandbox Code Playgroud)
那么,为什么嵌套函数中的引用和赋值的组合会导致异常呢?
# Reference and assignment
def toplevel():
a = 5
def nested():
print(a + 2)
a = 7
nested()
return a
toplevel()
# UnboundLocalError: local variable 'a' referenced …Run Code Online (Sandbox Code Playgroud)