如何处理“inspect.getsource”的限制 - 或者如何只获取函数的来源?

问题描述 投票:2回答:1

我一直在使用Python标准库中的inspect模块。

以下示例工作正常(假设已导入inspect):

def foo(x, y):
    return x - y
print(inspect.getsource(foo))

...将打印def foo(x, y):\n return x - y\n和......

bar = lambda x, y: x / y
print(inspect.getsource(bar))

...将打印bar = lambda x, y: x / y\n。到现在为止还挺好。然而,在以下示例中,事情变得有点奇怪:

print(inspect.getsource(lambda x, y: x / y))

...将打印print(inspect.getsource(lambda x, y: x / y))和......

baz = [2, 3, lambda x, y: x / y, 5]
print(inspect.getsource(baz[2]))

...将打印baz = [2, 3, lambda x, y: x / y, 5]

该模式似乎是所有相关的源代码行,无论上下文是由getsource返回的。除了所需的功能源/定义之外,还包括这些行中的所有其他内容。是否有另一种“替代”方法,它可以提取代表函数源代码的东西 - 只有源代码 - 最好是以某种匿名方式?


编辑(1)

def foo(x, y):
    return x - y
bar = [1, 2, foo, 4]
print(inspect.getsource(bar[2]))

...将打印def foo(x, y):\n return x - y\n

python python-3.x inspect
1个回答
3
投票

不幸的是,使用inspect是不可能的,如果不再解析(和编译)源代码,它就不可能工作。 inspectgetsource方法相当有限:它使用getsourcelines来调用然后findsource,它基本上解开你的对象直到我们最终在PyCodeObject

那时,我们正在处理编译的字节码。所有这些都是从原始来源are fragments and hints, such留下的co_firstlineno

/* Bytecode object */
typedef struct {
    /* ... other fields omitted ... */
    int co_firstlineno;         /* first source line number */
    PyObject *co_code;          /* instruction opcodes */
    /* ... other fields omitted ... */
} PyCodeObject;

顺便说一句,类似于PyCodeObjectPyFrameObject also contains only a f_lineno,但没有列,这解释了为什么回溯只包括文件名和行:列不编译成字节码。

由于字节码不包含比(第一)行更具体的区域,因此无法从inspect或任何其他仅使用(公共)字节码信息的库中获取确切的源位置而无需进一步解析。这也适用于仅使用字节码的任何其他选项,例如pickle

inspect使用公共信息(co_firstlineno)和then just searches for a suitable begin of a function and the end of the surrounding block。然而,inspect几乎就在那里,但它只找到any block, not the correct one,目前找不到正确的。 inspect标记整行并且不从正确的变体开始,它也不知道正确的相应源代码区域。

让我们说我们有

plus, minus, mult = lambda x: x + 1, lambda y: y - 1, lambda z: z * 5

我们只想要minus。由于字节码不包含co_firstcolumn,我们只提供完整的行。我们可以解析所有lambda,但我们仍然不知道哪个lambda适合我们的co_code。我们需要再次编译它们并检查它们的字节码是否适合原始字节码。

最后,我们必须这样做:再次解析源并找到正确的PyCodeObject。如果我们至少有一个起始列号就好了,因为我们可以使用语法分析,但AST只保留line numbers at the moment。所以要么inspect需要一个大的补丁,要么字节码需要包含编译对象的起始列。

© www.soinside.com 2019 - 2024. All rights reserved.