函数的定义

函数是一段具有特定功能的、可重用的语句组,用函数名来表示并通过函数 名在需要的地方调用执行,不需要在每个执行地方重复编写这些语句。每次 使用函数可以提供不同的参数作为输入,以实现对不同数据的处理;函数执行后,还可以反馈相应的处理结果。

Python定义一个函数使用def保留字,语法形式如下:

def <函数名>([参数列表]): 
 	[’’’注释’’’]
 	 <函数体> 
 	 [return <返回值列表>]

注意事项

  • 函数形参不需要声明类型,也不需要指定函数返回值类型
  • 即使该函数不需要接收任何参数,也必须保留一对空的圆括号
  • 括号后面的冒号必不可少
  • 函数体相对于def关键字必须保持一定的空格缩进
  • Python允许嵌套定义函数

例:斐波那契数列

def fib(n): 
	a, b=0, 1 
	while a<n: 
		print(a, end='   ')
		a, b=b, a+b
	print("\nend!")

函数的参数

  • 在Python中,函数参数的方式可分为四种:普通参数、默认参数,关键 参数、可变长度参数。
  • Python在定义函数时不需要指定形参的类型,完全由调用者传递的实参 类型以及Python解释器的理解和推断来决定。
  • Python函数定义时,也不需要指定函数的类型,而由函数中的return语 句来决定,如果没有return语句,或者return语句没有执行,则返回空值None
  • Python支持对函数参数和返回值类型的标注,但不强制限制。

位置参数

位置参数是比较常用的形式,调用函数时,实参和形参的顺序及数量 都必须完全相同

默认值参数

在调用带有默认值参数的函数时,可以不用为设置了默认值的形参进行 传值,此时函数将会直接使用函数定义时设置的默认值,也可以通过显式 赋值来替换其默认值。

关键参数

  • 关键参数主要指实参,即调用函数时的参数传递方式。
  • 通过关键参数,实参顺序可以和形参顺序不一致,但不影响传递结果, 避免了用户需要牢记位置参数的顺序的麻烦。

可变长度参数

可变长度参数主要有两种形式:

  • *parameter用来接受任意多个实参并将其放在一个元组中;
  • **parameter接受类似于关键参数一样显式赋值形式的多个实参,并将其放 入字典中。

参数传递的序列解包

  • 传递参数时,可通过在实参序列对象前加一个星号将其解包,然后传递 给多个单变量形参。
  • 调用函数时如果对实参使用一个星号*进行序列解包,那么这些解包后 的实参将会被当做普通位置参数对待,并会在关键参数和使用两个星号 **进行序列解包的参数之前进行处理。

Return语句

  • Return语句用来从一个函数中返回一个值,同时结束函数运行。
  • 如果函数没有return语句,或者有return语句但没有执行,或者有return而没有返回值,Python均认为该函数以return None结束。

lambda函数

lambda表达式只可以包含一个表达式,该表达式的计算结果可以看作是函 数的返回值,不允许包含复合语句,但在表达式中可以调用其他函数。

代码的复用和模块化设计

函数是程序的一种基本抽象方式,它将一系列代码组织起来通过命名供其他程序使用。 函数封装的直接好处是代码复用,任何其他代码只要输入参数即可调用函数,从而避免相同 功能代码在被调用处重复编写。代码复用产生了另一个好处,当更新函数功能时,所有被调 用处的功能都被更新。
当程序的长度在百行以上,如果不划分模块就算是最好的程序员也很难理解程序含义程 序的可读性就已经很糟糕了。解决这一问题的最好方法是将一个程序分割成短小的程序段, 每一段程序完成一个小的功能。无论面向过程和面向对象编程,对程序合理划分功能模块并 基于模块设计程序是一种常用方法,被称为“模块化设计”。
模块化设计一般有两个基本要求:

  • 紧耦合:尽可能合理划分功能块,功能块内部耦合紧密;
  • 松耦合:模块间关系尽可能简单,功能块之间耦合度低。

使用函数只是模块化设计的必要非充分条件,根据计算需求合理划分函数 十分重要。一般来说,完成特定功能或被经常复用的一组语句应该采用函数来 封装,并尽可能减少函数间参数和返回值的数量。

函数的递归

函数作为一种代码封装,可以被其他程序调用,当然,也可以被函数内部代码调用。 这种函数定义中调用函数自身的方式称为递归。就像一个人站在装满镜子的房间中,看到 的影像就是递归的结果。递归在数学和计算机应用上非常强大,能够非常简洁的解决重要 问题。
例:阶乘

n! = n(n-1)(n-2)...(1)

递归的2个关键特征:

  1. 存在一个或多个基例,基例不需要再次递归,它是确定的表达式。
  2. 递归链要以一个或多个基例结尾。