如何从dis获取函数参数

时间:2019-03-21 14:48:48

标签: python dis

如何从代码对象获取python中的函数参数列表。

import xdis.std as dis
ops = list(dis.Bytecode("""def f(a, b):
    return 1"""))
print(ops)
code_obj = ops[0]
print(list(dis.Bytecode(code_obj.argval)))

以上代码使用xdis模块反编译需要通过pip安装的代码。但是,代码对象是普通对象,您可以从python中的默认dis模块中获得期望。 我想知道如何按顺序获取函数参数列表。在这种情况下,a和b

这是交互式python中的输出-

>>> import xdis.std as dis
>>> ops = list(dis.Bytecode("""def f(a, b):
...     return 1"""))
>>> print(ops)
[Instruction(opname='LOAD_CONST', opcode=100, optype='const', inst_size=2, arg=0, argval=<code object f at 0x7a1a5c4f60, file "<disassembly>", line 1>, argrepr='<code object f at 0x7a1a5c4f60, file "<disassembly>", line 1>', has_arg=True, offset=0, starts_line=1, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, optype='const', inst_size=2, arg=1, argval='f', argrepr="'f'", has_arg=True, offset=2, starts_line=None, is_jump_target=False), Instruction(opname='MAKE_FUNCTION', opcode=132, optype=None, inst_size=2, arg=0, argval=0, argrepr='', has_arg=True, offset=4, starts_line=None, is_jump_target=False), Instruction(opname='STORE_NAME', opcode=90, optype='name', inst_size=2, arg=0, argval='f', argrepr='f', has_arg=True, offset=6, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, optype='const', inst_size=2, arg=2, argval=None, argrepr='None', has_arg=True, offset=8, starts_line=None, is_jump_target=False), Instruction(opname='RETURN_VALUE', opcode=83, optype=None, inst_size=2, arg=None, argval=None, argrepr='', has_arg=False, offset=10, starts_line=None, is_jump_target=False)]
>>> code_obj = ops[0]
>>> print(list(dis.Bytecode(code_obj.argval)))
[Instruction(opname='LOAD_CONST', opcode=100, optype='const', inst_size=2, arg=1, argval=1, argrepr='1', has_arg=True, offset=0, starts_line=2, is_jump_target=False), Instruction(opname='RETURN_VALUE', opcode=83, optype=None, inst_size=2, arg=None, argval=None, argrepr='', has_arg=False, offset=2, starts_line=None, is_jump_target=False)]

2 个答案:

答案 0 :(得分:1)

如果您有代码对象

def f(a, b, *, c=True):
    e = a + b
    if c:
        return a * e

code_obj = f.__code__

那么位置参数是

code_obj.co_varnames[:code_obj.co_argcount]

# --> ('a', 'b')

和仅关键字参数

code_obj.co_varnames[code_obj.co_argcount : code_obj.co_argcount + code_obj.co_kwonlyargcount]

# --> ('c',)

答案 1 :(得分:0)

xdis在这里不会为您提供许多有用的功能。它只是为您提供了更多的对象输出,从理论上讲,您可以比常规的dis模块更轻松地处理对象。但是,库存模块告诉我们我们需要知道的所有信息:

>>> from dis import dis
>>> def f(a, b):
...   return 1
...
>>> dis(f)
  2           0 LOAD_CONST               1 (1)
              2 RETURN_VALUE

请注意反汇编如何仅包含两个操作码。 LOAD_CONST1推入堆栈(cpython运行时基于堆栈),并且RETURN_VALUE从函数返回,其值在堆栈顶部。这里没有提及ab。这是有道理的。他们不被使用!字节字节码与函数参数无关。它将发出必要的操作,以将它们放入堆栈中(需要时):

>>> def f(a, b):
...   return a + b
...
>>> dis(f)
  2           0 LOAD_FAST                0 (a)
              2 LOAD_FAST                1 (b)
              4 BINARY_ADD
              6 RETURN_VALUE

请注意,LOAD_FAST得到ab并将它们压入堆栈,以BINARY_ADD(将堆栈中的前两个值相加并压入结果)

您可以使用__code__来获得所需的内容,特别是:

params_and_locals = f.__code__.co_varnames
num_args = f.__code__.co_argcount + f.__code__.co_kwonlyargcount
params = params_and_locals[:num_args]