This article is briefly stated, supplemented by code to further deepen understanding.
When a function calls itself to generate the final result, such a function is called recursive. Sometimes recursive functions are useful because they make writing code easier - some algorithms are very easy to write using the recursive paradigm, while others are not. There is no recursive function that cannot be rewritten in an iterative way, in other words, all recursive functions can be implemented iteratively through a loop, so it is usually up to the programmer to choose the best approach based on the situation at hand.
The body of a recursive function usually has two parts: one part's return value depends on subsequent calls to itself, and the other part's return value does not depend on subsequent calls to itself (called the base case, or recursion boundary).
As a reference example for understanding, let’s look at a factorial function N! As the two parts of the recursion are: the basic case (boundary, used to end the recursion) is that when N is 0 or 1, the function returns 1, No further calculations are required. On the other hand, in the general case of self-invocation, the generated result returned by N! is:
1 * 2 * ... * (N-1) * N
If you think about it carefully, N! can be written like this: N!= (N - 1) !*N . As a practical example, please look at the following factorial representation:
5! = 1 * 2 * 3 * 4 * 5 = (1 * 2 * 3 * 4) * 5 = 4! * 5
Let’s convert it into a function implementation:
# 阶乘递归函数实现 def factorial(n): if n in (0, 1): # 递归边界 return 1 return factorial(n - 1) * n # 递归调用
Masters and heroes often use it when writing algorithms Recursive functions, writing recursive functions is a lot of fun. As an exercise, try solving a few simple problems using recursive and iterative methods. A good practice might be calculating Fibonacci numbers, or something like that. Try it yourself.
Tip: When writing recursive functions, always consider how many nestings you want to make Called because there is a limit. For more information on this, check out sys.getrecursionlimit() and sys.setrecursionlimit(). |
还有一种函数是匿名函数(Anonymous functions)。这些函数在Python中称为lambda(兰姆达),其通常在使用具有自己完整定义名称的函数有些多余时而使用,此时所需要的只是一个快速、简单的一行程序来完成这项工作。
假设我们想要一个列表,所有N的某个值,是5的倍数的数字。为此,我们可以使用filter()函数,它需要一个函数和一个可迭代对象作为输入。返回值是一个过滤器对象,当你遍历它时,会从输入可迭代对象中生成元素,所需的参数函数会为其返回True。如果不使用匿名函数,我们可能会这样做:
def isMultipleOfFive(n): return not n % 5 def getMultiplesOfFive(n): return list(filter(isMultipleOfFive, range(n)))
注意我们如何使用isMultipleOfFive()来过滤前n个自然数。这似乎有点过分——任务及其很简单,我们不需要为其他任何事情保留isMultipleOfFive()函数。此时,我们就可用lambda函数来重写它:
# lambda过滤 def getMultiplesOfFive(n): return list(filter(lambda k: not k % 5, range(n)))
逻辑是完全相同的,但是过滤函数现在是个lambda函数,显然,Lambda更简单。
定义Lambda函数非常简单,它遵循以下形式:
funcName = lambda [parameter_list]: expression
其返回的是一个函数对象,相当于:
def func_ name([parameter_list]):return expression
参数列表以逗号分隔。
注意,可选参数是方括号括起来的部分,是通用语法的表示形式,即文中的方括号部分是可选的,根据实际需要提供,
我们再来看另外两个等价函数的例子,以两种形式定义:
# lambda说明 # 示例 1: 两数相加 def adder(a, b): return a + b # 等价于: adder_lambda = lambda a, b: a + b # 示例 2: 字符串转大写 def to_upper(s): return s.upper() # 等价于: to_upper_lambda = lambda s: s.upper()
前面的例子非常简单。第一个函数将两个数字相加,第二个函数生成字符串的大写版本。注意,我们将lambda表达式返回的内容赋值给一个名称(adder_lambda, to_upper_lambda),但是当按照filter()示例中的方式使用lambda时,就不需要这样做了——不需要把匿名函数赋给变量。
Python中每个函数都是一个完整的对。因此,它有许多属性。其中一些是特殊的,可以以内省的方式在运行时检查函数对象。下面的示例,展示了它们的一部分以及如何为示例函数显示它们的值:
# 函数属性 def multiplication(a, b=1): """返回a乘以b的结构. """ return a * b if __name__ == "__main__": special_attributes = [ "__doc__", "__name__", "__qualname__", "__module__", "__defaults__", "__code__", "__globals__", "__dict__", "__closure__", "__annotations__", "__kwdefaults__", ] for attribute in special_attributes: print(attribute, '->', getattr(multiplication, attribute))
我们使用内置的getattr()函数来获取这些属性的值。getattr(obj, attribute)等价于obj.attribute,当我们需要在运行时动态地获取属性时,就从变量中获取属性的名称(如本例中所示),此时它就会派上用场。
运行这个脚本会得到类似如下输出:
__doc__ -> 返回a乘以b的结果. __name__ -> multiplication __qualname__ -> multiplication __module__ -> __main__ __defaults__ -> (1,) __code__ -> <……> __globals__ -> {…略…} __dict__ -> {} __closure__ -> None __annotations__ -> {} __kwdefaults__ -> None |
这里省略了__globals__属性的值,内容太多。这个属性的含义可以在Python数据模型文档页面(或自带帮助文档中)的可调用类型部分找到:
//m.sbmmt.com/link/032abcd424b4312e7087f434ef1c0094
再次提醒:如果你想查看对象的所有属性,只需调用dir(object_name),将得到其所有属性的列表。
Python自带很多内置函数。它们可以在任何地方使用,你可以通过dir(__builtins__)来查看builtins模块,或通过访问官方Python文档来获得它们的列表。这里就不一一介绍了。在前面的学习过程中,我们已经见过其中的一些,如any、bin、bool、divmod、filter、float、getattr、id、int、len、list、min、print、set、tuple、type和zip等,但还有更多,建议你至少应该阅读一次。熟悉它们,尝试它们,为它们每个编写一小段代码,并确保您随时可以使用它们,以便在需要时使用它们。
可在官方文档中找到这个内置函数列表:https://docs.python.org/3/library/functions.html 。
我们非常喜欢不需要文档的代码。当我们正确地编程、选择正确的名称、并注意细节时,代码应该是不言自明的,几乎不需要文档。不过,有时注释非常有用,添加一些文档化描述也是如此。你可以在Python的PEP 257规范——文档字符串约定中找到Python的文档指南:
//m.sbmmt.com/link/da40657c9fece7e48d30af42d31d4350
但在这里还是会向你展示基本原理。Python的文档中包含字符串,这些字符串被恰当地称为文档字符串(docstrings)。任何对象都可以被文档化来加以描述记录,可以使用单行或多行文档字符串。单行程序非常简单。不是为函数提供另外的签名,而应该声明或描述函数的目的。请看下面的示例:
# 简单的文档化代码 def square(n): """功能:返回数字n的平方。 """ return n ** 2 def get_username(userid): """功能:返回给定id的用户名称。 """ return db.get(user_id=userid).username
使用三重双引号字符串可以在以后轻松展开或扩展文档内容。
使用以句号结尾的句子,不要在前后留下空行。
多行注释的结构与此类似。应该用一行代码简单地说明对象的主旨,然后是更详细的描述。
作为多行文档化的一个例子,我们在下面的例子中使用Sphinx表示法记录了一个虚构的connect()函数及文档化描述:
# 多行文档化代码 def connect(host, port, user, password): """功能:连接数据库并返回连接对象. 使用如下参数直接连接 PostgreSQL数据库. :param host: 主机 IP. :param port: 端口. :param user: 连接用户名. :param password: 连接密码. :return: 连接对象. """ # 函数主体... return connection
提示:
Sphinx是用于创建Python文档的最广泛使用的工具之一——事实上,官方Python文档就是用它编写的。绝对值得花点时间去看看。
内置函数help()用于即时交互使用的,它就使用对象的文档字符串为对象创建文档页面来展示对象的用法。基本用法如下:
def square(n): """功能:返回数字n的平方。 """ return n ** 2 help(square) Help on function square in module __main__: square(n) 功能:返回数字n的平方。
首先明确或定义一个对象或函数(包括已有的对象或函数),然后使用内置help函数,并把对象或函数做help的参数,该函数就会返回相应对象的说明文档了。就这么简单。
本文主要基于Python语言的一大特色——函数来拓展的一些相关编程知识,包括递归函数(重点是有限性和边界性)、lambda函数(简洁性和临时性)以及函数的属性以及如何实现函数的文档化描述等。
The above is the detailed content of Python programming: recursive and anonymous functions and function attributes and documentation strings (function supplement). For more information, please follow other related articles on the PHP Chinese website!