Python的函数
1. Python的函数
1.1 函数的定义
在Python中,函数是逻辑结构化和过程化的一种方法;是带名字的、组织好的、可重复使用的代码块,用于完成具体的任务。Python用def关键字来定义函数,然后用return关键字返回值,其语法格式如下:
def 函数名称([参数1],[参数2],…,[参数N]):
”””文档字符串”””
代码块
return [返回值]
说明:
(1)函数代码块以 def 关键字开头,然后空格加函数名称,圆括号(),以冒号(:)结尾。其中,若函数有参数,则将其放在括号中,若有多个参数,则用逗号分开。
(2)函数的内容以冒号起始,并且换行后需缩进。
(3)函数的第一行语句可以选择性地使用文档字符串,主要用于存放函数说明,描述该函数的功能。文档字符串用三引号括起来,Python使用它们来生成有关程序中函数的文档。
(4)代码块就是实现函数功能的具体的代码。
(5)以 return[返回值] 来结束函数,并返回一个值给调用方。若函数没有具体的返回值,则return会返回 None。
因此,可简单的说明,函数即由函数名称及函数体组成。其中函数体包括:文档字符串、代码块、返回值。
例如,定义一个欢迎用户登录时的问候语的函数。
代码:
1 def greet_user(): 2 """用户登录时,显示简单的问候语""" 3 print("Welcome to login!") 4 return
1.2 函数的作用
在Python中,函数的的作用主要有三点:
(1)代码重用。在程序中,可以调用已经有的函数,不用再重新写实现代码,故使得代码简洁,并能实现相同的功能。
(2)保持一致性。在程序中,可能会多处需要实现同样的功能,如果每次都写一遍实现,不仅浪费时间,使代吗臃肿,不易读,还可能没处实现的功能有差异。但调用同一个函数,若函数修改了,则其他调用的地方都跟着改变了。这样不仅具体功能实现保持了一致,还能使代码更整洁,易读。
(3)可扩展性。当我们需要让能够函数帮助我们完成更多的任务,我们只需在函数中编写实现即可。若参数有变化,则只需修改调用的地方。
(4)使用函数让程序更容易阅读。
(5)函数让代码更容易测试和调试。
1.3 参数
在Python中,参数也分为实参和形参。实参就是调用函数时,在括号中指定的具有实际值的参数;形参就是在定义函数时,在括号中指定的变量,无实际值。 其中,实参包括:位置实参、关键字实参、默认值等。
1.4 函数的调用
函数的调用很简单,即用函数名称加圆括号(),若有参数,则将其参数放在括号中,若有多个参数,则将其放到括号中,并用逗号分开。具体语法格式如下所示:
函数名称([参数1],[参数2],…,[参数N])
因此,函数调用存在两种情况,一种是无参函数调用;一种是有参函数调用。
1.4.1 无参函数的调用
例如,定义一个欢迎用户登录时的问候语的函数,并调用它。
代码:
1 def greet_user(): 2 """用户登录时,显示简单的问候语""" 3 print("Welcome to login!") 4 return 5 6 greet_user()
说明:
第1行,用def 关键字定义一个函数greet_user(),并以冒号结尾。
第2行,用文档字符串来注释说明该函数的功能。
第3行,打印一条登录时的欢迎问候语。
第4行,用关键字return 结束函数。
第6行,调用该函数greet_user()。由于该函数没有参数,所以直接用函数名加括号()调用即可。
运行结果:
Welcome to login!
1.4.2 有参函数的调用
由于函数定义中可能包含多个形参,因此有参函数的调用也可能包含多个实参。 调用函数时,给函数传递实参的方式有:位置实参、关键字实参、默认、还可能是列表和字典等等。
1.4.2.1 位置实参
由于使用位置实参传参要求实参的顺序与形参的顺序相同,因此,在调用函数时,必须将函数调用中的每个实参都关联到函数定义中的一个形参。即实参的位置必须与形参的位置保持一致。
(1)只有一个位置实参
例如,定义一个欢迎用户登录时的问候语的函数,根据不同用户打印一条相关的问候语,并调用它。
代码:
1 # 有参函数调 2 def greet_user(username): 3 """用户登录时,显示简单的问候语""" 4 print("Welcome to ",username,"!") 5 return 6 7 #有参函数调用 8 greet_user("Yun")
说明:
第2行,用def 关键字定义一个带有形参username的函数greet_user(),并以冒号结尾。
第8行,调用有参数的函数greet_user(),把实参”Yun” 的值传给形参username。
运行结果:
Welcome to Yun !
(2)有多个确认个数的位置实参
例如,定义一个有三个形参的函数,并调用它。
代码:
1 def test_func(x,y,z): 2 """接受三个参数值,并打印它们""" 3 print(x) 4 print(y) 5 print(z) 6 return 7 8 print("---第一次调用---") 9 test_func(1,2,3) 10 print("---第二次调用---") 11 test_func(4,5,6)
说明:
第1行,用def关键字定义一个具有x,y,z三个形参的函数test_func()。
第9行,调用函数test_func(),并按位置指定其参数值,即x=1,y=2,z=3。
第11行,调用函数test_func(),并按位置指定其参数值,即x=4,y=5,z=6。
运行结果:
1 ---第一次调用--- 2 1 3 2 4 3 5 ---第二次调用--- 6 4 7 5 8 6
从以上的运行结果可知,指定的位置实参的值不同,其函数返回的值也不同。
(3)有多个不确认个数的位置实参
有时候,我们无法预先知道函数需要接受多少个位置实参,因此,我们可以使用 ‘*args’ 定义形参, Python函数会从调用语句中收集任意数量的位置实参进行处理。
代码:
1 def test_func(*args): 2 print(args) 3 return 4 5 print("---第一次调用---") 6 test_func() 7 print("---第二次调用---") 8 test_func(1) 9 print("---第三次调用---") 10 test_func(1,2) 11 print("---第四次调用---") 12 test_func(1,2,3) 13 print("---第五次调用---") 14 test_func(1,2,3,4) 15 print("---第六次调用---") 16 test_func(1,2,3,4.5)
说明:
第1行,用关键字def定义了一个参数个数不确定的函数test_func(),其中“*args”表示形参个数不确定。
第2行,将接收到的参数以列表的形式输出。
第6行,调用函数test_func(),不提供任何实参值。
第8行,调用函数test_func(),提供一个实参:1。
第10行,调用函数test_func(),提供两个实参:1、2。
第12行,调用函数test_func(),提供三个实参:1、2、3。
第14行,调用函数test_func(),提供四个实参:1、2、3、4。
第16行,调用函数test_func(),提供五个实参:1、2、3、4、5。
运行结果:
1 ---第一次调用--- 2 () 3 ---第二次调用--- 4 (1,) 5 ---第三次调用--- 6 (1, 2) 7 ---第四次调用--- 8 (1, 2, 3) 9 ---第五次调用--- 10 (1, 2, 3, 4) 11 ---第六次调用--- 12 (1, 2, 3, 4.5)
从以上运行结果可知,当我们不确认函数有多少确认的位置实参时,可使用“*args”作为形参,然后会把每次调用时传入的位置实参值以列表的形式当做参数传递。这个位置实参可以没有人值,或者有多个值。
1.4.2.2 关键字实参
关键字实参是传递给函数的名称-值对,即每个实参都由变量和值组成。由于可以直接将实参中名称和值关联起来,因此向函数传递实参时就不会混淆,调用函数时不仅不用考虑实参的顺序,还能清楚的指出函数调用中每个值的用途。但是,使用关键这参数时,必须准确的指定函数定义中的形参名。
例如,我们使用关键字实参来调用1.4.2.1中定义的函数。
(1)只有一个关键字参数
代码:
1 def greet_user(username): 2 """用户登录时,显示简单的问候语""" 3 print("Welcome to ",username,"!") 4 return 5 6 #有参函数调用 7 greet_user(username="Yun")
说明:
第7行,调用函数greet_user()时,使用关键字实参来给函数传值。
运行结果:
Welcome to Yun !
从以上运行结果可知,跟1.4.1.1中的一致。
(2)有多个确定个数的关键字参数
代码:
1 def test_func(x,y,z): 2 """接受三个参数值,并打印它们""" 3 print(x) 4 print(y) 5 print(z) 6 return 7 8 print("---第一次调用---") 9 test_func(x=1,y=3,z=3) 10 print("---第二次调用---") 11 test_func(x=4,y=5,z=6)
运行结果:
1 ---第一次调用--- 2 1 3 3 4 3 5 ---第二次调用--- 6 4 7 5 8 6
从以上运行结果可知,与1.4.1.1中的一致。
那么,假如我们不指定实参z的值,那结果如何呢?
代码:
1 def test_func(x,y,z): 2 """接受三个参数值,并打印它们""" 3 print(x) 4 print(y) 5 print(z) 6 return 7 8 print("---第一次调用---") 9 test_func(x=1,y=3,3) 10 print("---第二次调用---") 11 test_func(x=4,y=5,6)
运行结果:
1 File "F:/PyProject/s14/day3/test_function.py", line 10 2 test_func(x=1,y=3,3) 3 ^ 4 SyntaxError: positional argument follows keyword argument
从以上的运行结果可知:
(1)当我们用关键字参数调用函数时,必须每个实参都需指定其关联的形参名。
(2)错误提示未指出第11行的错,这是因为Python时解释型语言,但前面的代码出错了,若没对异常进行处理,那么就停止,不再运行后续的代码。
(3)有多个不确定个数的关键字参数
有时候,我们无法预先知道函数需要接受多少个关键字实参,因此,我们可以使用‘**kwargs’定义形参, Python函数会从调用语句中收集任意数量的关键字实参进行处理。
代码:
1 def test_func(**kwargs): 2 print(kwargs) 3 return 4 5 print("---第一次调用---") 6 test_func() 7 print("---第二次调用---") 8 test_func(x=1) 9 print("---第三次调用---") 10 test_func(x=1,y=2) 11 print("---第四次调用---") 12 test_func(x=1,y=2,z=3) 13 print("---第五次调用---") 14 test_func(x=1,y=2,z=3,x1=4) 15 print("---第六次调用---") 16 test_func(x=1,y=2,z=3,x1=4,y1=5)
说明:
第1行,我们用关键字def定义函数test_func()时,由于不确认函数的形参个数,故用“**kwargs”作为形参。
第2行,打印该形参”**kwargs”的值。
运行结果:
1 ---第一次调用--- 2 {} 3 ---第二次调用--- 4 {'x': 1} 5 ---第三次调用--- 6 {'x': 1, 'y': 2} 7 ---第四次调用--- 8 {'x': 1, 'y': 2, 'z': 3} 9 ---第五次调用--- 10 {'x': 1, 'y': 2, 'z': 3, 'x1': 4} 11 ---第六次调用--- 12 {'x': 1, 'y': 2, 'z': 3, 'x1': 4, 'y1': 5}
从以上的运行结果可知,当我们调用形参个数不确定,且用“**kwargs”作为形参的函数时,我们只能使用关键字实参传值,并且会将指定的关键字实参当作字典的形式输出。
1.4.2.3 默认值
默认值就是指定的常量。当我们编写函数时,可以给每个形参指定默认值,然后在调用函数时,如果给形参提供了实参,则使用提供的实参,否则使用形参的指定的形参的默认值。
因此,给形参指定默认值后,可以在函数调用中省略相应的实参。但是形参列表中,默认值只能放到其他形参的后面,这样才能使Python解释器能够正确的解读位置实参。
使用默认值的好处:
(1)可简化函数调用。
(2)可清楚指出函数的典型用法
例如,创建一个函数具有三个形参x、y、z,其中z的默认值为0,然后调用该函数,并打印的值。
代码:
1 def test_func(x,y,z=0): 2 print(x) 3 print(y) 4 print(z) 5 6 print("---第一次调用---") 7 test_func(1,2) 8 print("---第二次调用---") 9 test_func(1,y=2) 10 print("---第三次调用---") 11 test_func(x=1,y=2) 12 print("---第四次调用---") 13 test_func(1,2,3) 14 print("---第五次调用---") 15 test_func(1,2,z=3) 16 print("---第六次调用---") 17 test_func(x=1,y=2,z=3)
运行结果:
1 ---第一次调用--- 2 1 3 2 4 0 5 ---第二次调用--- 6 1 7 2 8 0 9 ---第三次调用--- 10 1 11 2 12 0 13 ---第四次调用--- 14 1 15 2 16 3 17 ---第五次调用--- 18 1 19 2 20 3 21 ---第六次调用--- 22 1 23 2 24 3
从以上的运行结果可知:
(1)调用有默认值的函数时,如果没有指定实参,那么形参将使用自身的默认值,反之,则使用指定的实参。
(2)当混合使用关键字实参和位置实参时,位置实参只能位于关键字实参的前面。
1.5 返回值
1.5.1 返回值的定义
返回值是指函数返回的值,是函数重要的组成部分。由于函数的根本在于实现程序的部分功能,因此,很多时候我们需要将函数执行后的结果返回给程序再由程序作出进一步的操作。此时,可使用 return 语句将值返回到调用函数的代码行。
1.5.2 返回值的作用
返回值作用:能够将程序的大部分繁重工作移到函数中去完成,从而简化主程序。
1.5.3 返回一个简单值
例如,创建一个函数接受两个参数,然后返回最大者。
代码:
1 def test_func(x,y): 2 """判断数字大小,返回最大值""" 3 if x > y: 4 max_num = x 5 else: 6 max_num = y 7 return max_num 8 9 max_number = test_func(11,18) 10 print("The maximum is",max_number,".")
运行结果:
The maximum is 18 .
1.5.4 返回一个列表
例如,创建一个函数接受一个列表,然后将奇数组成一个新的列表作为返回值。
代码:
1 def test_func(list_nums): 2 """接收一个列表,返回奇数组成的列表""" 3 list_nums_new = [] 4 list_nums_bak = list_nums[:] 5 while list_nums_bak: 6 list_num = list_nums_bak.pop() 7 if list_num % 2 == 0 : 8 pass 9 else: 10 list_nums_new.append(list_num) 11 return list_nums_new 12 13 list = test_func([0,1,2,3,4,5,6,7,8,9]) 14 print(list)
说明:
第3行,创建一个空的列表。
第4行,创建一个接受到的列表的副本。
第5行,使用while循环列表副本。
第6行,每次从列表副本中单出末尾的元素,将其赋值给变量list_num。
第7~10行,判断弹出的元素是否为偶数,如果是,则跳过,反之,则将其增加到创建的空列表list_nums_new中。
第11行,用return语句返回奇数组成的新列表list_nums_new。
第13行,调用函数test_func(),将其返回值赋值给变量list。
第14行,打印返回的列表。
运行结果:
[9, 7, 5, 3, 1]
1.5.5 返回一个字典
例如,创建一个函数接受一个字典,然后将值的奇数的键-值对组成一个新字典返回。
代码:
1 def test_func(dict_nums): 2 """接收一个列表,返回值为奇数组成的字典""" 3 dict_nums_new = {} 4 for key,vlaue in dict_nums.items(): 5 if vlaue % 2 == 0 : 6 pass 7 else: 8 dict_nums_new[key] = vlaue 9 return dict_nums_new 10 11 dict = test_func({'a':0,'b':1,'c':2,'d':3,'e':4,'f':5}) 12 print(dict)
说明:
第3行,创建一个空字典dict_nums_new。
第4~8行,使用for语句循环接受的字典,然后判断该值是否为奇数,如果不是,则跳过;反之,则增加到空字典中。
运行结果:
{'b': 1, 'd': 3, 'f': 5}
1.6 将函数存储在模块中
在Python中,模块就是扩展名为.py的文件,它包含要导入到程序中的代码。
将函数存储在模块中,然后再将模块导入到主程序中。这样做的好处有:
(1)可隐藏程序代码的细节。
(2)可在众多不同的程序中重用函数。
(3)可与其他程序员共享这些文件而不是整个程序。
1.6.1 模块的导入
根据不同的需要,模块的导入方法也很多。模块的导入方法有:导入整个模块、导入特定的函数、导入模块中的所有函数。并且,我们可使用as来给导入的函数活或者模块指定别名。
1.6.1.1 导入整个模块
导入整个模块的方法为:
import 模块名
例如,我们创建将1.6.3中的代码修改一下,值保持函数代码部分,作为一个球任意两数的最大者的模块max_num,然后在一个调用程序test_max.py使用该模块。
模块中的函数:
1 def test_max(x,y): 2 """判断数字大小,返回最大值""" 3 if x > y: 4 max_num = x 5 else: 6 max_num = y 7 return max_num
代码:
1 import max_num 2 3 max = max_num.test_max(20,18) 4 print("The max is",max,".")
说明:
第1行,使用import导入模块max_num。
运行结果:
The max is 20 .
1.6.1.2 导入特定的函数
导入特定的函数的方法为:
from 模块名 import 函数名
例如,将求任意两个数的最大值和最小值的函数放到一个模块max_min_num的模块中,然后调用其中求最小值的函数。
模块:
1 def test_max(x,y): 2 """判断数字大小,返回最大值""" 3 if x > y: 4 max_num = x 5 else: 6 max_num = y 7 return max_num 8 9 def test_min(x,y): 10 """判断数字大小,返回最大值""" 11 if x < y: 12 min_num = x 13 else: 14 min_num = y 15 return min_num
代码:
1 from max_min_num import test_min 2 3 min = test_min(20,18) 4 print("The min is",min,".")
运行结果:
The min is 18 .
如果需要从某个模块中导入多个函数,可使用逗号分开即可。具体方法如下所示:
from 模块名 import [函数名1], [函数名2],…, [函数名N]
例如,调用模块max_min_num中的求最大值和最小值的函数。
代码:
1 from max_min_num import test_min as t_min,test_max as t_max 2 3 min = t_min(20,18) 4 print("The min is",min,".") 5 6 max = t_max(20,26) 7 print("The max is",max,".")
说明:
第1行,从模块max_min_num中导入求最大值和求最小值的函数,并分别给它们取一个别名。
第3行,使用求最小值的函数的别名调用其方法求最小值。
第6行,使用求最大值的函数的别名调用其方法求最大值。
运行结果:
1 The min is 18 . 2 The max is 26 .
从以上结果可知,使用函数别名和使用函数本身是一样的效果。
因此,在导入模块或者模块中的函数时,如果模块名称和函数名称比较尝,都可对其指定别名,在调用时,使用其别名即可。
1.6.1.3 导入所有的函数
导入所有的函数的方法如下:
from 模块名 import *
例如,调用模块max_min_num中的所有函数。
代码:
1 from max_min_num import * 2 3 min = test_min(20,18) 4 print("The min is",min,".") 5 6 max = test_max(20,26) 7 print("The max is",max,".")
运行结果:
1 The min is 18 . 2 The max is 26 .
从以上结果可知,从一个模块中分别导入的特定函数和导入所有函数的方法,其调用该函数的效果是不变的。
1.7 函数编写规范
编写函数时,应遵循以下规范:
(1)函数名称应具有描述性,且只使用小写字母和下划线来命名。
(2)每个函数都应包含文档字符串,即简要地阐述该函数的功能的注释,该注释应紧跟在函数定义后面,并采用文档字符串格式。
(3)给形参指定默认值时,等号两边不要有空格。
(4)对于函数调用中的关键字实参,也应遵循等号两边不要有空格的约定。
(5)PEP 8(https://www.python.org/dev/peps/pep-0008/)建议代码行的长度不要超过79字符。
(6)如果程序或模块包含多个函数,可使用两个空行将相邻的函数分开。
(7)所有的 import 语句都应放在文件开头,唯一例外的情形是,在文件开头使用了注释来描述整个程序。