接下来我们进入第三章的学习
一、函数的定义和调用
1.函数定义的格式:
def 函数名():
执行代码
2.函数的调用
函数名()
例如:定义函数,能够完成输出自己的姓名和年龄,并让函数执行
def getStudentInfo():
name = input('请输入姓名:')
age = int(input('请输入年龄:'))
print('我的名称是:%s,我今年%d岁'%(name,age))
#调用函数
getStudentInfo()
3.函数的参数
格式:
def 函数名(参数1,参数2...):
执行代码
调用格式:
函数名(参数1,参数2...)
案例:求两个数的总和
def add(a,b): #形参,相当于临时占了两个位置
print(a+b)
#调用函数
add(5,10) #实参,具体的值
4.调用函数时需要注意的问题
1.形参和实参必须一一对应
2.函数调用时参数的顺序
获取学生的姓名和年龄
def get_stu_info(name,age): #形参
print('我的姓名是:%s,我的年龄是:%d'%(name,age))
#调用函数
get_stu_info('姚明',18) #实参 按顺序来
get_stu_info(age = 21,name='蔡徐坤') 不按顺序来但是要多个age=...
两种方法都行
5.函数的返回值
返回值:就是程序中函数完成一件事后将结果返回给调用者
return的话只是返回值,不会输出,需要多个print
例如:求两个数之和
def add(m,n):
return m + n
#调用函数
# print(add(10,2))
res = add(10,2)
print(res)
二、函数的嵌套
一个函数中又调用了另外一个函数-----》函数的嵌套调用
例子:比较四个数的大小
#比较两个数的大小
def max(x,y):
return x if x > y else y
def max2(a,b,c,d):
res = max(a,b)
res2 = max(res,c)
res3 = max(res2,d)
return res3
#调用函数
result = max2(9,10,15,1)
print(result)
三、函数的参数传递
可分为可变对象和不可变对象
1.不可变对象
那么那些参数的值是不可变的呢? 例如:number,string,tuple
以number数字类型为例
def add(num): #形参
num = num + 10 #数字类型不可变 d本身没变
return num
2.可变对象
参数的值可以在函数中发生干改变,例如:list,dict,set
以列表为例
def change(num):#num形参
num.append(0)
li = [1,2,3,4]
change(li) #把列表作为参数
print(li) #可以发现li改变了变成[1,2,3,4,0]
我们再看如下两个例子,会让我们的印象更加深刻
def selfAdd(a):
a += a #a = a + a
return a
int = 1
result = selfAdd(int) #引用传递过去
print(int) # 输出int是1 尽管函数里是int=int+int
print(result) # result是2
list = [1,2]
result = selfAdd(list) #把值传递过去
print(list) # list被改变了为[1,2,1,2]
print(result) # 同上list
3、关键字参数
允许函数调用时参数顺序和定义时不一致
案例:获取学生的姓名,年龄等信息
def get_stu_info(name,age):
print(‘姓名是:%s,年龄是:%d’%(name,age))
get_stu_info(‘吴宣仪’,29)
get_stu_info(age = 24,name = ‘杨超越’) #age,name就是关键字
意思就是可以通过关键字来赋值,可以不用按形参的顺序
4.默认参数(缺省参数)
python为了简化函数的调用,提供默认参数机制,调用函数时,缺省参数的值如果没有传入,则会被认为是默认值
例如:获取学生的登记信息
def getStuInfo(name,sex,age = 18):
print(name)
print(age)
print(sex)
#调用函数
getStuInfo('欧阳娜娜','女') 会得到age=18
四、不定长参数
一个函数能够处理比当初声明时更多的参数------不定长参数,声明时一般不会命名
def function(args,*args,**kwargs): arg表示参数的意思
加了一个*号的变量args会存放所有未命名的变量参数,----》元祖
加了**号,存放所有命名的变量参数----》字典
def fun(a,b,c,*args,**kwargs):
print('a=',a)
print('b=',b)
print('c=',c)
print('args=',args)
print('kwargs=',kwargs)
for key,value in kwargs.items():
print('key=',key,'value=',value)
#调用函数
fun(1,3,5,6,name='鹿晗',age=20,height=180)
a= 1
b= 3
c= 5
args= (6,)
kwargs= {'name': '鹿晗', 'age': 20, 'height': 180}
key= name value= 鹿晗
key= age value= 20
key= height value= 180
可以看到除了被声明的形参拿走的,剩下的未命名的都在args里以元组的形式存放
已命名的都在kwargs里,以字典的形式存放
#方式2
d = (9,99)
e = {'1':'hello','2':'world'}
fun(1,2,3,*d,**e)
五、匿名函数
不使用def这样语句来定义函数,使用lambda来创建一个匿名函数
1.原则:用lambda关键字能够创建小型匿名函数,可以省略用def声明函数的标准步骤
2.格式
lambda[args1,args2....]:expression
sum = lambda args1,args2:args1 + args2
print(sum(10,20))
3.特点:
1.lambda只是一个表达式,比函数def声明简单
######## 2.lambda的主体也是一个表达式,而不是代码块,只能在lambda表达式中封装简单的逻辑
3.lambda函数有自己的命名空间,
且不能访问自由参数列表以外或者全局命名空间的参数
4. lambda函数能够接受任何数量的参数,只能返回一个表达式的值
4.匿名函数的应用场景
4.1.作为参数进行传递
def test(a,b,opt): #opt当做参数传递
print(a)
print(b)
print(opt(1,8)) #其实就是可以讲opt看成一个小型的函数,具体是什么函数可以用lambda去定义
#调用函数
test(10,100,lambda x,y:x+y)
4.2.作为内置函数的参数
案例:下面的数据如何排序,按照指定的name,age排序
stus = [
{"name":"zhangsan","age":18},
{"name":"wangwu","age":20},
{"name":"laowang","age":35}]
#根据名称进行排序
print(stus)
stus.sort(key=lambda y:y['name']) #这里面的y就是代表着stus,意思就是sort排列的顺利按照stus['name']
print(stus)
#根据年龄进行排序
stus.sort(key=lambda c:c['age']) #同理咯,c也是代表stus
print(stus)
六、偏函数
定义:
函数在执行时,要带上所有必要的参数进行调用。但是,有时参数可以在函数被调用之前提前获知。这种情况下,一个函数有一个或多个参数预先就能用上,以便函数能用更少的参数进行调用。
好处:
一个函数或者多个函数的参数预先就能用上,以便函数能用更少的参数进行调用
比如定义了一个函数,传了2个参数,现在调用可能只会用到部分参数,可以将它冻结起来,后面想使用时候随时解冻
例如:求两个数之和
from functools import partial
def add(a,b):
return a + b
#偏函数调用
plus = partial(add,100) #意思就是将add的第一个参数a给冻结起来,冻结成100
res = plus(9) # 由于第一个参数a被冻结为100了,那么plus(9)就代表add(100,9)
print(res)
七、变量
变量分为两类:局部变量和全局变量
1.局部变量
定义:
在函数内部定义的变量
在函数内部定义变量名称
def test():
a = 10 #a就是局部变量
print(a)
#调用函数
test()
在函数内部定义的变量–>局部变量
只能作用于当前这个函数,在其他函数里面不能使用
在多个函数里面,可以声明同名的局部变量,彼此之间不受影响
作用:给我们临时保存数据
2.全局变量
定义:在函数外面声明的变量,能够在所有函数里面使用,全局变量必须在所有使用函数的最上方
s = 100
def test():
print(s)
test()
3.全局变量和局部变量名字相同的问题
a = 200
def test():
a = 100
print(a)
a = 300
print(a)
#调用函数
test() #输出的是100,300
说明首先局部找->全局找->报错
4.修改全局变量
global关键字
语法格式:global 修改变量名
x = 10
def test():
global x
x = 1010
print(x)
#调用函数
test() #1010
def test2():
print(x)
test2() #1010
可以看到在test函数里已经把全局变量X的指给改变了
5.函数使用外层的变量
nonlocal:使用函数的外层变量
def test():
num = 2
def test2():
nonlocal num #这样外层的num=2就可以使用了
num *= 2
print(num)
return test2()
#调用函数
test()
6.可变类型的全局变量
当不可变的数据类型作为全局变量,需要用global声明,进行修改
可变的数据类型 不一定
以列表为例
li = []
def test():
li.append(1)
print(li)
test() #[1]
print(li) #[1]
但是以下如此又不会改变全局变量
li3 = []
def test3():
# global li3
li3 = [1,3,5]
print(li3)
#调用函数
test3() #[1,3,5]
print(li3) #[]
所以我建议要是想在函数里改变全局变量的话最好加个global
7.不可变类型的全局变量
直接来例子啦
#以数字为例
a = 0
def test():
a = a+1
print(a)
test() #!
print(a) #0
可见 不可变类型在函数里改变但在全局里是不可改变的噢
八、装饰器
装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
例如
#定义一个普通函数
def foo2():
print('foo2')
foo2 = lambda x:x+1
print(foo2(5)) # 6
简单的装饰器
def fun():
print('haha')
def fun2(num):
def fun3():
print('heihei')
num()
return fun3
#调用装饰器
f = fun2(fun) #返回的f也是一个函数
f() # heihei haha
装饰器的作用:
在不修改原函数代码的前提下,增加额外的功能,返回的也是一个函数对象(函数中的函数)
from time import ctime
def timeFun(fun):
def wrapped(): #fun->foo->黑墙->wrapped->白墙
print('%s called at %s'%(fun.__name__,ctime()))
fun()
return wrapped
def foo3():
print ('i am foo3')
#调用函数
# foo3()
f = timeFun(foo3)
f()