检查两个 Python 函数是不是相等
Posted
技术标签:
【中文标题】检查两个 Python 函数是不是相等【英文标题】:Check if two Python functions are equal检查两个 Python 函数是否相等 【发布时间】:2013-12-02 06:22:44 【问题描述】:我想知道如何检查两个函数是否相同。一个例子是(lambda x: x) == (lambda y: y)
评估为真。据我所知,Python会检查函数是否在内存中占据相同的位置,而不是它们是否具有相同的操作。我知道拥有该功能似乎不切实际。
另一种解决方案是我可以在函数上运行一些方法来查看它包含什么或它是如何工作的。所以一种(lambda x: x).what()
会返回该方法的工作原理,可能在字典或其他东西中。
我很想得到答案,但我怀疑这是可能的。
【问题讨论】:
密切相关:Developing a heuristic to test simple anonymous Python functions for equivalency, Clojure test for equality of function expression ... 尽管 Python 问题的答案似乎假设无法直接获取字节码,因此您必须对其进行反汇编,然后尝试去除反汇编程序从源代码中添加的所有额外内容除了字节码,当它实际上完全有可能(而且更简单)直接获取字节码时,这很愚蠢...... 如果其他人来这里了解如何比较同一函数的两个引用:f==g
适合我
【参考方案1】:
您可以测试的一件事是代码对象相等性:
>>> x = lambda x: x
>>> y = lambda y: y
>>> x.__code__.co_code
'|\x00\x00S'
>>> x.__code__.co_code == y.__code__.co_code
True
这里两个函数的字节码是一样的。您可能需要验证代码对象的更多方面(想到常量和闭包),但相同的字节码应该等于相同的执行路径。
当然有很多方法可以创建对相同输入返回相同值但字节码不同的函数;剥鱼皮的方法总是有很多。
【讨论】:
您也可以在您的测试为真但结果不同的地方创建对象。 (这有点做作,但无论如何......):gist.github.com/sharth/7536465 @sharth:答案已经涵盖了这一点:“您可能需要验证……”他以闭包为例。自定义函数属性是另一个。给函数一个不同的__globals__
是另一回事。我认为我们不需要详尽的清单。
? 你说鱼,我说 catato。 ♪?
lambda x: x+1
和 lambda x: x+2
根据这个定义也是相等的。
@AndreasMueller:这与 abarnert 的评论属于同一标题;代码对象的 co_consts
元组变化很大。【参考方案2】:
如果您真的想知道两个函数是否总是对所有输入执行相同的操作,则必须在所有输入上都运行它们(这将花费无限时间),并拦截所有可能的副作用(这实际上是不可能)。
您当然可以想出一些启发式方法,向它们抛出一组不同的值,对于您的应用领域,如果功能不同,它们很可能会产生不同的输出。但显然没有通用的解决方案——否则,所有的单元测试都会自动生成,为我们节省了大量的工作,对吧?
相反,您可能只想知道两个函数是否具有完全相同的实现。为此,Martijn Pieters 的回答是显而易见的起点,甚至可能是终点(取决于您是否关心闭包、全局变量等)。
但是你要求的是与这两个不同的东西;您显然想手动查看代码以查看“它是如何工作的”:
另一个解决方案是我可以在函数上运行一些方法来查看它包含什么或它是如何工作的。所以一种 (lambda x: x).what() 会返回该方法的工作原理,可能在字典或其他东西中。
该函数已经存在:dis.dis
。当你在一个函数上运行它时,它会告诉你这个函数是如何工作的。不在字典中(什么字典?),而是在 Python 解释器的一系列字节码中(这是一个相对简单的堆栈机器,顶部添加了一些更高级别的东西,大部分在 dis
中描述文档)。
或者,更简单地说,您可以通过inspect.getsource
获取源代码。
这是您的示例中两者的样子:
>>> f1 = lambda x: x
>>> f2 = lambda y: y
>>> def f3(z):
... return z
>>> dis.dis(f1)
1 0 LOAD_FAST 0 (x)
3 RETURN_VALUE
>>> dis.dis(f2)
1 0 LOAD_FAST 0 (y)
3 RETURN_VALUE
>>> dis.dis(f3)
1 0 LOAD_FAST 0 (z)
3 RETURN_VALUE
>>> inspect.getsource(f1)
'f1 = lambda x: x\n'
>>> inspect.getsource(f2)
'f2 = lambda y: y\n'
>>> inspect.getsource(f3)
'def f3(z):\n return z\n'
在第一种情况下,您需要对dis
有足够的了解才能意识到(x)
等不是字节码的一部分,而是函数的本地名称列表的一部分。 (这在inspect
文档中与dis
文档中的解释一样多。)其次,您需要对Python 有足够的了解才能意识到def
和lambda
定义了完全相同的函数.所以,无论哪种方式,都没有办法自动化这个(或者,真的,任何超出 Martijn 答案的东西)。
【讨论】:
在某些情况下,可以使用自动定理证明器来证明函数的等价性,例如 Z3。以上是关于检查两个 Python 函数是不是相等的主要内容,如果未能解决你的问题,请参考以下文章
python - 如何在python中使用IF语句检查两个列表的元素是不是相等?