如何写一个更好的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代码时所做的那种)中,它们是所有函数中最安全的函数。

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

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

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

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

相关文章
|
24天前
|
搜索推荐 Python
利用Python内置函数实现的冒泡排序算法
在上述代码中,`bubble_sort` 函数接受一个列表 `arr` 作为输入。通过两层循环,外层循环控制排序的轮数,内层循环用于比较相邻的元素并进行交换。如果前一个元素大于后一个元素,就将它们交换位置。
125 67
|
18天前
|
Python
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
42 18
|
9天前
|
数据可视化 DataX Python
Seaborn 教程-绘图函数
Seaborn 教程-绘图函数
40 8
|
19天前
|
Python
Python中的函数
Python中的函数
31 8
|
25天前
|
监控 测试技术 数据库
Python中的装饰器:解锁函数增强的魔法####
本文深入探讨了Python语言中一个既强大又灵活的特性——装饰器(Decorator),它以一种优雅的方式实现了函数功能的扩展与增强。不同于传统的代码复用机制,装饰器通过高阶函数的形式,为开发者提供了在不修改原函数源代码的前提下,动态添加新功能的能力。我们将从装饰器的基本概念入手,逐步解析其工作原理,并通过一系列实例展示如何利用装饰器进行日志记录、性能测试、事务处理等常见任务,最终揭示装饰器在提升代码可读性、维护性和功能性方面的独特价值。 ####
|
1月前
|
Python
Python中的`range`函数与负增长
在Python中,`range`函数用于生成整数序列,支持正向和负向增长。本文详细介绍了如何使用`range`生成负增长的整数序列,并提供了多个实际应用示例,如反向遍历列表、生成倒计时和计算递减等差数列的和。通过这些示例,读者可以更好地掌握`range`函数的使用方法。
49 5
|
1月前
|
测试技术 数据安全/隐私保护 Python
探索Python中的装饰器:简化和增强你的函数
【10月更文挑战第24天】在Python编程的海洋中,装饰器是那把可以令你的代码更简洁、更强大的魔法棒。它们不仅能够扩展函数的功能,还能保持代码的整洁性。本文将带你深入了解装饰器的概念、实现方式以及如何通过它们来提升你的代码质量。让我们一起揭开装饰器的神秘面纱,学习如何用它们来打造更加优雅和高效的代码。
|
1月前
|
弹性计算 安全 数据处理
Python高手秘籍:列表推导式与Lambda函数的高效应用
列表推导式和Lambda函数是Python中强大的工具。列表推导式允许在一行代码中生成新列表,而Lambda函数则是用于简单操作的匿名函数。通过示例展示了如何使用这些工具进行数据处理和功能实现,包括生成偶数平方、展平二维列表、按长度排序单词等。这些工具在Python编程中具有高度的灵活性和实用性。
36 2
|
2月前
|
Python
python的时间操作time-函数介绍
【10月更文挑战第19天】 python模块time的函数使用介绍和使用。
38 4
|
1月前
|
中间件 Docker Python
【Azure Function】FTP上传了Python Function文件后,无法在门户页面加载函数的问题
通过FTP上传Python Function至Azure云后,出现函数列表无法加载的问题。经排查,发现是由于`requirements.txt`中的依赖包未被正确安装。解决方法为:在本地安装依赖包到`.python_packages/lib/site-packages`目录,再将该目录内容上传至云上的`wwwroot`目录,并重启应用。最终成功加载函数列表。

热门文章

最新文章