用 Perl 的 B::Concise 之类的东西转储 Python optree?

Dumping the Python optree with something like Perl's B::Concise?

Perl 有一个叫做 B::Concise 的东西,我们可以将它与 -MO=Concise

一起使用
perl -MO=Concise -e "!$a&&!$b"
7  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 1 -e:1) v:{ ->3
6     <1> not vK/1 ->7
4        <|> or(other->5) sK/1 ->6
-           <1> ex-not sK/1 ->4
-              <1> ex-rv2sv sK/1 ->-
3                 <#> gvsv[*a] s ->4
-           <1> ex-not sK/1 ->6
-              <1> ex-rv2sv sK/1 ->-
5                 <#> gvsv[*b] s ->6

有没有办法让 Python 以文本可读的形式转储 optree?

我能够使用 dis 模块做到这一点

import dis;

a = 5;

def f():
    a = a+1
    print "foo"

print dis.dis(f);

输出,

  7           0 LOAD_FAST                0 (a)
              3 LOAD_CONST               1 (1)
              6 BINARY_ADD          
              7 STORE_FAST               0 (a)

  8          10 LOAD_CONST               2 ('foo')
             13 PRINT_ITEM          
             14 PRINT_NEWLINE       
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE        
None

而不是从dis, you can get the AST from ast获取字节码:

>>> import ast
>>> ast.dump(ast.parse("a = a+1").body[0])
"Assign(targets=[Name(id='a', ctx=Store())], value=BinOp(left=Name(id='a', ctx=Load()), op=Add(), right=Num(n=1)))"

问题中的例子:

>>> ast.dump(ast.parse("not a and not b").body[0])
"Expr(value=BoolOp(op=And(), values=[UnaryOp(op=Not(), operand=Name(id='a', ctx=Load())), UnaryOp(op=Not(), operand=Name(id='b', ctx=Load()))]))"

定义示例:

>>> ast.dump(ast.parse("""def f():
...     a = a+1
...     print \"foo\"""").body[0])
"FunctionDef(name='f', args=arguments(args=[], vararg=None, kwarg=None, defaults=[]), body=[Assign(targets=[Name(id='a', ctx=Store())], value=BinOp(left=Name(id='a', ctx=Load()), op=Add(), right=Num(n=1))), Print(dest=None, values=[Str(s='foo')], nl=True)], decorator_list=[])"