前言
昨天将函数前半部分看完了,这里稍微做一下总结。
知识回顾
函数定义
函数的定义很简单,如下:
函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需要调用这个函数名即可
注意:调用函数名之后,要在函数名后面加一对(),函数才会执行,否则将返回函数的内存地址。
在代码中定义一个函数:
def calc(x,y): res = x**y return res
那为什么要使用函数呢?
在学习函数之前,假设需要你写一段代码,7*24h监控公司服务器,当CPU/MEMORY/DISK超过阈值时报警并发送邮件,那你可能会这么写:
乍一看这段代码能够将功能实现,但你会发现,这中间有很多重复的代码,而且万一哪天想换个报警的方式,还得换三次。这时候你学到了函数,那你可能会这么写:
def send_mail(): #发送邮件提醒 连接邮箱服务器 发送邮件 关闭连接 while True: if cpu利用率>90% send_mail() if 硬盘使用空间>90%: send_mail() if 内存占用>90%: send_mail()
相比较一下,函数的特性变可得出:
- 减少重复的代码
- 是代码变得可拓展,易维护
函数的参数
这时候又有一个新的需求,就是每次调用这个发邮件函数的时候,我可能要发给不一样的人来维护,比如CPU占用率的报警我要发给Eric,硬盘使用率要发给Rain,内存使用率要发给Kris,这可怎么办呢?
之前我们写的函数里面只能发给特定的人的邮箱…唔,想一想,我们之前好像已经学过变量,那我们如果将邮箱账号换成变量,然后每次调用函数的时候给变量赋我们需要的值便可。如我们之前定义过的calc():
def calc(x,y): res = x**y return res
这里定义时括号里的x,y便是形参变量,形参变量只有在被调用时才会被分配内存单元,在调用结束后就会被立刻释放内存单元。因此,形参只在函数内部有效。函数调用结束后就不能再使用该函数的形参变量。
而当我们在调用这个calc()函数时,是一定要给两个参数的,即:
calc(3,4) a=5 b=6 calc(a,b)
这里使用的3,4或者a,b,称为实参变量。实参可以是常亮、变量、表达式、函数等,无论是哪种类型,在进行函数调用时,必须有明确的值,以便来传送给形参。
位置参数
在运行上面的代码时可以发现,a的值总是传给了x,b的值总是传给了y,如果我们给a,b换个位置,执行:
c = calc(b,a)
就会得到另一个结果,并且是b**a,这就意味着这一次b的值给了x,而a的值给了y,这样以位置顺序确定对应关系的参数就叫位置参数。
关键参数
如果有一天你不想按顺序传参数了,你可以使用关键字参数,又称关键参数。你只需要做的只是指定参数名,就是告诉函数你的这个值是给谁的。
def stu_info(name,age,country,course) print('姓名:',name) print('年龄:',age) print('国籍:',country) print('课程:',course) # 关键参数 stu_info('山炮',course='Python',age=22,country='CN') #但绝不可以这样 stu_info('山炮',course='Python',22,country='CN') #这样也不行,同一个参数传两个值 stu_info('山炮',25,age=22,country='CN')
注意:关键参数要放在位置参数后面,切记。
默认参数
当我们在调用上面的函数录入学生信息时,我们发现由于学生大部分都是中国学生,所以国籍country这个形参我们传的大部分都是CN,为了简便,我们可以将contry变成默认参数,即这个参数在调用时不指定,那么就是你定义的默认值,如果指定了,就用你指定的值。这时,我们就可以这么定义参数:
def stu_info(name,age,course,country = 'CN') print('姓名:',name) print('年龄:',age) print('课程:',course) print('国籍:',country) #调用函数 stu_info('山炮',22,'Python') # 这里使用默认国籍CN stu_info('松岛菜菜子',22,'TV','JP') # 这里使用指定的值
你可能注意到了,在把country变成默认参数后,同时把它移动到了最后面,可以思考下为什么?
很简单…
不放在最后会产生歧义。
还是上面的例子…
# 假设我这么定义,注意这是错误的 def stu_info(name,age,country = 'CN',course) print('姓名:',name) print('年龄:',age) print('课程:',course) print('国籍:',country) # country使用默认值,course = 'Python' stu_info('山炮二号',25,'Python')
运行后会报错,前两个没什么问题,到了第三个这里,’Python’原本你是想传给course,但是由于位置的关系,它会传给country,而最后一个course就没有值传给它,它又不是个默认参数,所以会报错。…其实根本就不能运行,因为定义函数的时候就错了- –
非固定参数
还是回到最开始发邮件的那个函数,我们已经可以做到给不同的人发邮件,只要定义的时候多加一个参数user:
def send_mail(user): #发送邮件提醒 连接邮箱服务器 发送邮件给user 关闭连接
现在你的公司扩招了,负责CPU处理的人变多了,这时候你想给他们都发邮件,那你的做法可能是:
for i in users_list: send_mail(i)
循环给他们每个人发邮件…那如果我现在要求只给一部分的人发邮件,不要全部,你可能会想到去改users_list,假如这个list里有成千上万人,就是很多很多人,你要给其中一部分发邮件,那修改list的方法似乎有点难以实现…当你不确定你的用户个数时,你需要定义非固定参数:
def send_mail(*args): #发送邮件提醒 连接邮箱服务器 发送邮件给user 关闭连接
…一般我们在定义非固定参数时,都用 *args ,当然不用args也可以,但主要是为了规范。
这里定义的参数就是非固定参数,当你调用参数时:
#调用参数 send_mail('Alex','Rain','Eric','Kris')
*args
会将你传给它的值变为一个元组形式,即('Alex','Rain','Eric','Kris')
,然后会将元组中的每个元素依次传出,相当于for循环了这个元组,但是不需要另外写代码,只要定义时注意将参数定义成非固定参数即可。
这样就实现了可传入不确定个数的参数。
非固定关键字参数
和上面的非固定参数差不多,只不过这里定义时是使用两个*,即**kwargs
,这里传入值时,需要使用关键字参数传入的形式:
def send_mail(**kwargs): #发送邮件提醒 连接邮箱服务器 发送邮件给user 关闭连接 #调用参数 send_mail(name='Alex',age=22,sex='male')
**kwargs
会将传给它的参数转成dict,则上面代码调用函数的效果就是返回{‘name’:‘Alex’,‘age’:22,‘sex’:‘male’}。
函数的返回值
这里来处理一个历史遗留问题,在上面我们定义calc函数时,你会发现函数的最后有一句:return res
。如果函数外部的代码想要获得函数执行的结果,就需要通过return来返回结果。
注意:
- 函数执行过程中只要遇到return语句,就会停止执行返回测试结果。可以理解为第一句return即为函数的结束。
def func(): # 可以思考下执行这个函数会打印2嘛? print('1') return True print('2') return False
- 如果函数中未指定return的内容,变会返回None。
局部变量
我们知道了函数定义时可以定义各种变量,但这些变量都有一个限制,就是他们只能在这个函数中使用,在其他函数中想要调用是不行的。即局部变量的作用域是定义该变量的函数。
作用域(scope),程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
而与之相对的则是全局变量。
全局变量
在程序一开始定义的变量称为全局变量。全局变量的作用域是整个程序,你在程序重定义的函数也可以调用全局变量。
全局变量vs局部变量
- 全局变量的作用域是整个框即整个程序,而局部变量的作用域仅限于定义该变量的函数的作用域。
- 当全局变量与局部变量重名时,在定义该局部变量的函数中,局部变量起作用,其他地方全局变量起作用。
嵌套函数
嵌套函数就是在一个函数中再定义一个函数:
a = 3 b = 4 def fun1(): print(a) def func2(): print(b) #func1 里调用func2 func2() #调用func1() func1()
这个调用的结果就是:3,4
再看这段代码:
请问最后输出的是什么?
牢记局部变量的作用域。
匿名函数
匿名函数就是不需要指定显示的函数名
匿名函数最多支持我们之前学过的三元函数。
主要用处是与其他的函数搭配使用。
高阶函数
变量可以指向函数,函数的参数可以接受变量,那么一个函数就可以接受另一个函数作为参数,这种函数就叫高阶函数。
只需要满足以下任一条件,即为高阶函数:
- 接受一个或者多个函数作为输入
- return返回另一个函数