什么是函数?
具备某一功能的工具->函数
事先准备工具的过程—>函数的定义
遇到应用场景,拿来就用---->函数的调用
- 函数分类两大类:
-
内置函数
为了方便我们的开发,针对一些简单的功能,python解释器已经为我们定义好了的函数即内置函数。对于内置函数,我们可以拿来就用而无需事先定义,如len(),sum(),max()
-
自定义函数
很明显内置函数所能提供的功能是有限的,这就需要我们自己根据需求,事先定制好我们自己的函数来实现某种功能,以后,在遇到应用场景时,调用自定义的函数即可
-
为什么要用函数?
当我们需要多次使用同一种功能时,每次都要写一次代码。对程序员来说,写重复代码永远都是一件很low的事情。如果我们重复写同样的代码会有几个问题:
- 代码冗余
- 可读性差
- 可扩展性差
如何使用函数?
-
函数使用原则:必须先定义,再调用
定义函数的语法:
def 函数名(参数1,参数2,...): """文档注释""" code1 code2 code3 .... return 返回值
调用函数的语法:
函数名(值1,值2,…)
def login(): #先定义
uname=input('请输入用户名>>: ').strip()
pwd=input('password>>: ').strip()
if uname == 'egon' and pwd == '123':
print('login successfull')
return True
else:
print('user or password error')
return False
# print(login)
login() #再调用这个函数中 不需要(值,值)
login()
def max2(x,y): #定义
# x=10
# y=20
if x > y:
return x
else:
return y
res=max2(3.1,2.3) #调用 这里就需要值了
print(res*12)
- 函数在定义阶段:只检测语法,不执行语法
也就是说,在函数的定义阶段,可以检测到语法格式错误,不能检测到代码的逻辑错误,逻辑错误在代码执行的时候会出现
- 定义函数的三种形式:
- 无参函数:应用场景仅仅只是执行一些操作,比如用户交互,打印。
def bar():
pass
- 有参函数:需要根据外部传入的参数,才能执行相应的逻辑,比如统计长度、求最大值最小值。
def func(x):
pass
func(1)
- 空函数:设计代码结构时用。
def auth():
pass
def register():
pass
def shopping():
pass
def transfer():
pass
def pay():
pass
-
调用函数的三种方式:
1.语句式:register()
2.表达式形式:3*len(‘hello’)
3.把函数调用当作另一个参数传给另一个函数:res=max2(max2(10,20),30) -
函数的返回值
注意点:
- 1.函数的返回值没有类型限制
- 2.函数的返回值没有个数限制
返回多个值:多个值之间用逗号分隔开,返回的是元组形式
def func():
print('from func')
return 1,1.1,'hello',[1,2,3]
res=func()
print(res,type(res))
返回1个值:返回的就是值本身
def func():
return 123
res=func()
print(res,type(res))
返回0个值,或者干脆没有return:返回None
def func():
return
pass
res=func()
print(res)
return的功能除了有返回值,还有结束函数执行的功能(函数内可以有多个return,但只要执行一次整个函数就立即结束,并且将return的值返回)
def func():
print(1)
return
print(2)
return
print(3)
return
func()
- 函数参数的使用
- 一:函数的参数分为两大类:
- 形式参数(形参):在定义函数阶段,括号内定义的参数\变量名称为形参
- 实际参数(实参):在调用函数阶段,括号内传入的值\变量值称为实参
- 一:函数的参数分为两大类:
#ps:在函数调用阶段会将实参的值绑定给形参,这种绑定关系只在函数调用阶段有效,在函数执行完毕之后就会解除绑定关系
def func(x,y): #x=1 y=2
# x=1
# y=2
print(x,y)
func(1,2)
print(x)
print(y)
-
-
二:细分
-
1.位置参数:
- 1.1位置形参:在定义阶段,按照从左到右的顺序依次定义的形参称为位置形参。
特点:但凡是按照位置定义的参数,必须被传值
def func(x,y,z): print(x,y,z) func(1,2) #报错 func(1,2,3) func(1,2,3,4) #报错
- 1.2位置实参:在调用阶段,按照从左到右的顺序依次传入的实参称为位置实参
特点:与位置形参一一对应
def func(x,y,z): print(x,y,z) func(2,1,3)
-
2.关键字实参:在调用阶段,按照key=value形式传值的实参称为关键字实参
特点:可以完全打乱顺序,但仍然能为指定的形参传值(总结:指名道姓的为指定的形参传值)
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) #错误
- 默认形参:在定义阶段,就已经为形参赋值,该形参称之为默认参数
特点:
- 定义阶段就已经有值意味着调用阶段可以不用传值
- 位置形参必须放到默认形参的前面
- 默认形参的值在函数定义阶段就已经固定死了,定义阶段之后的改动不会影响该值
- 默认形参的值通常应该是不可变类型
-
-
def func(x,y,z=100): #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')
def func(x,z=100,y): #会报错,默认形参后面是为默认形参
print(x,y,z)
m=10
def func(x,y,z=m):
#z=10
print(x,y,z)
m=100
func(1,2) #依然打印1,2,10 默认形参的值在函数定义阶段就已经固定死了,定义阶段之后的改动不会影响该值
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) 溢出的3,4,5以元组的形式给z
print(x,y,z)
func(1,2,3,4,5)
-
- 在实参前加*:但凡碰到实参中带*的,先将实参打散成位置实参再与形参做对应
def func(x,y,z):
print(x,y,z)
func(1,2,[3,4,5])
func(*[1,2,3,4,5]) #先打散func(1,2,3,4,5)
func(*[1,2,3]) #先打散func(1,2,3)
def func(x,y,*z): # z=(1,2,3,4,5) 1,2,3,4,5以元组的形式为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,**kwargs
def func(x,*args):
print(x)
print(args)
def func(x,**kwargs):
print(x)
print(kwargs)
-
- *与**的应用:
def index(name,age,sex):
print('index=====>',name,age,sex)
#会将wrapper函数接收的参数格式原封不动地转嫁给其内部的index函数,必须要遵循的是index的参数规则
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)
-
- 命名关键字参数:
在定义函数时,*与**之间参数称之为命名关键字参数
特点:
在调用函数时,命名关键字参数必须按照key=value的形式传值
- 命名关键字参数:
def func(x,*,y=1,z):
print(x)
print(y)
print(z)
func(1,z=2)
之后的博客不会以具体的时间来分,会一个知识点一篇,一篇大概也是一天所学的知识点,