自定义函数非常简洁有效地实现了代码的复用,让程序编写、阅读、测试和修改变得更加容易。
下面记录Python自定义函数的使用。
1、定义函数:
def describe_pet(pet_name,animal_type='dog'):
'''显示宠物的信息'''
print(f"\nI have a {animal_type}.")
print(f"My {animal_type}'s name is {pet_name.title()}。")
上面代码定义了一个函数describe_pet(),第一行使用定义函数的关键字def,def关键字告诉Python解释器你要定义一个函数,describe_pet是函数名字,紧跟函数名字后面是一对圆括号,括号内可定义参数,或者为空(没有参数,圆括号也是必须的),最后是冒号结尾。
上面代码第二行及所有缩进的代码构成了函数体。
上面代码第二行的文本使用一对三单引号(或者双引号),成为文档字符串(docstring)注释,描述该函数功能。文档字符串注释可以是单行,也可以是多行,但并不是必须有,主要是供以后调用及其他人调用可以清楚该函数的功能。
2、函数参数:形参与实参
在函数定义中,变量pet_name和animal_type是函数形参(parameter),属于函数完成工作所需要的信息。
在调用函数时,让函数使用的信息放在圆括号内,如下的代码实现调用,'旺旺'就是一个实参,这个实参传递给函数describe_pet(),并把值赋给形参pet_name。
describe_pet('旺旺')
3、传递参数
函数定义中可以包含多个形参,因此函数调用中也可能包含多个实参。向函数传递实参的方法很多,既可以使用位置实参,这要求实参的顺序与形参的顺序必须相同;也可以使用关键字实参,其中每个实参是由变量名(形参)=值(实参)组成;还可以使用列表和字典。
(1)位置实参
使用位置实参,函数调用中的每个实参关联到函数定义中的一个形参。最简单的方式是基于实参的顺序进行关联。以这种方式关联的实参成为位置实参。如下:
describe_pet('花花','猫咪')
实参'花花'被赋值给形参pet_name,实参'猫咪'赋值给形参animal_type.
使用位置实参来调用函数是,实参和形参的顺序必须一致。
(2)关键字参数
关键字实参是传递给函数的名值对。如下:
describe_pet(animal_type='猫咪',pet_name='花花')
使用关键值实参,因将函数中形参名和实参值关联起来,Python知道各个值该赋值给哪个形参,故位置可以不按照顺序。如下代码输入效果和上面是一样的:
describe_pet(pet_name='花花',animal_type='猫咪')
(3)默认值
在编写函数时,可以给每个形参指定默认值。如果在调用函数时给形参提供了实参,Python将使用指定的实参值;否则将使用形参的默认值。因此,给形参指定默认值后,可在函数调用时省略相应的实参。上面函数定义中,对形参animal_type='dog',就是给形参animal_type指定了默认值'dog'。看如下代码:
describe_pet('旺旺')
上面一行代码调用describe_pet()函数,仅传递了一个实参,可以正确执行,输出结果如下:
函数中因给形参animal_type指定了默认值'dog',调用时如果没有对应的实参,Python将自动把animal_type形参赋值默认值'dog'。
注意(1):当使用默认值时,必须在形参列表中先列出没有默认值的形参,再列出有默认值的形参,这让Python依然能够正确地解读位置参数。
注意(2):在给形参指定默认值时,通俗习惯是等号两边不要有空格。但是如果有空格,系统会正常运行。
(4)混合调用:
Python允许使用位置参数、关键字参数和默认值,可以多种形式进行混合调用,上面定义的函数2个参数,一个是位置参数pet_name,一个是关键字参数animal_type。
基于这种混合定义,在任何情况下调用ame提供实参,在指定该实参时,既可以使用位置实参,也可以使用关键字实参。
因为animal_type是关键字实参,指定了默认值'dog',调用函数可以不传递实参,使用默认值。但是要描述的动物不是'dog',就需要传递相应的实参值,同样,既可以使用位置参数如下:
describe_pet('花花','猫咪')
也可以使用关键参数,如下:
describe_pet(pet_name='花花',animal_type='猫咪')
使用关键字实参,顺序可以更改,结果是一样的。
另外,可以混合使用,如下:
describe_pet('花花',animal_type='猫咪')
实参'花花'将赋值给形参pet_name,形参animal_type被赋值为'猫咪'。
请注意:混合调用,位置参数要在前,关键字参数在后,多个位置参数,需要确保顺序,如下位置参数在后,则出现错误:
(5)实参不匹配错误
调用函数,很可能会遇到实参不匹配异常错误。当调用时提供的实参多于或者少于函数定义时的形参数量时,将出现实参不匹配错误。如下:
上面代码调用describe_pet(),没有传递参数,Python会提示出错信息“缺少一个位置参数”,因为定义函数时提供的形参animal_type提供了默认值,所以提示是“缺少一个参数”。
(6)让实参变成可选
有时候,需要让参数变成可选的(额外信息),以便使用函数的人只在必要时才提供。给形参指定默认值就可以做到这一点。
注意:Python中,整数0,空字符串''及None值都等同于布尔值False。
(7)列表作为函数的参数
向函数传递列表比较常用,可能是名字列表、整数列表或更复杂的对象列表,这样可以传递给函数更多的值。如下:
上面代码,向函数传递了一个列表,函数获取列表的值,输入一条个性化的问候语。
(1)将列表传递给函数后,函数中可以修改列表,这让函数可以高效的处理大量数据,但是需要需要清楚和注意的是:在函数中对这个列表所做的任何修改是永久的。
上面函数print_models(),两个形参都是列表,一个是未打印的设计列表,以及一个空列表是完成打印的列表。函数print_models()模拟了打印设计的过程。
运行上面代码,调用函数print_models(),在函数中对列表进行了修改,实参unprinted_designs列表中元素被遍历弹出pop(),执行函数后成为空列表了。
(2)禁止函数修改列表
有时候,需要禁止函数修改列表(传入的实参列表类型变量),为了解决这个问题,可以向函数传递列表的副本而不是原始列表,这样函数体内对传入的实参(列表变量)做任何修改都只影响副本,而不影响原列表。需要如下这样做:
function_name(list_name[:])
上面代码向函数传递原列表的切片,切片是创建了原列表的副本,这样调用函数,函数体内代码对副本做修改,不影响原列表,比如: