瞧瞧,这样的「函数」才叫 Pythonic( 三 )


幂等性和函数纯度
幂等函数(idempotent function)在给定相同变量参数集时会返回相同的值 , 无论它被调用多少次 。 函数的结果不依赖于非局部变量、参数的易变性或来自任何 I/O 流的数据 。 以下的 add_three(number) 函数是幂等的:
def add_three(number): """Return *number* + 3.""" return number + 3无论何时调用 add_three(7) , 其返回值都是 10 。 以下展示了非幂等的函数示例:
def add_three(): """Return 3 + the number entered by the user.""" number = int(input('Enter a number: ')) return number + 3这函数不是幂等的 , 因为函数的返回值依赖于 I/O , 即用户输入的数字 。 每次调用这个函数时 , 它都可能返回不同的值 。 如果它被调用两次 , 则用户可以第一次输入 3 , 第二次输入 7 , 使得对 add_three() 的调用分别返回 6 和 10 。
为什么幂等很重要?
可测试性和可维护性 。 幂等函数易于测试 , 因为它们在使用相同参数的情况下会返回同样的结果 。 测试就是检查对函数的不同调用所返回的值是否符合预期 。 此外 , 对幂等函数的测试很快 , 这在单元测试(Unit Testing)中非常重要 , 但经常被忽视 。 重构幂等函数也很简单 。 不管你如何改变函数以外的代码 , 使用同样的参数调用函数所返回的值都是一样的 。
什么是「纯」函数?
在函数编程中 , 如果函数是幂等函数且没有明显的副作用(side effect) , 则它就是纯函数 。 记住 , 幂等函数表示在给定参数集的情况下该函数总是返回相同的结果 , 不能使用任何外部因素来计算结果 。 但是 , 这并不意味着幂等函数无法影响非局部变量(non-local variable)或 I/O stream 等 。 例如 , 如果上文中 add_three(number) 的幂等版本在返回结果之前先输出了结果 , 它仍然是幂等的 , 因为它访问了 I/O stream , 这不会影响函数的返回值 。 调用 print() 是副作用:除返回值以外 , 与程序或系统中其余部分的交互 。
我们来扩展一下 add_three(number) 这个例子 。 我们可以用以下代码片段来查看 add_three(number) 函数被调用的次数:
add_three_calls = 0def add_three(number): """Return *number* + 3.""" global add_three_calls print(f'Returning {number + 3}') add_three_calls += 1 return number + 3def num_calls(): """Return the number of times *add_three* was called.""" return add_three_calls现在我们向控制台输出结果(一项副作用) , 并修改了非局部变量(又一项副作用) , 但是由于这些副作用不影响函数的返回值 , 因此该函数仍然是幂等的 。
纯函数没有副作用 。 它不仅不使用任何「外来数据」来计算值 , 也不与系统/程序的其它部分进行交互 , 除了计算和返回值 。 因此 , 尽管我们新定义的 add_three(number) 仍是幂等函数 , 但它不再是纯函数 。
纯函数不记录语句或 print() 调用 , 不使用数据库或互联网连接 , 不访问或修改非局部变量 。 它们不调用任何其它的非纯函数 。
总之 , 纯函数无法(在计算机科学背景中)做到爱因斯坦所说的「幽灵般的远距效应」(spooky action at a distance) 。 它们不以任何形式修改程序或系统的其余部分 。 在命令式编程中(写 Python 代码就是命令式编程) , 它们是最安全的函数 。 它们非常好测试和维护 , 甚至在这方面优于纯粹的幂等函数 。 测试纯函数的速度与执行速度几乎一样快 。 而且测试很简单:没有数据库连接或其它外部资源 , 不要求设置代码 , 测试结束后也不需要清理什么 。
显然 , 幂等和纯函数是锦上添花 , 但并非必需 。 即 , 由于上述优点 , 我们喜欢写纯函数或幂等函数 , 但并不是所有时候都可以写出它们 。 关键在于 , 我们本能地在开始部署代码的时候就想着剔除副作用和外部依赖 。 这使得我们所写的每一行代码都更容易测试 , 即使并没有写纯函数或幂等函数 。
总结
写出好的函数的奥秘不再是秘密 。 只需按照一些完备的最佳实践和经验法则 。 希望本期教程能够帮助到大家 。
2020版Python教程_完全入门_学完达到Python工程师水平
网盘链接:
Python入门视频全套全开源
网盘链接:
【瞧瞧,这样的「函数」才叫 Pythonic】900多集 , 大家可以按需学习 , 小白就从头学起!不清楚的地方 , 可以给我留言!
瞧瞧,这样的「函数」才叫 Pythonic文章插图