函数就是具备某一哥功能的工具
为什么要用函数
1.程序的组织结构不清晰,可读性差
2.代码冗余
3.可扩展性差
如何用函数
函数的使用必须遵循的原则:先定义,后调用
修理工事先准备工具的过程即函数的定义
修理工遇到应用场景拿来工具就用即函数的调用
语法:
def 函数名(参数1,参数2...)
"""
文档注释
"""
code1
code2
...
return 返回值
def:定义函数的关键字
函数名:就相当于一个变量名,指向函数的内存地址
注意:函数的内存地址()就可以出发函数体内代码的执行
参数:参数是函数的调用者为函数体代码传值的媒介,在python中函数的参数无序声明类型
""" 文档注释""" :推荐写上
代码块:就是函数体功能的具体实现
return:返回值,函数体代码运行的结果
函数的使用分为两个阶段:
定义阶段:只检测语法,不执行代码
调用阶段:运行函数体代码
def foo():
xxx
print()
先定义
def foo():
print("from foo")
后调用
print(foo)
foo() # 定义时无参,意味着调用时也无需传入参数
先定义
def bar(x,y):
print(x)
print(y)
后调用
bar('a',2) ## 定义时无参,意味着调用时也必须传入参数
定义无参函数:当函数体的代码逻辑不依赖任何传入的值就能执行,就不需要定义参数
def print_msg():
print('='*50)
print('welecome.....'.center(50,' '))
print('='*50)
print_msg()
print_msg()
定义有参函数:当函数体的代码逻辑依赖于外部调用者传入的值才能执行,必须定义参数用来接收外部传入的值
def max2(x,y):
x=1
y=3
if x > y:
print(x)
else:
print(y)
max2(1,4)
def max2(x,y):
if x > y:
return x
else:
return y
res=max2(1,4)
print(res)
空函数:函数体为pass
def auth():
"""
这是一个认证功能
:return:
"""
pass
函数的功能越细越好。比如,认证可分为输入和对比
函数的调用
函数的使用必须遵循:先定义后调用的原则
注意:没事先定义函数而直接调用,就相当于引用一个不存在的变量名
定义阶段:在定义阶段只检测语法,不执行函数体代码
调用阶段:根据函数名找到函数的内存地址,然后执行函数体代码
运行以下代码,不报错,因为没有语法错误
def func():
xxx
运行以下代码,报错,因为有语法错误
def func():
print('sadfsadf'
运行以下代码,不报错,因为定义在调用之前,若将foo()前移,则报错
def bar(): #定义阶段
print('from bar')
def foo():
print('from foo')
bar()
foo() #调用阶段
调用函数的三种形式
语句形式:foo()
def func():
print('from func')
func()
表达式形式:3*len('hello')
def max2(x,y):
if x > y:
return x
else:
return y
res=max2(10,3)
print(res)
当中另外一个函数的参数:range(len('hello'))
def max2(x,y):
if x > y:
return x
else:
return y
res=max2(max2(10,3),11)
print(res)
函数的返回值
什么时候应该有返回值:函数体代码运行完毕后需要有一个返回结果给调用者
返回值没有类型限制
返回值没有个数限制
返回1个值:调用函数拿到的结果就是一个值
返回多个值:调用函数拿到的结果就是一个元组
返回0个值,或者不写return:调用函数拿到的结果就是None
return关键字:return是函数结束的标志,函数内可以有多个return,但只要执行一次,整个函数就结束
没有return,返回值为None
def func():
pass
res=func()
print(res)
return后跟一个值,返回该值本身
def func1():
return 1
res=func1()
print(res)
return可以逗号分隔,返回多个值,会返回一个元组给调用者
def func2():
return 1,2,[1,2,3] #等同于return (1,2,[1,2,3])
res=func2()
print(res)
形参与实参
形参(形式参数):指的是在定义函数时,括号内定义的参数,形参其实就变量名
实参(实际参数):指的是在调用函数时,括号内传入的值,实参其实就变量的值
x,y是形参
def func(x,y): #x=10,y=11
print(x)
print(y)
10,11是实参
func(10,11)
注意:
实参值(变量的值)与形参(变量名)的绑定关系只在函数调用时才会生效/绑定
在函数调用结束后就立刻解除绑定
位置参数
位置参数(分两种: 位置形参,位置实参)
位置即顺序,位置参参数指的就是按照从左到右的顺序依次定义的参数
在定义函数时,按照位置定义的形参,称为位置形参
def foo(x,y,z):
print(x,y,z)
注意:位置形参的特性是:在调用函数时必须为其传值,而且多一个不行,少一个也不行
在调用函数时,按照位置定义的实参,称之为位置实参
注意:位置实参会与形参一一对应
foo(1,3,2) 这里 x=1 y=3 z=2
关键字参数
什么是关键字参数:在调用函数时,按照key=value的形式定义的实参,称为关键字参数
def foo(x,y,z): #x=1,y=2,z=3
print(x,y,z)
foo(x=1,y=2,z=3)
注意:相当于指名道姓的为形参传值,意味着即便是不按照顺序定义,仍然能为指定的参数传值
foo(y=2,x=1,z=3)
在调用函数时,位置实参与关键字实参可以混合使用,但必须
1.遵循形参的规则
2.不能为同一个形参重复传值
3.位置实参必须放到关键字实参的前面
默认参数
默认参数:指的是在定义函数阶段,就已经为某个形参赋值了,改形参称之为有默认值的形参,简称默认形参
注意:
在定义阶段就已经被赋值,意味着在调用阶段可以不用为其赋值
位置形参应该放到默认形参前面
默认参数的值在函数定义阶段就已经固定死了
默认参数的值通常应该是不可变类型
def foo(x,y=2):
print(x,y)
foo(1)
foo(1,3)
foo(y=3,x=1)
def foo(y=2,x):
print(x,y)
m=10
def foo(x,y=m):
print(x,y)
m=20
foo(1)
位置形参vs默认形参
对于大多情况下传的值都不相同的,应该定义成位置形参
对于大多情况下传的值都相同的,应该定义成默认形参
def register(name,age,sex='男'):
print(name,age,sex)
register('李铁蛋',18,)
register('李银蛋',28)
register('张铜蛋',38)
register('刘卤蛋',48)
register('刘二丫',19,'女')
可变长度的参数
站在实参的角度,参数长度可变指的是在调用函数时,传入的实参值的个数不固定
而实参的定义方式无法两种:位置实参,关键字实参,对应着形参也必须有两种解决方案*与**,类分别应对溢出的位置实参与关键字实参
在形参中带*:会将调用函数时溢出位置实参保存成元组的形式,然后赋值*后的变量名
def foo(x,y,*z): #z=(3,4,5,6)
print(x,y,z)
foo(1,2,3,4,5,6)
在实参中带*: 但凡在实参中带*星的,在传值前都先将其打散成位置实参,再进行赋值
def foo(x,y,*z): #z=(3,4,5,6)
print(x,y,z)
foo(1,*[2,3,4,5,6]) # foo(1,2,3,4,5,6)
在形参中带**:会将调用函数时溢出关键字实参保存成字典的形式,然后赋值**后的变量名
def foo(x,y,**z): #z={'z':3,'a':1,'b':2}
print(x,y,z)
foo(1,y=2,a=1,b=2,c=3)
在实参中带**: 但凡在实参中带**星的,在传值前都先将其打散成关键字实参,再进行赋值
def foo(x,y,**z): #z={'a':100,'b':200}
print(x,y,z)
foo(1,**{'a':100,'b':200,'y':111}) #foo(1,b=200,a=100,y=111)
规范: 在形参中带*与**的,*后的变量名应该为args,**后跟的变量名应该时kwargs
def foo(*args,**kwargs): #args=(1,2,3,4,5) kwargs={'a':1,'b':2,'c':3}
print(args)
print(kwargs)
foo(1,2,3,4,5,a=1,b=2,c=3)
当我们想要将传给一个函数的参数格式原方不动地转嫁给其内部的一个函数,应该使用下面这种形式
def bar(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs): #args=(1,2) kwargs={'z':3}
bar(*args,**kwargs)
bar(*(1,2),**{'z':3}) #bar(1,2,z=3)
wrapper(1,2,z=3) # 虽然调用的是wrapper,但是要遵循的确是bar的参数标准
当我们想要将传给一个函数的参数格式原方不动地转嫁给其内部的一个函数,应该使用下面这种形式
def bar(x,y,z):
print(x,y,z)
def wrapper(*args,**kwargs): #args=(1,2) kwargs={'z':3}
bar(*args,**kwargs)
bar(*(1,2),**{'z':3}) #bar(1,2,z=3)
wrapper(1,2,z=3) # 虽然调用的是wrapper,但是要遵循的确是bar的参数标准
命名关键字参数: 放到*与**之间的参数称之为命名关键字参数
注意: 命名关键字参数必须按照key=value的形式传值
def foo(x,y,*args,m,n,**kwargs): #args=(3,4,5,6,7,8)
print(x,y) # 1,2
print(args) #(3,4,5,6,7,8)
print(m,n) #222,333
print(kwargs)
foo(1,2,3,4,5,6,7,8,n=333,m=222,a=1,b=2)