Day04:函数参数、对象、嵌套、闭包函数和装饰器
上节课复习:
1.什么是函数
函数就是具备某一功能的工具
2.为何用函数
1.程序的组织结构和可读性
2.减少代码冗余
3.扩展性强
3.如何用函数
函数分为两大类:
内置函数:len
自定义函数: 1.有参 2.无参 3.空函数
语法:
def函数名(arg1,arg2)
'''
注释
'''
code1
code2
return 返回值
调用函数: 函数名(1,2,3)
函数必须遵循:先定义,后调用
定义阶段:只检测语法,与执行函数体代码
调用阶段:通过函数名找到函数,然后执行函数整体代码
函数名:用来访问函数的内存地址,加上括号用来执行函数
函数参数:是外调用者为函数体传值的媒介
函数体代码:是函数功能的具体实现
函数返回值是函数体执行的成果,不写return默认返回None
1.返回值没有类型限制
2.返回值没有个数限制
无return,默认返回None
return值1:返回1
return值1,2,3,:返回值(1,2,3)
return注意点:是函数结束标志,函数体内可以有多个return,但是只要执行一次return,即代表函数结束
1.函数参数的使用
2.函数对象
3.函数嵌套
4.名称空间与作用域
5.闭包函数(2+3+4)
6.装饰器
1.形参与实参
形参:定义函数时,括号内指定的参数,本质就是调用名
实参:调用函数时,括号内传入的值
只有在调用函数时才会在函数体内发生实参(值)与形参(变量名)的绑定关系
该绑定关系只在调用函数时临时生效,在调用函数结束时解除绑定
1 def foo(x,y): #括号内x,y 为形参 2 print(x) 3 print(y) 4 foo(1,2) # 括号内1,2为实参
输出:
1
2
2.位置参数:
位置形参:在定义函数时,从左往右的顺序依次定义形参称之为位置形参
注意:1.但凡是按照位置定义的形参,在调用函数时必须为其传值,多一个少一个都不行
位置实参:在调用函数时,从左往右的顺序依次传入值称之为位置实参
注意:1.在传值时按照顺序与形参一一对应
1 def foo(x,y,z): #括号内x,y,z 为形参 2 print(x) 3 print(y) 4 foo(1,2) # 括号内1,2为实参
输出:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-b10bbf76aa4f> in <module>()
2 print(x)
3 print(y)
----> 4 foo(1,2) # 括号内1,2为实参
TypeError: foo() missing 1 required positional argument: 'z'
3.关键字实参:
在调用函数时,按照key=value的形式定义的实参,称之为关键字实参
注意:1.在传值时可以完全打乱顺序,但仍然能指名道姓地指定参数的传值
2.可以在调用函数时,混用位置实参与关键字实参,但是位置实参必须在关键字实参的左边,并且不能为某个形参重复性传值
1 def foo(x,y): #括号内x,y为形参 2 print(x) 3 print(y) 4 foo(y=3,x=2) # 指定关键字实参,可打乱顺序
输出:
2
3
4.默认参数:
在定义函数时,就已经为某些参数绑定值,称之为默认参数
注意:
1.在定义阶段就已经有值,意味在调用阶段可以不用为其传值
2.默认形参必须放到位置形参的后面
3.默认形参的值只在定义阶段生效一次
4.默认形参的值通常应该是不可变类型
1 def foo(x,y,z=3): 2 print(x) 3 print(y) 4 print(z) 5 6 foo(1,2)
输出:
1
2
3
归纳对比:默认形参vs位置形参:
默认形参:大多数情况值不变
位置形参:大多数情况值都是不一样的
1 m=10 2 def foo(x,y,z=m): 3 print('x:%s' %x) 4 print('y:%s' %y) 5 print('z:%s' %z) 6 7 m=1111111 8 foo(1,2)
输出:
x:1
y:2
z:10
1 def foo(name,hobby,l=[]): 2 l.append(hobby) 3 print('%s 的爱好是 %s' % (name,l)) 4 5 foo('andy','read') 6 foo('tom','run') 7 foo('alex','sing')
输出:
andy 的爱好是 ['read']
tom 的爱好是 ['read', 'run']
alex 的爱好是 ['read', 'run', 'sing']
1 def foo(name,hobby,l=None): 2 if l is None: 3 l=[] 4 l.append(hobby) 5 print('%s 的爱好是 %s' % (name,l)) 6 l1=[] 7 foo('andy','read',l1) 8 foo('andy','music',l1) 9 foo('andy','run',l1) 10 l2=[] 11 foo('lily','run',l2) 12 l3=[] 13 foo('alex','sing',l3)
输出:
andy 的爱好是 ['read']
andy 的爱好是 ['read', 'music']
andy 的爱好是 ['read', 'music', 'run']
lily 的爱好是 ['run']
alex 的爱好是 ['sing']
5.可变长度的参数:
可变长度指的是在调用函数时,函数参数的个数可以不固定
然而实参终究是要为形参传值的,针对两种形式实参个数不固定,对应形参也必须要有两种解决方案来分别处理溢出位置实参(*)与溢出的关键字实参(**)
1 #*会将溢出的位置实参存成元组,然后赋值给紧跟其后的变量名 2 #1.1 形参中带* 3 def foo(x,y,*z): #*z=(3,4,5,6,7,8), 4 print(x) 5 print(y) 6 print(z) 7 foo(1,2,3,4,5,6,7,8)
输出:
1
2
(3, 4, 5, 6, 7, 8)
1
2
('h', 'e', 'l', 'l', 'o')
h
e
('l', 'l', 'o')
1 #1.3 实参中带*, 窍门:但凡碰到实参中带*,都先将其打散成位置实参,然后再考虑传值 2 def foo(x,y,z): 3 print(x,y,z) 4 l=['alex','tom','andy'] 5 foo(*l) #*后被打散
输出:
alex tom andy
1 #1.1 形参中带** 2 #**会将溢出的关键字实参存成字典,然后赋值给紧跟其后的变量名 3 4 def foo(x,y,m,n,**z): #**z={'a': 1, 'b': 2, 'c': 3}, 5 print(x) 6 print(y) 7 print(m) 8 print(n) 9 print(z) 10 foo(1,2,n=10,m=20,a=1,b=2,c=3)
输出:
1
2
20
10
{'a': 1, 'b': 2, 'c': 3}
1 #1.2 形参中带**,实参中带** 2 #**会将溢出的关键字实参存成字典,然后赋值给紧跟其后的变量名 3 #窍门:但凡在实参中带**,都将其打散称关键字实参,然后考虑传值 4 5 def foo(x,y,m,n,**z): #**z={'a': 1, 'b': 2, 'c': 3}, 6 print(x) 7 print(y) 8 print(m) 9 print(n) 10 print(z) 11 foo(1,2,n=10,m=20,**{'a':1,'b':2,'c':3})
输出:
1
2
20
10
{'a': 1, 'b': 2, 'c': 3}
1 def foo(x,y,m,n,**z): #**z={'a': 1, 'b': 2, 'c': 3}, 2 print(x) 3 print(y) 4 print(m) 5 print(n) 6 print(z) 7 foo(1,n=10,m=20,**{'a':1,'b':2,'c':3,'y':111})
输出:
1
111
20
10
{'a': 1, 'b': 2, 'c': 3}
1 #1.3 实参中带** 2 def foo(x,y,z): #**z={'a': 1, 'b': 2, 'c': 3}, 3 print(x) 4 print(y) 5 print(z) 6 foo(**{'x':1,'y':1,'z':2})
输出:
1
1
2
1 #如果需要将外层的函数的参数格式原封不动地转嫁给内部调用的函数,就需要用到下述方法: 2 def index(name,age,sex): 3 print('name:%s age:%s sex:%s' %(name,age,sex)) 4 5 def wrapper(*args,**kwargs): #args=(1,2,3),kwargs={'a': 10, 'b': 20, 'c': 30} 6 print(args,kwargs) 7 index(*args,**kwargs) #index(*(1,2,3),**{'a': 10, 'b': 20, 'c': 30} 8 #我们虽然调用的是wrapper函数,但是我们遵循的其实是index函数的参数规则 9 wrapper(1,2,3,a=10,b=20,c=30)
输出:
(1, 2, 3) {'a': 10, 'b': 20, 'c': 30}