递归与匿名函数及函数属性与文档字符串

上一篇 / 下一篇  2022-11-11 13:32:48

  有一份51Testing测试行业调查问卷需要您的助力,差不多三分钟的时间即可填完。我们给您准备了一份价值398元的测试课程作为礼品,感谢您的帮忙~链接:http://vote.51testing.com/

  递归函数
  当函数调用自身而生成最终结果时,这样的函数称为递归。有时递归函数非常有用,因为它们使编写代码变得更容易——使用递归范式编写一些算法非常容易,而其他算法则不是这样。没有不能以迭代方式重写的递归函数,换句话说,所有递归函数都可以通过循环迭代的方式实现,因此通常由程序员根据手头的情况选择最佳方法。
  递归函数主体通常有两个部分:一部分的返回值依赖于对自身的后续调用,另一部分的返回值不依赖于对自身的后续调用(称基本情况,或递归边界)。
  作为理解的参考示例,我们看一个阶乘函数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
  再次提醒:如果你想查看对象的所有属性,只需调用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的文档中包含字符串,这些字符串被恰当地称为文档字符串(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函数(简洁性和临时性)以及函数的属性以及如何实现函数的文档化描述等。

TAG: 软件开发 Python

 

评分:0

我来说两句

Open Toolbar