首选了解函数的使用应该分为两个明确的阶段:
1、定义阶段:只检测语法,不执行函数体代码
2、调用阶段:会触发函数体代码的执行
先定义后调用 # 示范一 # def foo(): # print('from foo') # bar() # foo() 错误 # # 示范二: # def bar(): # print('from bar') # # def foo(): # print('from foo') # bar() # # foo() 正确 # # 示范三: # def foo(): # print('from foo') # bar() # # def bar(): # print('from bar') # # foo() 正确 # 示范四: def foo(): print('from foo') bar() foo() def bar(): print('from bar') 错误
一、函数的定义三种形式:
1、有参函数:
def func(x): print(x)
2、无参函数
def func(): print('无参函数')
3、空函数
def func(): pass
一般用来写代码时框架
二、函数调用的三种形式
1、语句形式:单纯的使用函数,不需要拿到返回值进一步处理
2、表达式:拿到返回值进一步处理
3、将函数的调用当做参数传给另一个函数
def max2(x,y): if x > y: return x else: return y res = max2(max2(10, 20), 30) print(res)
三、return值
# 注意点:
# 1. 函数的返回值没有类型限制
# 2. 函数的返回值没有个数限制
# 2.1 返回多个值: 多个返回值用逗号分隔开,返回的是元组形式
# def func():
# print('from func')
# return 1,1.1,'hello',[1,2,3]
#
# res=func()
# print(res,type(res))
# 2.2 返回1个值: 返回的就是该值本身
# def func():
# return 123
# res=func()
# print(res,type(res))
# 2.3 返回0个值或者干脆没有return: 返回None
# def func():
# return
# pass
# res=func()
# print(res)
# return除了有返回值的功能,还有结束函数执行的的功能
# 函数内可以有多个return,但只要执行一次,整个函数就立即结束,并且将return后的值返回
四、函数的参数分类“
1、形式参数:在定义函数阶段,括号内定义的参数/变量名称为行参
2、实际参数:在调用函数阶段,括号内传入的值/变量值称为实参
ps: 在调用函数阶段会将实参(值)的值绑定给形参(变量名),这种绑定关系只在调用函数时生效,在函数执行完毕后就会解除绑定
五、函数细分
1、位置参数:
(1)位置形参:在定义阶段,按照从左到右的顺序依次定义的形参称之为位置形参
特点:但凡是按照位置定义的形参,必须被传值,多一个少一个都不行
# def func(x,y,z): # print(x,y,z) # func(1,2) 错 # func(1,2,3) 对 # func(1,2,3,4) 错
(2)位置实参:在调用阶段,按照从左到右的顺序依次传入的值称之为位置实参
特点:与形参一一对应
2、关键字实参:在调用阶段,按照Key=value的形式定义的实参称之为关键字实参
特点:key完全打乱顺序,但仍然能为指定的形参传值(总结:指名道姓的微指定的形式传值)
def func(x,y,z): print(x,y,z) # func(x=1,y=2,z=3) 关键字实参 # func(1,2,3) 位置实参 # func(z=3,y=2,x=1) 关键字实参
实参的形式可以是位置实参与关键字实参混合使用,但是必须遵循原则
# 1.位置实参必须放在关键字实参的前面
# 2.不能对同一个形参重复传值
# func(1,z=3,y=2) # func(z=3,1,y=2) #错误 # func(1,z=3,x=2,y=3) #错误
3、默认形参:在定义阶段,就已经为形参赋值,该形参称之为默认参数
特点:(1)定义阶段就已经有值意味着调用阶段可以不用传值
(2)位置形参必须放到默认形参的前面
(3)默认形参的值在函数定义阶段就已经固定死了,定义阶段之后的改动不会影响该值
# def func(x,y,z=100): # print(x,y,z) # func(10,20) # func(10,20,200)
作用:
# def register(name,age,sex='male'): # print(name,age,sex) # # register('egon',18,) # register('lxx',38,) # register('cw',48,) # register('yyh',58,) # register('alex',73,'female')
(4)默认形参的值通常应该是不可变类型
如果默认形参的值为可变类型
def add_hobby(name, x, hobbies=[]): hobbies.append(x) print('%s 的爱好有 %s' % (name, hobbies)) add_hobby('egon','read') add_hobby('wxx', 'eat', ) add_hobby('alex', 'piao')
导致上面的值会对下面的值操作有影响
修改后:
# def add_hobby(name,x,hobbies=None): # if hobbies is None: # hobbies=[] # hobbies.append(x) # print('%s 的爱好有 %s' %(name,hobbies)) # # add_hobby('egon','read',) # add_hobby('wxx','eat',) # add_hobby('alex','piao')
4、可变长参数
可变长实参:指的是在调用阶段,实参值个数是不固定的
实参无非两种形式(位置、关键字实参),对应着形参也必须有两种解决方案来分别接受溢出位置实参或者关键字实参
*————》溢出的位置实参
**————》溢出的关键字实参
# def sum2(*x): #x=(1,2,3,4,5) # res=0 # for i in x: # res+=i # return res # print(sum2(1,2,3,4,5))
4.1*的用法
在形参前加*:*会将溢出的位置实参存成元祖的形式,然后复制给*后的形参名
# def func(x,y,*z): #z=(3,4,5) # print(x,y,z) # func(1,2,3,4,5)
在实参前加*:但凡碰到实参中带*的,先将实参打散成位置实参再与形参做对应
def func(x,y,*z): # print(x,y,z) # func(1111,2222,*[1,2,3,4,5]) #func(1111,2222,1,2,3,4,5)
4.2**的用法
在形参前加**:**会将溢出的关键字实参存成字典的形式,然后复制给**后的形参名
# def func(x,y,**z): #z={'c':3,'b':2,'a':1} # print(x,y,z) # func(1,y=2,a=1,b=2,c=3)
在实参前加**:但凡碰到实参中带**的,先将实参打散成关键字实参再与形参做对应
# def func(x,y,z): # print(x,y,z) # func(1,**{'y':2,'z':3}) #func(1,z=3,y=2) # func(1,**{'a':2,'y':333,'z':3}) #func(1,a=2,y=333,z=3) # 错误
# def func(x,y,**z): # print(x,y,z) # func(**{'y':1,'x':2,'a':1111,'b':2222}) #func(y=1,x=2,a=1111,b=2222)
注意:约定俗成*args(*后面是变量名args),**kwargs(**后面是变量名kwargs)
*与**的应用:
def index(name,age,sex): print('index=====>',name,age,sex)
def wrapper(*args,**kwargs): #args=('egon',) kwargs={'sex':'male','age':18} # print(args) # print(kwargs) index(*args,**kwargs) #index(*('egon',),**{'sex':'male','age':18}) #index('egon',sex='male',age=18) # wrapper(1,2,3,4,5,a=1,b=2,c=3) wrapper('egon',sex='male',age=18)
会将wrapper函数接受的参数格式原封不动的转嫁给其内部的index函数,必须要遵循的是index的参数规则