如何检查python函数是否已更改(在实时代码中)?

如何检查python函数是否已更改(在实时代码中)?,python,reflection,introspection,Python,Reflection,Introspection,如果我有一个函数的引用,我可以检查它的代码对象f.\uuuu code\uuuu,获取签名,然后对该签名执行后续检查,以查看代码是否更改。这很好。 但是如果函数的一个依赖项发生了变化怎么办?例如 def foo(a, b): return bar(a, b) 比如说foo保持不变,但是bar发生了变化。有没有一种方法可以通过foo.\uuu code\uuuu对象(与解析文本和使用AST相比)来检查foo的依赖项“实时”?我只是在这里浏览\uu code\uuuuu对象,所以我不能肯定

如果我有一个函数的引用,我可以检查它的代码对象
f.\uuuu code\uuuu
,获取签名,然后对该签名执行后续检查,以查看代码是否更改。这很好。 但是如果函数的一个依赖项发生了变化怎么办?例如

def foo(a, b):
    return bar(a, b)

比如说
foo
保持不变,但是
bar
发生了变化。有没有一种方法可以通过
foo.\uuu code\uuuu
对象(与解析文本和使用AST相比)来检查
foo
的依赖项“实时”?

我只是在这里浏览
\uu code\uuuuu
对象,所以我不能肯定这会起作用,但在我看来,你可以使用
co\u name
元组(递归地)来遍历以特定函数为根的调用图,以建立可能被调用的函数的传递闭包的某种散列。(我认为不可能只包含将为特定输入调用的函数,但可以保守地包含所有可能的调用。)


为此,您需要维护某种符号表,以便能够查找被调用函数的名称。但一旦你开始沿着这条路走下去,看起来你基本上要建立自己的AST。那么,为什么不从AST开始呢?

您可以使用
方法比较代码对象上的字节码属性。例如,让我们定义两个类:

>>> class A:
...     a = 1
...     def b(self, b):
...             print(self.a + b)
... 
>>> class B:
...     a = 1
...     def b(self, b):
...             print(self.a + b)
... 
>>> A().b.__code__.co_code
'|\x00\x00j\x00\x00|\x01\x00\x17GHd\x00\x00S'
>>> B().b.__code__.co_code
'|\x00\x00j\x00\x00|\x01\x00\x17GHd\x00\x00S'
>>> A().b.__code__.co_code == B().b.__code__.co_code
True
如果类
A
中的方法
b
发生变化:

>>> class A:
...     a = 1
...     def b(self, b):
...             print(b + self.a)
... 
>>> A().b.__code__.co_code
'|\x01\x00|\x00\x00j\x00\x00\x17GHd\x00\x00S'
>>> A().b.__code__.co_code == B().b.__code__.co_code
False
或使用检查方法:

返回对象的源代码文本。这个论点可能是正确的 模块、类、方法、函数、回溯、帧或代码对象。 源代码作为单个字符串返回


如果您想知道代码是否在动态中发生了更改,您可能需要使用字节码重新加载类并进行比较。

请问您为什么要这样做?更广泛的目的是什么?如果你需要这样做,那么一定是出了严重的问题。(另外,holy crap.Python允许您重新分配函数的代码。这将被归档在“features to never,ever touch”(永不接触的特性)下。不管您的意图如何,这似乎仍然是一个有趣的问题,尽管有点学术性。非学术性:)。我有一个pipeline对象,它接受一系列通常很简单的“处理器”,每个处理器接受一条最初来自静态源的记录,对其进行扩充并传递给下一个处理器。这是表示所需预处理的好方法,但效率不高。因此,cache对象将处理后的记录转储到一个(json)文件中作为缓存。获取函数签名的原因是当某些内容发生变化时强制刷新缓存。@Maxikhesin我正计划做同样的事情,哇。我的设置是针对ML/数据处理管道的,只有在函数代码更改时才重新计算值。谢谢。我也在做同样的事情(脑子里想着同样的递归处理),但是“bar”并不存在!