如何在Python中检查函数是否纯粹?

Car*_*orc 12 python formal-verification metaprogramming decorator purely-functional

一个纯粹的 功能类似于一个数学函数,在那里与"现实世界",也不副作用没有交互的功能.从更实际的角度来看,这意味着纯函数不能:

  • 打印或以其他方式显示消息
  • 随意
  • 取决于系统时间
  • 更改全局变量
  • 和别的

所有这些限制使得更容易推理纯函数而不是非纯函数.然后,大多数函数应该是纯函数,以便程序可以减少错误.

在像Haskell这样的庞大类型系统的语言中,如果函数是纯粹的或者不是纯粹的,读者可以从一开始就知道,使得连续阅读更容易.

在Python中,这些信息可以由@pure放在函数顶部的装饰器模拟.我也希望那个装饰器实际上做一些验证工作.我的问题在于这种装饰器的实现.

现在我只是看一下流行语的功能的源代码,如globalor randomprint抱怨,如果找到其中一个.

import inspect

def pure(function):
    source = inspect.getsource(function)
    for non_pure_indicator in ('random', 'time', 'input', 'print', 'global'):
        if non_pure_indicator in source:
            raise ValueError("The function {} is not pure as it uses `{}`".format(
                function.__name__, non_pure_indicator))
    return function
Run Code Online (Sandbox Code Playgroud)

然而,感觉就像一个奇怪的黑客,根据你的运气可能会或可能不会工作,你能帮我写一个更好的装饰?

str*_*bly 10

我有点看到你来自哪里,但我不认为这可行.我们举一个简单的例子:

def add(a,b):
    return a + b
Run Code Online (Sandbox Code Playgroud)

所以这对你来说可能看起来很"纯粹".但是在Python中,+这里是一个可以执行任何操作的任意函数,只需要在调用它时依赖于有效的绑定.这样a + b可以产生任意的副作用.

但它甚至比这更糟糕.即使这只是做标准整数,+那么还有更多"不纯"的东西在继续.

+是创建一个新的对象.现在,如果您确定只有调用者具有对该新对象的引用,那么您可以将其视为纯函数.但是你无法确定在该对象的创建过程中,没有泄露它的引用.

例如:

class RegisteredNumber(int):

    numbers = []

    def __new__(cls,*args,**kwargs):
        self = int.__new__(cls,*args,**kwargs)
        self.numbers.append(self)
        return self

    def __add__(self,other):
        return RegisteredNumber(super().__add__(other))

c = RegisteredNumber(1) + 2

print(RegisteredNumber.numbers)
Run Code Online (Sandbox Code Playgroud)

这将表明所谓的纯粹的添加函数实际上已经改变了RegisteredNumber类的状态.这不是一个愚蠢的例子:在我的生产代码库中,我们有跟踪每个创建的实例的类,例如,允许通过密钥访问.

纯粹的概念在Python中没有多大意义.