如何写一个更好的Python函数?(下)

简介: Python虽然好用,但用好真的很难。 尤其是函数部分,只要写不好,后面的一连串人都会遭殃。 看又看不懂,测试起来也麻烦,维护又维护不动,真是让人头疼。 那怎么写好一个Python函数呢?

函数长度


让你读一个200行的函数,并说出它是做什么的,你是什么感受?

函数的长度直接影响可读性,从而影响可维护性。所以要保持你的函数简短。50行是一个随意的数字,在我看来是合理的。你编写的大多数函数应该要短一些。

如果一个函数遵循单一功能原则,它很可能是相当短的。如果它是纯函数或是幂等的(下面讨论) ,它也可能是短的。

那么,如果函数太长,应该怎么做?重构。这会改变程序的结构而不改变其行为。

从一个长函数中提取几行代码,并把它们变成自己的函数。这是缩短长函数的最快、也是最常见的方式。

加上你给所有这些新函数取了合适的名称,因此生成的代码读起来也会更容易。


幂等和函数纯度

不管被调用了多少次,幂等函数总是在给定相同参数集的情况下返回相同的值。

结果不依赖于非局部变量、参数的可变性或来自任何I / O流的数据。下面的这个add_three(number)函数是幂等函数:

def add_three(number):
    """Return *number* + 3."""
    return number + 3

不管一个人调用add_three(7)多少次,答案总是10。以下是一个非幂等函数:

defadd_three():

   """Return 3 + the number entered by the user."""

   number = int(input('Enter a number: '))

   return number + 3

这个函数的返回值取决于I / O,即用户输入的数字。对add_three()的每次调用都会返回不同的值。

如果它被调用两次,用户可以第一次输入3,第二次输入7,分别调用add_three()返回6和10。

幂等性的一个现实中例子是在电梯前点击“向上”按钮。第一次按时,电梯会被“通知”你要上去。因为按按钮是幂等的,所以反复按它都没有什么影响。结果是一样的。


为什么幂等很重要?


可维护性和可维护性。幂等函数很容易测试,因为在使用相同的参数时,它们总是返回相同的结果。

测试仅仅是检查通过不同调用返回值的预期值。更重要的是,这些测试很快,这是单元测试中一个重要且经常被忽视的问题。

而在处理幂等函数时,重构是轻而易举的事情。无论如何在函数之外更改代码,使用相同的参数调用它的结果总是一样的。


什么是纯函数?

在函数编程中,如果一个函数既幂等又没有可观察到的副作用,它就被认为是纯函数。函数外部的任何东西都不会影响这个值。

然而,这并不意味着函数不能影响非局部变量或I / O流之类的事情。例如,如果上面add_three(number)的幂等版本在返回结果之前打印了结果,那么它仍然被认为是幂等的,因为当它访问I / O流时,这个访问与从函数返回的值无关。

调用print ( )只是一个副作用:除了返回值之外,还与程序的其他部分或系统本身进行了一些交互。

让我们把我们的add_three(number)示例再向前推进一步。我们可以编写下面的代码片段来确定调用add_three(number)的次数:

add_three_calls = 0

defadd_three(number):

   """Return *number* + 3."""

   global add_three_calls

   print(f'Returning {number + 3}')

   add_three_calls += 1

   return number + 3

defnum_calls():

   """Return the number of times *add_three* was called."""

   return add_three_calls

我们现在正在打印到控制台(一个副作用)并修改一个非局部变量(另一个副作用),但是由于这两者都不影响函数返回的值,它仍然是幂等的。

纯函数没有副作用。它不仅不使用任何“外部数据”来计算值,除了计算和返回所述值之外,它与系统/程序的其余部分都没有交互。因此,虽然我们新的add_three(number)定义仍然是幂等的,但它不再是纯的。

纯函数没有日志语句或print ( )调用。它们不使用数据库或互联网连接。它们不访问或修改非局部变量。它们不调用任何其他非纯函数。

简而言之,它们无法做到爱因斯坦所说的“远距离幽灵般的行动”(在计算机科学环境中)。它们不会以任何方式修改程序或系统的其余部分。

在命令式编程(编写Python代码时所做的那种)中,它们是所有函数中最安全的函数。

它们也很容易被测试和维护,甚至比只是幂等函数更重要的是,测试它们基本上可以和执行它们一样快。

测试本身很简单:没有数据库连接或其他外部资源进行模拟,也不需要安装代码,之后也没有什么需要清理的。

明确地说,幂等性和纯函数只是一种期望,不是必需的。也就是说,由于好处很多,我们可能会希望只编写纯函数或幂等函数,但这不现实。

重要的是,我们要有意识开始写代码来隔离副作用和外部依赖性。这会使得我们编写的每一行代码都更容易被测试。

相关文章
|
1月前
|
Python
【python从入门到精通】-- 第五战:函数大总结
【python从入门到精通】-- 第五战:函数大总结
66 0
|
30天前
|
Python
Python之函数详解
【10月更文挑战第12天】
Python之函数详解
|
1月前
|
存储 数据安全/隐私保护 索引
|
20天前
|
测试技术 数据安全/隐私保护 Python
探索Python中的装饰器:简化和增强你的函数
【10月更文挑战第24天】在Python编程的海洋中,装饰器是那把可以令你的代码更简洁、更强大的魔法棒。它们不仅能够扩展函数的功能,还能保持代码的整洁性。本文将带你深入了解装饰器的概念、实现方式以及如何通过它们来提升你的代码质量。让我们一起揭开装饰器的神秘面纱,学习如何用它们来打造更加优雅和高效的代码。
|
22天前
|
弹性计算 安全 数据处理
Python高手秘籍:列表推导式与Lambda函数的高效应用
列表推导式和Lambda函数是Python中强大的工具。列表推导式允许在一行代码中生成新列表,而Lambda函数则是用于简单操作的匿名函数。通过示例展示了如何使用这些工具进行数据处理和功能实现,包括生成偶数平方、展平二维列表、按长度排序单词等。这些工具在Python编程中具有高度的灵活性和实用性。
|
25天前
|
Python
python的时间操作time-函数介绍
【10月更文挑战第19天】 python模块time的函数使用介绍和使用。
27 4
|
26天前
|
存储 Python
[oeasy]python038_ range函数_大小写字母的起止范围_start_stop
本文介绍了Python中`range`函数的使用方法及其在生成大小写字母序号范围时的应用。通过示例展示了如何利用`range`和`for`循环输出指定范围内的数字,重点讲解了小写和大写字母对应的ASCII码值范围,并解释了`range`函数的参数(start, stop)以及为何不包括stop值的原因。最后,文章留下了关于为何`range`不包含stop值的问题,留待下一次讨论。
19 1
|
1月前
|
索引 Python
Python中的其他内置函数有哪些
【10月更文挑战第12天】Python中的其他内置函数有哪些
15 1
|
26天前
|
安全 数据处理 数据安全/隐私保护
python中mod函数怎么用
通过这些实例,我们不仅掌握了Python中 `%`运算符的基础用法,还领略了它在解决实际问题中的灵活性和实用性。在诸如云计算服务提供商的技术栈中,类似的数学运算逻辑常被应用于数据处理、安全加密等关键领域,凸显了基础运算符在复杂系统中的不可或缺性。
18 0
|
1月前
|
开发者 索引 Python
Python中有哪些内置函数
【10月更文挑战第12天】Python中有哪些内置函数
18 0