前面几期内容连续的介绍了Python的函数相关编程知识,是一个相对且完整的知识域,本文主要是对函数知识的一些有益拓展和补充。
本文简单扼要地说,辅以代码进一步地加深理解。我们继续——记得点赞+关注@传新视界
当函数调用自身而生成最终结果时,这样的函数称为递归。有时递归函数非常有用,因为它们使编写代码变得更容易——使用递归范式编写一些算法非常容易,而其他算法则不是这样。没有不能以迭代方式重写的递归函数,换句话说,所有递归函数都可以通过循环迭代的方式实现,因此通常由程序员根据手头的情况选择最佳方法。
递归函数主体通常有两个部分:一部分的返回值依赖于对自身的后续调用,另一部分的返回值不依赖于对自身的后续调用(称基本情况,或递归边界)。
作为理解的参考示例,我们看一个阶乘函数N!作为递归的两部分分别是:基本情况(边界,用来结束递归)是当N为0或1时,函数返回1,不需要进一步计算。另一方面,在一般情况下的自我调用,即N!返回的生成结果:
1 * 2 * ... * (N-1) * N
如果你仔细想想,N!可以写成这样:N!= (N - 1) !*N。作为一个实际的例子,请看如下的阶乘表示:
5! = 1 * 2 * 3 * 4 * 5 = (1 * 2 * 3 * 4) * 5 = 4! * 5
我们来转化成函数实现:
# 阶乘递归函数实现
def factorial(n):
if n in (0, 1): # 递归边界
return 1
return factorial(n - 1) * n # 递归调用
高手大侠们在编写算法时经常使用递归函数,编写递归函数非常有趣。作为练习,尝试使用递归和迭代方法解决几个简单的问题。很好的练习对象可能是计算斐波那契数列,或其它诸如此类的东西。自己动手去试试吧。
提示: 在编写递归函数时,总是考虑要进行多少个嵌套调用,因为这是有限制的。有关这方面的更多信息,请查看sys.getrecursionlimit()和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数据模型文档页面(或自带帮助文档中)的可调用类型部分找到:
https://docs.python.org/3/reference/datamodel.html#the-standard-typehierarchy
再次提醒:如果你想查看对象的所有属性,只需调用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的文档指南:
https://www.python.org/dev/peps/pep-0257/,
但在这里还是会向你展示基本原理。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函数(简洁性和临时性)以及函数的属性以及如何实现函数的文档化描述等。
本文就写这些了,记得点赞 +关注@传新视界,转发分享给更多的朋友。再见^_^
上一篇
已是最后文章