如何判断(或如何编写)没有副作用的python函数?

tcp*_*per 8 python functional-programming

答案等于的定义side effects.

到目前为止,我还没有找到准确的答案.python doc说: Functional style discourages functions with side effects that modify internal state or make other changes that aren’t visible in the function’s return value.

什么是modify internal statemake other changes that aren’t visible...

绑定变量到对象(只是绑定,而不是修改)意味着没有副作用?例如a=1a=[1,2,3]a,b=1,2.

这里有4个功能.它们都没有副作用吗?为什么?

注意,假设参数n必须是一个int对象.

def purefunc1(n):
    def getn(n):
        return [1,2,3,4,5][:n-1],[1,2,3,4,5][:n]
    def addn(fir,sec,thd):
        return fir+sec+thd
    return addn(getn(n)[0],['HEY'],getn(n)[1])

def purefunc2(n):
    def getn(n):
        #bind
        arr=[1,2,3,4,5]
        return arr[:n-1],arr[:n]
    def addn(fir=[],sec=[],thd=[]):
        return fir+sec+thd
    #bind
    arg1,arg3=getn(n)
    return addn(arg1,['HEY'],arg3)

def purefunc3(n):
    arr=[1,2,3,4,5]
    def getn(n):
        #closure 'arr'
        return arr[:n-1],arr[:n]
    def addn(fir=[],sec=[],thd=[]):
        return fir+sec+thd
    #bind
    arg1,arg3=getn(n)
    return addn(arg1,['HEY'],arg3)

def purefunc4(n):
    def arr():
        return [1,2,3,4,5]
    def getn(n):
        #closure
        return arr()[:n-1],arr()[:n]
    def addn(fir=[],sec=[],thd=[]):
        return fir+sec+thd
    #bind
    arg1,arg3=getn(n)
    return addn(arg1,['HEY'],arg3)

print (purefunc1(3))
print (purefunc2(3))
print (purefunc3(3))
print (purefunc4(3))
Run Code Online (Sandbox Code Playgroud)

我的猜测:purefunc1没有副作用.但我不知道以下purefunc*.

输出是:

[1, 2, 'HEY', 1, 2, 3]
[1, 2, 'HEY', 1, 2, 3]
[1, 2, 'HEY', 1, 2, 3]
[1, 2, 'HEY', 1, 2, 3]    
Run Code Online (Sandbox Code Playgroud)

如果你问为什么存在这样奇怪的功能,答案就是为了方便起见.真正的功能很复杂.但如果您有兴趣,可以点击这里查看该功能ieval是否没有副作用.

提前谢谢所有人.

Ult*_*nct 6

Python关于函数式编程的文档中,有一个小段落.我将在下面引用(强调我的):

以函数式编写的Python程序通常不会完全避免所有I/O或所有赋值 ; 相反,它们将提供功能出现的界面,但将在内部使用非功能性功能.例如,函数的实现仍将使用局部变量的赋值,但不会修改全局变量或具有其他副作用.

换句话说,想想从外面看什么.函数是否修改了一些全局变量,类变量?它会操纵任何状态吗?如果没有,那么它的纯净.根据上面的文档,函数内部可以分配给局部变量,但重要的是函数不应该修改任何面向外部的状态.


什么是修改内部状态并进行其他不可见的更改...?

请看下面的例子.我们global_list每次调用时都在修改non_pure_add1_func(..).

global_list = []\n\ndef non_pure_add1_func(x):\n    global_list.append(x)\n    return x+1\n
Run Code Online (Sandbox Code Playgroud)

虽然,上述功能可能是幂等的,但它并不纯粹.


Luc*_*iro 5

在函数式编程的上下文中,函数是一个确定性的东西,在给定输入的情况下,输出一些东西.这就是纯粹的功能.他们只计算事物.他们不"做"事情.如果你的功能代码理论上可以通过表(甚至是无限的)来切换,那么你就有了一个没有副作用的函数.

除了返回值之外的任何东西都是副作用.术语"修改内部状态"和"进行其他不可见的更改"指的是这一点.修改内部状态或进行更改......可以表示:

  1. 打印东西
  2. 修改超出范围的对象
  3. 保存一些东西

您可以将副作用理解为"修改外部世界".在您的示例中,他们都没有这样做.但是,如果你给n分配了一些东西,比如追加某些东西,或者在函数返回后会在你的环境中存在的任何东西,那么这将是一个副作用.

您可以比较输入和输出来测试所有功能.如果你有副作用(比如变异n)你的测试会变得更复杂,你需要分析你的函数的上下文.