一、概念及作用:
概念:由若干条语句组成语句块,其中包括函数名称、参数列表,它是组织代码的最小单元,完成一定的功能
作用:把一个代码封装成一个函数,一般按功能组织一段代码
目的就是为了重复使用如,print函数可以重复多次的使用,
减少了代码冗余,代码更加简洁美观,可读易懂
二、函数的定义
def 函数名(标识符)
函数体(代码块)
return(返回值){如果没有return语句,隐士返回None值}
下面用一个最简单的函数,加法来举例说明
调用时写传入的参数是实际参数,是实实在在传入的值,简称为实参,如add(5,4)
定义中参数列表称为形式参数,只是一种符号的表达(标识符),简称形参,如add(x,y)
输出结果
从上面代码中可以看出,
定义了一个叫add的函数,能接收两个参数
该函数计算 的结果,通过返回值返回,也就是return语句
调用时通过函数名add后的两个参数,返回可使用变量接收
函数名也是标识符
返回值也是只
三、函数的参数
了解了函数的定义,我们知道了函数要定义好形式参数,调用是也要有足够的实际参数,一般来说,形式参数要和实际参数一致(除可变参数除外)
3.1、实参传参方式
3.1.1、位置传参
定义式def fn(x,y,z),调用时使用fn(1,3,5),按照参数定义顺序传入实参
输出结果
3.1.2、关键字传参
定义时def fn(x,y,z),调用时使用fn(x=1,y=2,z=3)使用形参的名字来传入实参的方式,如果使用了形参名,那么传入顺序可就和定义顺序不同了
输出结果
那么这两种方式可以混和使用吗?答案是肯定的,可以,如何使用?如下
情况一、位置参数在前面,关键字参数在后面
输出结果
情况一、位置参数在后面,关键字参数在前面
输出结果
直译过了就是位置参数要跟在关键字后面,也就是说位置参数必须在关键字之前传入
总结:实际传参有两种方式,位置传参和关键字传参
位置传参和形参依次对应
关键字传参,按照参数名称对应,与顺序无关
这两种传参方式可以混和使用
位置传参不能再关键字传参之后
了解了实参,下面 来看看形参
3.2、形参定义
3.2.1、形参缺省值
缺省值,也称为默认值,可以在函数定义时,为函数增加一个缺省值,其作用:
参数的默认值可以在未传入足够的实参时,对没有给定的参数赋值为默认值
参数非常多的时候,并不需要用户每次输入 都输入所有参数,简化函数调用。
如下:
输出结果
也可以这样使用
位置传参,6传给了x,y=5
还可以这样定义函数
如果缺省值定义在普通参数之前呢?如下:
输出结果
没有默认值的参数后面跟着默认值的参数是错误的,也就是说缺省值应该在普通列表的最后
总结:x,y都可以接受两种传参方式,既可以接收位置又可以接受关键字参数,但是注意,不能传入多个参数,也就是形参有多少个,实参对应形参的个数。普通参数也可以有缺省值。缺省值应该在普通列表的最后。
下面来看一个登录函数
输出结果
解决调用时函数参数过于复杂的问题.
3.3、可变参数
3.1、可变位置参数
将可变参数之前先看一段代码,需求:写一个函数,可以对多个数累加求和。
输出结果
上列中传入可迭代对象,并累加每一个元素
如果非要用fn(1,2,3)怎么办呢?其实可以这样写
输出
从上面可以看出,*可变形参,可以接收多个实参,多个实参被收集到一个对象中,元组不可变。但是元组可迭代,所以可以写成
这是按照位置传参
输出结果:
如果按照关键字传参呢?
输出结果:
也就是说不期望用关键字传参
总结:在形参前使用*表示改形参是可变位置参数,可以接受多个实参
他将收集到的实参组织到一个元组中。
3.1、可变关键字参数
在形参前使用**,表示改形参是可变关键字参数,可以接受多个关键字参数,
他将收集到的实参的名称和值,组织到一个dict中。字典是可变的
输出结果
在函数函数内部,你能传入的变量名,有要求,对kwargs进行处理,username in kwargs.keys()
如果可变位置参数和可变关键字参数混合使用呢?请看下列代码。
可以定义为下列方式吗?
输出结果:
在115行中,这种定义方式是错误的。也就是说,可变位置参数要在可变关键字参数之前。
总结就是:
有可变位置参数和可变关键字参数。
可变位置参数在形参前使用一个*号,可以收集若干个实参,将这些实参收集成一个tuple对象
一般用*args
可变关键字参数在形参前使用两个**好,可以收集若干个实参,讲这些实参收集成一个dict对象。一般用**kwargs
混合使用参数时,普通参数需要放到参数列表前面,可变参数要放到参数列表后面,可变位置参数要放到可变关键字参数之前。
下面看一个混合使用的列子加深对他的使用
输出结果
3.3、keyword-only参数
先看一段代码
输出结果
在python3.6之后新增了keyword-noly参数,
keyword-noly参数:在形参定义时,在一个*号之后,或一个可变位置参数之后,出现的普通参数,就已经;不在是普通参数了,称为keyword-noly参数。
keyword-only参数,言下之意就是这个参数只许传入关键字参数。
看上面代码可知,*args已经截获了所有位置参数,后面的x,y不可能通过位置参数传值了,所以132、133、134都是同一类型的错误。
它的宁外一种形式。
输出结果
3.4、position-only参数
参数规则一般顺序是:position-only参数,普通参数、缺省参数、可变位置参数、keyword-only参数、可变关键字参数。
注意代码应该易读易懂,而不是为难别人。
请看下面一段代码。
输出结果
由此可知a,b必须传入位置参数。
四、封装解构
首先先看一个例子:
可以这样写
运行结果
但是这样写太麻烦了
能不能简化呢?可以这样写
输出结果
下面再来看一段代码:
输出结果
总结:
在函数使用参数,可以在迭代对象前使用*,或**来对结构进行结构,提取所有元素作为函数的实参。
*解构成位置传参
**结构成关键字传参
提取出来的元素数目要和参数要求相匹配。
注意看下面一个代码:
输出结果
通过上面的详细讲解,其实这个就很简单了,要多加练习,熟悉函数的参数和传参形式,这样以后写函数才会更加容易
五、return返回值
先看几个例子
例1:
输出结果:
return 之后的语句不会被执行
例2:
输出结果
return多条语句不能被执行
例3:
输出结果
六、函数练习题
例题1:
函数练习编写一个函数,至少能够接受两个参数,返回最小值和最大值
特别说明这里题目中的lst都等于list(range(100000)),这样便于分析时间效率
解法1:
解法1存在的问题解构了两次,max和min要遍历函数进行比较,也就是遍历了两次。时间复杂度是O(2n)能不能只遍历一次,解构一次呢?
解法2:
sorted内部使用的是排序算法,时间复杂度是O(n**2)所以在时间效率上来看,解法1比解法2执行效率更快,解构了一次
解法3:
相比与解法1,解法3只解构了1次,算法效率大大提高