使用IF语句的ABSOLUTE? Python 2.5
我一直在使用'dis'模块来重新编写一些编译脚本(.pyc)。 我了解JUMP_FORWARD和JUMP_ABSOLUTE之间的区别。 据我所知,IF声明将由JUMP_FORWARD关闭:
>>> def f():
if a:
print ''
>>> from dis import dis
>>> dis(f)
2 0 LOAD_GLOBAL 0 (a)
3 JUMP_IF_FALSE 9 (to 15)
6 POP_TOP
3 7 LOAD_CONST 1 ('')
10 PRINT_ITEM
11 PRINT_NEWLINE
12 JUMP_FORWARD 1 (to 16)
>> 15 POP_TOP
>> 16 LOAD_CONST 0 (None)
19 RETURN_VALUE
如果IF语句位于另一个循环的末尾,则会出现JUMP_ABSOLUTE。 例如:
>>> def f1():
if a:
if b:
print ''
>>> dis(f1)
2 0 LOAD_GLOBAL 0 (a)
3 JUMP_IF_FALSE 20 (to 26)
6 POP_TOP
3 7 LOAD_GLOBAL 1 (b)
10 JUMP_IF_FALSE 9 (to 22)
13 POP_TOP
4 14 LOAD_CONST 1 ('')
17 PRINT_ITEM
18 PRINT_NEWLINE
19 JUMP_ABSOLUTE 27
>> 22 POP_TOP
23 JUMP_FORWARD 1 (to 27)
>> 26 POP_TOP
>> 27 LOAD_CONST 0 (None)
30 RETURN_VALUE
从我读的代码中读回的Bytecode,有一个令我惊讶的JUMP_ABSOLUTE:
121 228 LOAD_FAST 11 (a)
231 LOAD_CONST 9 (100)
234 COMPARE_OP 0 (<)
237 JUMP_IF_FALSE 23 (to 263)
240 POP_TOP
241 LOAD_FAST 11 (b)
244 LOAD_CONST 11 (10)
247 COMPARE_OP 4 (>)
250 JUMP_IF_FALSE 10 (to 263)
253 POP_TOP
122 254 LOAD_CONST 3 (1)
257 STORE_FAST 4 (ok)
260 JUMP_ABSOLUTE 27
>> 263 POP_TOP
我会认为代码如下:
if a<100 and b>10:
ok=1
但它引发了JUMP_FORWARD而不是JUMP_ABSOLUTE。 我知道它不是WHILE循环,也不是FOR语句,因为它们都在字节码中创建了一条SETUP_LOOP行。
我的问题是:我错过了什么? 为什么我得到FORWARD而不是ABSOLUTE跳转?
编辑:绝对跳转到索引27指向这两条线121和122所属的(WHILE?)循环的开始:
106 24 SETUP_LOOP 297 (to 324)
>> 27 LOAD_FAST 4 (ok)
30 LOAD_CONST 1 (0)
33 COMPARE_OP 2 (==)
36 JUMP_IF_FALSE 283 (to 322)
39 POP_TOP
这些行之前有一个IF语句和另一个语句。 这是之前的代码,使用相同的JUMP_ABSOLUTE关闭语句。
115 170 LOAD_FAST 3 (q)
173 LOAD_CONST 10 (1)
176 COMPARE_OP 0 (<)
179 JUMP_IF_FALSE 45 (to 227)
182 POP_TOP
183 LOAD_FAST 11 (z)
186 LOAD_CONST 11 (10)
189 COMPARE_OP 4 (>)
192 JUMP_IF_FALSE 32 (to 227)
195 POP_TOP
116 196 LOAD_CONST 1 (0)
199 STORE_FAST 4 (ok)
117 202 LOAD_FAST 5 (u)
205 LOAD_CONST 3 (1)
208 BINARY_ADD
209 STORE_FAST 5 (u)
118 212 LOAD_CONST 1 (0)
215 STORE_FAST 3 (k)
119 218 LOAD_CONST 3 (10)
221 STORE_FAST 6 (dv)
224 JUMP_ABSOLUTE 27
>> 227 POP_TOP
JUMP_FORWARD表示“转到下一行”,JUMP_ABSOLUTE表示“返回到WHILE循环的开始处”。 问题是我不知道如何复制一个能够提供与上面相同的字节码的代码。
谢谢 !
我接受了挑战,在你的帮助下,你可以使用下面的(无意义的)函数重现你的情况(或者类似的东西):
>>> def f():
... while ok==0:
... if q<1 and z>10:
... ok=0
... u=u+1
... k=0
... dv=10
... elif a<100 and b>10:
... ok=1
...
>>> dis(f)
2 0 SETUP_LOOP 112 (to 115)
>> 3 LOAD_FAST 0 (ok)
6 LOAD_CONST 1 (0)
9 COMPARE_OP 2 (==)
12 JUMP_IF_FALSE 98 (to 113)
15 POP_TOP
3 16 LOAD_GLOBAL 0 (q)
19 LOAD_CONST 2 (1)
22 COMPARE_OP 0 (<)
25 JUMP_IF_FALSE 45 (to 73)
28 POP_TOP
29 LOAD_GLOBAL 1 (z)
32 LOAD_CONST 3 (10)
35 COMPARE_OP 4 (>)
38 JUMP_IF_FALSE 32 (to 73)
41 POP_TOP
4 42 LOAD_CONST 1 (0)
45 STORE_FAST 0 (ok)
5 48 LOAD_FAST 1 (u)
51 LOAD_CONST 2 (1)
54 BINARY_ADD
55 STORE_FAST 1 (u)
6 58 LOAD_CONST 1 (0)
61 STORE_FAST 2 (k)
7 64 LOAD_CONST 3 (10)
67 STORE_FAST 3 (dv)
70 JUMP_ABSOLUTE 3
>> 73 POP_TOP
8 74 LOAD_GLOBAL 2 (a)
77 LOAD_CONST 4 (100)
80 COMPARE_OP 0 (<)
83 JUMP_IF_FALSE 23 (to 109)
86 POP_TOP
87 LOAD_GLOBAL 3 (b)
90 LOAD_CONST 3 (10)
93 COMPARE_OP 4 (>)
96 JUMP_IF_FALSE 10 (to 109)
99 POP_TOP
9 100 LOAD_CONST 2 (1)
103 STORE_FAST 0 (ok)
106 JUMP_ABSOLUTE 3
>> 109 POP_TOP
110 JUMP_ABSOLUTE 3
>> 113 POP_TOP
114 POP_BLOCK
>> 115 LOAD_CONST 0 (None)
118 RETURN_VALUE
第8行和第11行具有您要求的JUMP_ABSOLUTE
。 像LOAD_GLOBAL
和LOAD_FAST
类的轻微差异是由变量的范围引起的。
请注意,我不得不切换到Python 2.5来重现这一点。 较新的版本会产生不同的结果。
如果continue
似乎不适用于您的情况,我建议您在Python的源代码中进行一些研究,并在Python/compile.c
中查找ADDOP_JABS
以了解在其他情况下是否插入了绝对跳转。
如果你的目标是“只”反编译这个.pyc
,那么你应该尝试uncompyle2
,它将自己描述为“用Python 2.7编写的Python uncompyle2
字节代码反编译器”