今天,飞哥就给小伙伴讲讲函数,由浅入深的从小例子出发,带领小伙伴掌握开发过程中必备的入门基础知识。

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>>>