从 Python 3 中的代码对象中提取所有常量

Extracting all constants from code object in Python 3

我想提取函数中使用的所有常量。在 Python 2.7 中,我可以在函数的 __code__ 中遍历 co_consts 并提取所有字符串。例如, Python2.7

>>> def func():
...:     return 'foo' if True else ('bar',)

>>> print(func.__code__.co_consts)
(None, 'foo', 'bar', ('bar',)) # no need to look into the tuple as 'bar' is available outside it as well.

这将按预期给我 'foo''bar'。但是,在 Python 3.7 中,代码对象仅在元组内部包含 'bar'

Python 3.7

>>> print(func.__code__.co_consts)
(None, True, 'foo', ('bar',))

这意味着我还需要查看 co_consts 中的元组。我的困惑是 co_consts?

中是否可以有更多级别的嵌套

你可以递归地遍历 co_consts 元组然后:

def x():
    return {
        "y": ("bla" + "ble", ("blo", ["blu", "blip"])),
        ("x", "z"): "blup",
        True: False,
        42: "hello" * 10,
        None: 4 + 1j,
    }


def get_consts(func):
    def walk(cell):
        if isinstance(cell, tuple):
            for item in cell:
                yield from walk(item)
        else:
            yield cell

    yield from walk(func.__code__.co_consts)


for const in get_consts(x):
    print(const)

打印

None
blable
blo
blu
blip
blup
False
hellohellohellohellohellohellohellohellohellohello
(4+1j)
y
x
z
True
42
None

常数的顺序可能与原始来源中的顺序不同;它们确实对应于反汇编中的顺序:

  5           0 LOAD_CONST               1 ('blable')
              2 LOAD_CONST               2 ('blo')
              4 LOAD_CONST               3 ('blu')
              6 LOAD_CONST               4 ('blip')
              8 BUILD_LIST               2
             10 BUILD_TUPLE              2
             12 BUILD_TUPLE              2

  6          14 LOAD_CONST               5 ('blup')

  7          16 LOAD_CONST               6 (False)

  8          18 LOAD_CONST               7 ('hellohellohellohellohellohellohellohellohellohello')

  9          20 LOAD_CONST               8 ((4+1j))
             22 LOAD_CONST               9 (('y', ('x', 'z'), True, 42, None))
             24 BUILD_CONST_KEY_MAP      5
             26 RETURN_VALUE

编辑:如果您需要源代码中的原始字符串,则需要改用 ast 模块:

import ast
import inspect


class ConstantGatherer(ast.NodeVisitor):
    def __init__(self):
        super().__init__()
        self.consts = []

    def visit_Str(self, node):
        self.consts.append(node.s)

    def visit_Num(self, node):
        self.consts.append(node.n)


cg = ConstantGatherer()
cg.visit(ast.parse(inspect.getsource(x)))
print(cg.consts)

产出

['y', 'x', 'z', 42, 'bla', 'ble', 'blo', 'blu', 'blip', 'blup', 'hello', 10, 4, 1j]

如何在下面的代码中使用 inspect 从函数 f 中获取常量参数值 3?

def l2_norm(x, axis):
  print("l2_norm", x, axis)

f = lambda x: l2_norm(x, axis=3)