函数与参数
函数是一种代码的组织形式,将特定的功能封装成函数,有利于代码复用、提高代码可读性。
在 Python 中定义一个函数有如下规则:
- 函数代码块以
def
关键词开头,后接函数标识符名称和圆括号(无参数也要加上圆括号);- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数,参数之间用逗号隔开;
- 函数的第一行语句可以选择性地使用文档字符串(用于存放函数说明);
- 函数内容以冒号(
:
)起始,并且缩进;return [表达式]
结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回None
;- 函数名的命名规则和变量一样。
总体来说,函数的定义有如下几种格式:
(1)基本函数格式
def func_name():
函数功能代码…
函数功能代码…
…
调用函数:func_name()
特征:函数定义之后不会自动执行,必须在调用函数之后才会执行。
(2)带有参数的函数格式
def func_name(参数, 参数, ...):
函数功能代码…
函数功能代码…
…
调用函数:func_name(参数, 参数, ...)
注意:实参将只传递给形参的过程本质上就是简单的变量赋值仅此而已。在此情况下,参数必须以正确的顺序传入函数,调用时的数量必须与声明时一样。
(3)带有默认值的参数
def func_name(形参=默认值, 形参=默认值 ...):
函数功能代码…
函数功能代码…
…
调用函数:
func_name()
调用函数时所有形参采用默认值操作func_name(实参, 实参 ...)
调用时形参使用实参的值而抛弃默认值
注意:在此情况下使用实参值覆盖原有形参的默认值,本质上就是变量的重新赋值操作。调用函数时,如果没有传递参数,则会使用默认参数。
(4)关键字参数
def func_name(形参=默认值, 形参=默认值 ...):
函数功能代码…
函数功能代码…
…
调用函数:func_name(形参=实参, 形参=实参 ...)
特征:
- 关键字参数就是调用函数时,在实参前面指定形参的做法,可以防止参数按照位置传递出现的错误;
- 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值;
- 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
(5)收集参数/变长参数(带 *)
(5.1)非关键字收集参数/元组(Tuple)变长参数
def func_name(*参数名):
函数功能代码…
函数功能代码…
…
调用函数:func_name(实参, 实参 …)
参数数量没有限制
特征:
- 非关键字收集参数,在形参前添加一个
*
即可;- 非关键字收集参数收集实参组成一个元组;
- 非关键字收集参数,仅收集没有任何形参接受的非关键字实参;
- 非关键字收集参数和普通的形参可以共存。
(5.2)关键字收集参数/字典(Dictionary)变长参数
def func_name(**参数名):
函数功能代码…
函数功能代码…
…
调用函数:func_name(形参=实参, 形参=实参 …)
参数数量没有限制
特征:
- 关键字收集参数,在形参前添加两个
**
即可;- 关键字收集参数,收集的结果组成一个
字典
,关键字(形参)成为字典的键,实参成为值;- 关键字收集参数,仅收集没有任何形参接受的关键字参数;
- 关键字参数可以和普通的形参共存;
(6)多种参数混合
总结一下,函数中参数定义有这几种格式:普通参数、关键字参数、非关键字收集参数、关键字收集参数。
虽然 Python 支持多种参数格式混合,但是程序员在定义函数时,应尽量避免多种参数格式混合。
如果必须使用多种参数格式,那么需要遵循如下规则:
- 普通参数和关键字参数必须在两种收集参数之前;
- 非关键字收集参数,必须在关键字收集参数之前;
- 如果多种参数在一起,必须注意禁止参数多次赋值操作(相同“赋值”赋值之后,关键字参数在此赋值)。
函数返回值
根据函数执行完毕后是否得到一个结果,我们将函数分为两种类型:
- 执行过程函数,如 print()
- 具有返回值的函数,如 id()、type()
特性:
- 具有 return 语句的函数称为具有返回值的函数;
- return 可以为当前函数执行完毕返回一个结果,这样的函数调用是可以被赋值运算符左边的变量接收;
- return 执行之后,函数则会终止,所有 return 之后的语句都不会被执行;
- 一个函数可以书写多个 return 语句,但是一般会处于不同的分支结构中;
- 一个函数如果要返回多个数据,可以借助复合数据类型(list、tuple、set 和 dict)来实现;
- 不带参数值的 return 语句返回 None,如果没有显式的 return 语句,函数执行完毕返回的也是 None。
函数文档
前面我们说过“函数的第一行语句可以选择性地使用文档字符串(用于存放函数说明)”。
举个栗子:
def say_hello(somebody):
"""
It will print a hello string to 'somebody'
"""
print("Hello, %s" %(somebody))
然后我们执行 help(say_hello)
查看函数文档,可以看到如下内容:
Help on function say_hello in module __main__:
say_hello(somebody)
It will print a hello string to 'somebody'
通过这个例子,我们知道,函数文档其实就是用来查看当前函数相关信息介绍的一个特定格式。它的格式很简单,就是在函数的第一行中使用 '''
或者 """
将对该函数的说明包含进来。
使用函数文档有利于用户阅读和快速掌握函数的使用,通常函数文档需要具备以下信息:
- 函数的作用
- 函数的参数介绍(个数,数据类型)
- 函数的返回值(数据和类型)
查看函数文档有以下两种方法:
help(函数名称)
直接输出显示函数文档的内容字符串函数名.__doc__
直接输出显示函数文档的内容元字符串(转义字符不转义)
匿名函数
匿名函数使用关键字 lambda
来定义,而不再使用 def
语句这样标准的形式定义一个函数。
举个栗子:
def add(v1, v2):
return v1+v2
sum = lambda v1,v2:v1+v2
print("type(add)", type(add))
print(add(10, 20))
print("type(sum)", type(sum))
print(sum(10, 20))
输出结果如下:
type(add) <class 'function'>
30
type(sum) <class 'function'>
30
可以看到,lambda 只是一个表达式,函数体比 def 简单得多。
匿名函数的定义简单,有如下一些特性与限制:
- 语法:lambda 函数的语法只包含一个语句,如:
lambda [arg1 [,arg2, …, argn]]:expression
- lambda 主体是一个表达式,而不是代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去;
- lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数;
- 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率;
变量作用域
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问(当然,全局变量需要在被调用之前加载好)。
调用函数时,所有在函数内声明的变量名称都将被加入到作用域。函数内定义的变量在函数外部是拿不到的,除非通过 return 的方式将变量返回。
如果想在函数内使用全局变量,需要使用关键字 global
进行声明。global 不是声明变量类型,而是声明命名空间也就是作用域。