如何检查 Python 中的函数是否纯?
How to check if a function is pure in Python?
A pure function 是一个类似于数学函数的函数,其中没有与 "Real world" 的相互作用,也没有副作用。从更实际的角度来说,就是说一个纯函数可以not:
- 打印或以其他方式显示消息
- 随机
- 取决于系统时间
- 更改全局变量
- 其他
所有这些限制使得纯函数比非纯函数更容易推理。大部分的功能应该是纯粹的,这样程序才能有更少的错误。
在像 Haskell 这样具有庞大类型系统的语言中,reader 可以从一开始就知道函数是纯函数还是非纯函数,从而使后续阅读更容易。
在 Python 中,此信息可以通过放在函数顶部的 @pure
装饰器来模拟。我还希望那个装饰器真正做一些验证工作。我的问题在于这样一个装饰器的实现。
现在我只是简单地查看函数的源代码以查找诸如 global
或 random
或 print
之类的流行词,如果找到其中一个就会抱怨。
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
然而,这感觉像是一个奇怪的 hack,它可能会或可能不会取决于你的运气,你能帮我写一个更好的装饰器吗?
(不是答案,但评论太长了)
所以如果一个函数可以return 同一组参数的不同值,它就不是纯粹的?
请记住 Python 中的函数是对象,因此您想检查对象的纯度...
举个例子:
def foo(x):
ret, foo.x = x*x+foo.x, foo.x+1
return ret
foo.x=0
重复调用 foo(3)
得到:
>>> foo(3)
9
>>> foo(3)
10
>>> foo(3)
11
...
此外,读取全局变量不需要使用 global
语句或函数中的 global()
内置函数。全局变量可能会在其他地方发生变化,从而影响函数的纯度。
上述所有情况在运行时可能很难检测到。
我有点明白你是从哪里来的,但我认为这行不通。举个简单的例子:
def add(a,b):
return a + b
所以这对您来说可能看起来 "pure"。但是在 Python 中,+
是一个可以做任何事情的任意函数,仅取决于调用时有效的绑定。所以 a + b
可以有任意的副作用。
但比这更糟。即使这只是在做标准整数 +
,还有更多 'impure' 事情在进行。
+
正在创建一个新对象。现在,如果您确定只有调用者拥有对该新对象的引用,那么在某种意义上您可以将其视为纯函数。但是你不能确定,在那个对象的创建过程中,没有泄漏对它的引用。
例如:
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)
这将表明所谓的纯 add 函数实际上已经改变了 RegisteredNumber
class 的状态。这不是一个愚蠢的例子:在我的生产代码库中,我们有 classes 跟踪每个创建的实例,例如,允许通过密钥访问。
纯洁的概念在 Python 中没有多大意义。
A pure function 是一个类似于数学函数的函数,其中没有与 "Real world" 的相互作用,也没有副作用。从更实际的角度来说,就是说一个纯函数可以not:
- 打印或以其他方式显示消息
- 随机
- 取决于系统时间
- 更改全局变量
- 其他
所有这些限制使得纯函数比非纯函数更容易推理。大部分的功能应该是纯粹的,这样程序才能有更少的错误。
在像 Haskell 这样具有庞大类型系统的语言中,reader 可以从一开始就知道函数是纯函数还是非纯函数,从而使后续阅读更容易。
在 Python 中,此信息可以通过放在函数顶部的 @pure
装饰器来模拟。我还希望那个装饰器真正做一些验证工作。我的问题在于这样一个装饰器的实现。
现在我只是简单地查看函数的源代码以查找诸如 global
或 random
或 print
之类的流行词,如果找到其中一个就会抱怨。
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
然而,这感觉像是一个奇怪的 hack,它可能会或可能不会取决于你的运气,你能帮我写一个更好的装饰器吗?
(不是答案,但评论太长了)
所以如果一个函数可以return 同一组参数的不同值,它就不是纯粹的?
请记住 Python 中的函数是对象,因此您想检查对象的纯度...
举个例子:
def foo(x):
ret, foo.x = x*x+foo.x, foo.x+1
return ret
foo.x=0
重复调用 foo(3)
得到:
>>> foo(3)
9
>>> foo(3)
10
>>> foo(3)
11
...
此外,读取全局变量不需要使用 global
语句或函数中的 global()
内置函数。全局变量可能会在其他地方发生变化,从而影响函数的纯度。
上述所有情况在运行时可能很难检测到。
我有点明白你是从哪里来的,但我认为这行不通。举个简单的例子:
def add(a,b):
return a + b
所以这对您来说可能看起来 "pure"。但是在 Python 中,+
是一个可以做任何事情的任意函数,仅取决于调用时有效的绑定。所以 a + b
可以有任意的副作用。
但比这更糟。即使这只是在做标准整数 +
,还有更多 'impure' 事情在进行。
+
正在创建一个新对象。现在,如果您确定只有调用者拥有对该新对象的引用,那么在某种意义上您可以将其视为纯函数。但是你不能确定,在那个对象的创建过程中,没有泄漏对它的引用。
例如:
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)
这将表明所谓的纯 add 函数实际上已经改变了 RegisteredNumber
class 的状态。这不是一个愚蠢的例子:在我的生产代码库中,我们有 classes 跟踪每个创建的实例,例如,允许通过密钥访问。
纯洁的概念在 Python 中没有多大意义。