17

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

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

假设foo保持不变,但bar改变了。有没有办法可以foo通过对象检查“实时”依赖项foo.__code__(与解析文本和使用 AST 相比)?

4

2 回答 2

5

我只是在__code__这里寻找对象,所以我不能说这肯定会起作用,但在我看来,您可以使用co_names元组(递归)遍历以特定函数为根的调用图,在为了建立某种可能被调用的函数的传递闭包的散列。(我认为不可能只包括将为 特定输入调用的函数,但你可以保守一点,包括所有可能的调用。)

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

于 2013-08-08T19:19:26.773 回答
5

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

>>> 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

如果bA中的方法发生了变化:

>>> 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

或使用以下检查方法inspect.getsource(object)

返回对象的源代码文本。参数可以是模块、类、方法、函数、回溯、框架或代码对象。源代码作为单个字符串返回。

如果您想知道代码是否动态更改,您可能需要重新加载您的类importlib并比较字节码。

于 2018-03-01T10:05:32.260 回答