将uncompyle6用于代码对象的正确方法是什么?

时间:2018-07-12 18:28:20

标签: python

我在github (original)上找到了这个示例,但这似乎已经过时了,所以我做了一些改动。

from uncompyle6.main import decompile 
import sys

def uncompyle_test():
    gen = (expr1 if cond1 else expr2 for A in [] if (expr3 if cond2 else expr4))
    co = gen.gi_code
    decompile (3.6, co, sys.stdout, showast=False)

uncompyle_test()

通过运行此命令,我得到 .0A if expr3 if cond2 else expr4。 这似乎很不正确。我错过了什么还是仅仅是一个错误?

1 个答案:

答案 0 :(得分:1)

这不是一个完整的答案,但它应该使您对正在发生的事情有所了解。

首先要注意的是,传递到decompile()函数中的字节码版本应与您正在运行的Python版本相同,因为这是正在生成的字节码。 xdis具有确保以下功能的功能:

>>> from xdis.magics import sysinfo2float
>>> sysinfo2float()
3.6

但是我认为情况就是如此。

第二,当您反编译整个程序时,会得到正确的结果:

# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.5 (default, Apr  9 2018, 01:37:56) 
# [GCC 7.2.0]
# Embedded file name: exec
# Compiled at: 2018-09-18 16:10:11
# Size of source mod 2**32: 243 bytes
from uncompyle6.main import decompile
import sys

def uncompyle_test():
    gen = ((expr1 if cond1 else expr2) for A in [] if (expr3 if cond2 else expr4))
    co = gen.gi_code
    decompile(3.6, co, sys.stdout, showast=False)

那么,为什么您尝试的方法不起作用?主要的问题是uncompyle6需要知道它试图贬低什么样的东西。回想一下compile()函数具有三个“模式”:“ exec”,“ eval”和“ single”。

摘自built-in function compile()的Python文档:

  

mode参数指定必须编译的代码类型;它可以   如果source由语句序列组成,则为'exec';如果它由语句序列组成,则为'eval'   由一个表达式组成,如果由一个表达式组成,则为“单个”   单一互动声明

这里的上下文是s生成器,eval是一种表达。 deparse()不允许您选择要表达的意思,而是使用“ exec”。在解析的较低级别,尽管您将“ exec”与“ single”区分开,但是目前尚无一种方法可以指定“ eval”,更不用说在此特定函数中了。我打开了一个uncompyle6问题来注意这一点。

最后,让我们更多地描述为什么您看到自己看到的东西。

为此,让我们使用我编写的这个方便且独特的调试器,向您展示在解析过程中如何运行,更重要的是在反汇编中。

$ trepan3k /tmp/bug.py 
(/tmp/bug.py:1): <module>
-> 1 from uncompyle6.main import decompile
Rocky's Python Trepan Python code startup loaded
(trepan3k) next 2
(/tmp/bug.py:9 @28): <module>
-- 9 uncompyle_test()
(trepan3k) step
(/tmp/bug.py:4): uncompyle_test
-> 4 def uncompyle_test():
(trepan3k) next 3
(/tmp/bug.py:7 @20): uncompyle_test
-- 7     decompile (3.6, co, sys.stdout, showast=False)
(trepan3k) disasm co
Disassembly of <code object <genexpr> at 0x7f6a3faff300, file "/tmp/bug.py", line 5>: 
   5        0 LOAD_FAST           0          .0                  
       >>   2 FOR_ITER            30         to 34               
            4 STORE_FAST          1          A                   
            6 LOAD_GLOBAL         0          cond2               
            8 POP_JUMP_IF_FALSE   14         to 14               
           10 LOAD_GLOBAL         1          expr3               
           12 JUMP_FORWARD        2          to 16               
       >>  14 LOAD_GLOBAL         2          expr4               
       >>  16 POP_JUMP_IF_FALSE   2          to 2                
           18 LOAD_GLOBAL         3          cond1               
           20 POP_JUMP_IF_FALSE   26         to 26               
           22 LOAD_GLOBAL         4          expr1               
           24 JUMP_FORWARD        2          to 28               
       >>  26 LOAD_GLOBAL         5          expr2               
       >>  28 YIELD_VALUE         None                           
           30 POP_TOP             None                           
           32 JUMP_ABSOLUTE       2          to 2                
       >>  34 LOAD_CONST          0          None                
           36 RETURN_VALUE        None                           
(trepan3k) Leaving
trepan3k: That's all, folks...

因此,您看到.0确实来自代码:它是在生成器内部使用的临时变量。但是,应该有某种“ for”,并且“ []”中也缺少。这是丢失的,因为我认为其他地方的代码可以起到作用。

总而言之,事情有点怪异,因为顶级上下文不正确。应该使用假定这是单个表达式的语法规则,而不是完整程序的语法规则。