今天,飞哥就给小伙伴讲讲函数,由浅入深的从小例子出发,带领小伙伴掌握开发过程中必备的入门基础知识。
Python中函数分为内置函数和自定义函数,在使用函数时通过函数名来调用。内置函数是Python语言的一部分,平时常用到的print()和len()都是Python给我们定义好的内置函数,我们直接拿来调用。自定义函数方便开发者将一段实现特定功能的、有规律的、可重复使用的代码定义成函数,从而达到代码封装、代码复用的目的。
01
定义函数
在使用函数前,必须先定义函数,也就是创建一个函数。定义函数需要用 def 关键字实现,基本语法格式如下:
def 函数名(参数1, 参数2, ..., 参数N): #实现特定功能的多行代码 [return [返回值]]
根据上面的语法格式,可以看出函数是由以下部分组成:
1)def关键字后跟带有圆括号和冒号的函数名称;
2)圆括号里定义0个或多个参数;
3)统一缩进4个空格的若干语句块;
4)return语句的返回值组成(返回值语句可无);
下面,飞哥带领小伙伴写一个简单的函数(study)。
def study(): """记录我的学习计划和目标""" print("2020年的冬天悄无声息的到来") # 学习前的准备 print("我也开启了Python Web学习计划") # 具体的学习计划 print("我的目标是大厂") # 大厂的要求 print("加油!")
有时候,我们只是想预先定义好函数名,实际的函数功能打算后面再去写,这时候就可以使用pass关键字占个位,否则编译时会报错。如下所示:
def ready(): """学习前的准备工作""" pass
是不是非常的简单,我们再后面逐步的完善这个学习函数。
02
函数调用
上面的函数被定义后,它自己是不会自动执行的,只有函数被调用后,函数体里面的代码块才会被执行,完成指定的功能。
函数调用是非常的简单,直接是函数名后跟圆括号,如果有参数,在圆括号里面输入对应的参数就调用完成。
函数调用,其基本语法格式如下:
[返回值] = 函数名([参数值])
其中,参数值指的是创建函数时要求传入的各个参数的值。如果该函数有返回值,我们可以通过一个变量来接收该返回值,当然也可以不接收。
注意:定义函数时有多少个参数,调用函数时就需要传入多少个参数值,且传入的参数值顺序必须和创建函数时一致。即使函数没有参数,函数名后的圆括号也不能省略。
# 函数调用,函数名后跟圆括号study()
03
参数传递
1、基础知识
大多数情况下,定义函数时都会有参数的,用于传递函数的个性化数据,实现代码最大化的复用。
很多业务功能的代码逻辑是一样的,但是不同的业务,执行函数时用到的业务数据不一样,这时候就需要通过参数来传递这些个性化的数据。
例如,上面定义的学习(study)函数,可以传递一个姓名(name)和职位(job)的参数,这样打印出来,就可以知道这是谁的,学习什么Python方向的计划。我们来改造一下代码:
def study(name, job): """记录我的学习计划和目标""" print("2020年的冬天悄无声息的到来") # 学习前的准备 print("{}开启了{}学习计划".format(name, job)) # 具体的学习计划 print("{}的目标是大厂".format(name)) # 大厂的要求 print("加油!")# 函数调用
study("富贵", "Python Web")---------------输出结果如下--------------2020年的冬天悄无声息的到来富贵开启了Python Web学习计划富贵的目标是大厂加油!----------------------------------------# 函数调用study("来福", "Python 爬虫")---------------输出结果如下--------------2020年的冬天悄无声息的到来来福开启了Python Web学习计划来福的目标是大厂加油!----------------------------------------
2、值传递和引用传递
小伙伴在开发的过程中,可能会遇到这样的场景:
定义了一个全局的列表类型的变量,并给了默认值。然后传给另外一个同事写的接口函数,结果调用完成后,这个全局的变量怎么变了?后面还要把这个全局列表变量传给其他人的接口使用,而且列表变量必须是原始的默认值。搞的我一头雾水,我就传了一下参数值么,怎么就把值给改变了?
其实,这个问题很好解释,因为这个列表类型的变量作为函数参数传递时,是引用传递,这样在函数中对这个传入的参数做了任何改变后,外面的这个列表类型的变量也会跟着改变。
在Python中,字符串(str), 元组(tuple), 和数字(numbers)是不可变(不可更改)的对象,而列表(list), 字典(dict), 集合(set)等是可变(可以修改)的对象。
1)值传递
不可变对象作为函数参数值传入时,相当于值传递。这时候,在函数中对这个函数参数做任何改动,都不会影响函数外面的这个原始的变量对象。
>>> a = 100 #定义一个全局变量a>>> def change_value(v1): v1 = 1000 print("函数中参数值:{}".format(v1)) >>> change_value(a) #传递上面定义的全局变量a函数中参数值:1000>>> print(a) #输出全局变量a的值,看是否改变100>>>
2)引用传递
可变对象作为函数参数值传入,相当于引用传递。在函数中对这个函数参数做任何改动,函数外面的这个原始的变量对象也会跟着变动。
>>> list1 = [100,1000,10000] #定义一个全局列表变量list1>>> def change_list(v1): v1[-1] = v1[-1]*5 print("函数中参数值:{}".format(v1)) >>> change_list(list1) #传递上面定义的全局列表变量list1函数中参数值:[100, 1000, 50000]>>> print(list1) #输出全局列表变量list1,看是否改变[100, 1000, 50000]>>>
04 参数的类型 1、
必备参数
定义函数时有多少个参数,调用函数时就需要传入多少个参数值,且传入的参数值顺序必须和创建函数时一致。大部分情况下,我们定义的函数参数都是必备参数。例如,上面的study函数中的参数就是必备参数。
# 函数调用,如果顺序错了,则输出结果让人摸不着头脑study("Python 爬虫","来福") #参数顺序错误---------------输出结果如下--------------2020年的冬天悄无声息的到来Python 爬虫开启了来福学习计划Python 爬虫的目标是大厂加油!----------------------------------------
# 函数调用,如果少传入一个参数,则会出现异常报错study("来福") #参数缺失---------------异常信息如下--------------Traceback (most recent call last): File "E:/code/python/pycharm_code/untitled/test1.py", line 19, in <module> study("富贵")TypeError: study() missing 1 required positional argument: 'job'----------------------------------------
2、默认参数
在定义函数时,直接给参数指定一个默认值。这样在调用函数时,若没有给拥有默认值的参数传递参数值,该参数就直接使用定义函数时设置的默认值。
小伙伴想象这样的场景:
大家吃饭的时候,饭菜里的盐都是厨师凭经验放的,你点餐的时候,不用告诉他放盐,厨师做菜的时候都会放。《默认》
可偏偏有一些人,吃盐很重,他去点餐的时候,就会说盐大一点。《定制》
还有人不吃盐,他去点餐的时候,就会说不放盐。《定制》
假如这是一个自动化的炒菜机,现在模拟炒菜行为:
def cook(name, food, salt="正常"): """自动烹饪程序""" print("{}点的{},盐的口味:{}".format(name, food, salt)) print("你的餐正在烹饪...") print("你的餐已完成,请食用.")
# 函数调用,第3个参数不传时使用默认值,这是大部分的情况cook("富贵", "西红柿茄子")---------------输出结果如下---------------富贵点的西红柿茄子,盐的口味:正常你的餐正在烹饪...你的餐已完成,请食用.-----------------------------------------
# 函数调用,第3个参数使用传递的值,这样的情况很少cook("来福", "西红柿茄子", "盐大一些")---------------输出结果如下---------------来福点的西红柿茄子,盐的口味:盐大一些你的餐正在烹饪...你的餐已完成,请食用.-----------------------------------------
总结:默认参数,很适合在类似上面的使用场景中使用。也就是,大部分情况下,参数值都是固定的,只有极少数情况下需要用户手动指定参数值。
注意,在定义函数使用默认参数时,指定有默认值的参数必须在所有不是默认值参数的最后,否则会产生语法错误。
3、关键字参数
关键字参数是指使用《定义函数时参数的名字》来指定传递的参数值。使用关键字参数指定参数值时,不再需要与定义函数时参数的顺序完全一致,只要将参数名写正确即可。
在使用必备参数时,传入的参数值顺序必须和创建函数时一致,否则出现程序行为异常,严重时导致程序崩溃。例如,下面的参数顺序错了:
# 函数调用,如果顺序错了,则输出结果让人摸不着头脑study("Python 爬虫","来福") #参数顺序错误---------------输出结果如下---------------2020年的冬天悄无声息的到来Python 爬虫开启了来福学习计划Python 爬虫的目标是大厂加油!-----------------------------------------
但是,使用关键字参数,就可以避免上述的参数顺序错位的问题。例如,上面的调用使用关键字参数:
# 函数调用,函数名后跟圆括号study(job="Python 爬虫", name="来福") # 使用关键字参数---------------输出结果如下---------------2020年的冬天悄无声息的到来来福开启了Python 爬虫学习计划来福的目标是大厂加油!-----------------------------------------
4、可变参数
有时候我们在定义函数时,没办法确定函数参数的个数,这时候就可以用可变参数来满足这种需求。
在Python中,可变参数使用*参数名称定义,在函数中使用时,可变参数是一个元组,函数调用时传递的参数值被依次放在这个元组里。
示例,使用下面的代码验证关键字参数的类型和值:
def sum_money(*values): """计算开发小组发放的项目奖金的总和""" print("可变参数的类型:{}".format(type(values))) print("参数值:{}".format(values))---------------输出结果如下---------------可变参数的类型:'tuple'>参数值:(10000, 8000, 12000)-----------------------------------------
到年底了,领导在群里说:“要计算每个月我们开发小组所有人的奖金总和。”
这时候富贵想起了刚学的可变参数,这不是用上排场了吗。
富贵自高奋勇的说,“1分钟搞定。”
# 使用可变参数搞定多个参数值def sum_money(*values): """计算开发小组发放的项目奖金的总和""" print("奖金总额:{}".format(sum(values)))
# 计算3个人的奖金sum_money(10000, 8000, 12000)---------------输出结果如下---------------奖金总额:30000-----------------------------------------# 计算5个人的奖金sum_money(10000, 8000, 12000, 15000, 6000)---------------输出结果如下---------------奖金总额:51000-----------------------------------------
05
匿名函数
lambda 表达式,又称匿名函数,常用在需要传入一个函数对象的场景,这时候,不需要显示的定义函数,直接传入匿名函数。
匿名函数,其基本语法格式如下:
Lambda [参数1 [参数2,…, 参数N]]: 表达式
匿名函数的函数体只能是一个表达式,不能用return语句,返回值就是该表达式的值。由于函数体不能包含复杂的代码结构,因此通常用于实现一些简单的功能。
匿名函数因为没有名字,所以不用担心函数名称冲突。此外,匿名函数也是一个函数对象,可以把匿名函数赋值给一个变量,再利用变量来调用该函数,就像普通的函数调用一样。
示例1,输出奖金最高的小伙伴的信息:
bonuses = [ ("小王", 10000), ("小李", 8000), ("小赵", 12000), ("小刘", 15000)]def get_bonus(item): """提取奖金值用于比较""" return item[1]# 使用普通函数print(max(bonuses, key=get_bonus))---------------输出结果如下---------------------('小刘', 15000)-----------------------------------------------# 使用匿名函数print(max(bonuses, key=lambda item: item[1]))---------------输出结果如下---------------------('小刘', 15000)-----------------------------------------------
示例2,把匿名函数赋值给一个变量,利用变量来调用该函数:
>>> f1 = lambda x: x-100>>> type(f1)<class 'function'>>>> f1(100)0>>> f1(101)1>>>