函数,函数嵌套,装饰器,装饰器语法糖,装饰器嵌套
基本使用
盛放功能的容器,用功能时直接来调就可以,增强代码的可读性
先定义,后调用
定义函数的三种格式
有参函数,无参函数,空函数(站位)
return 返回值
可以返回一个值,可以没有返回值,没有值就返回None
return可以返回多个值,返回的类型是个元组
并且可以返回后,可以解压赋值给变量
return也可以结束函数,可以有多个return,并且用于if判断,结束函数
可以提示他传入的‘值’的类型
def foo(x:int,y:int) ->'返回值是int'#函数定义
res=x+y
print(res)
foo(10,20)#函数调用
Type hinting 类型提示功能
?
定义阶段及调用原理:
1,只检测语法,不执行代码 ,申请内存空间,把函数体放进去,然后函数名指向内存地址
2,调用函数就是,指向内存地址
函数的参数
形参:函数定义阶段,括号内指定的参数
实参:函数调用阶段,括号内传入值(变量值)
在函数调用阶段,实参可以传值给形参,函数体就可以用了
调用结束后,实参和形参解除绑定,传入的值就不存在了
?
位置形参和位置实参
位置形参:
在函数定义阶段,按照从左到右的顺序一次定义的参数,称之为位置参数
def foo(x,y,z):
print(x,y,z)
特点:必须被传值,一一对应
位置实参:
在函数调用阶段,按照从左到右的顺序一次传入的值,称之为位置实参
foo(10,20,)
特点:按照位置依次给形参赋值
?
关键字实参
在函数的调用阶段,按照key=value的格式来传值,称之为关键字实参
def foo(x,y,z):
print(x,y,z)
foo(x=1,y=2,z=3)
foo(y=2,z=3,x=1)
特点:可以打乱传值的顺序,仍能为指定的形参赋值
可以混用位置实参和关键字实参,但是位置实参必须在关键字前面
不能为同一个形参重复赋值
def foo(x,y,z):
print(X,Y,Z)
foo(10,z=30,y=20)
默认形参
在函数的定义阶段,就已经为形参赋值了,意味着在调用阶段可以不用为其传值,称之为默认形参
def foo(name,age,gender='male'):
print(name,age,gender)
register('egon',18)
register('tony',23)
register('jack',25)
resister('lili',19,'female')
可以混用位置形参和默认形参,但是默认形参必须跟在位置形参的后面
默认形参的值推荐指向不可变类型,让它为可控的形参
默认形参的值只在函数定义阶段赋值一次,如果不传值,默认为默认赋值
如果一定要默认参数为可变类型,请按照一下模式:
def resgister1(name,hobby,hobbies=None):
if hobbies is None:
hobbies=[]
hobbies.append(hobby)
print('%s的爱好是%s'%(name,hobbies))
resgister1('egon','read')
resgister1('lili','music')
?
可变长参数
*与**
在形参中带*
*会将溢出的位置实参值汇总成元组,然后赋值给紧跟其后的形参名
不能将溢出的关键字实参,赋值给*y(可变长形参)
def foo(x,*y): #()
print(x,y)
foo(1)
foo(1,2,3,4,5,6)
?
在形参中带**
会将溢出的关键字实参汇总成字典,然后赋值给紧跟其后的形参名
def foo(x,**y):
print(x,y)
foo(1,a=111,c=555,b=666)
?
?
在实参中带*
def foo(x,z,y)
print(x,z,y)
foo(*[11,22,33])#相当于for循环遍历,注意在实参中加*后的参数,能被for循环遍历的猜可以加
在实参中带**
def foo(x,z,y)
print(x,z,y)
foo(**{'x':1,'z':3},'y':2)
带**的实参只能是字典
?
def wrapper(*args,**kwargs) #不过穿什么进去,都会原封不动的传给index函数
index(*args,**kwargs)
函数对象
函数是第一类对象,函数是第一公民
1 函数可以被赋值(函数的内存地址)
def func(aaa)
print(aaa)
res=func
res()
?
2 函数可以当做参数传给函数
def foo():
print('from foo')
?
f=foo #注意不要加括号,我们是把函数的地址给了f 而不是调用它
?
def func(f)
f()
func(fo)
3 函数可以当做函数的返回值
def foo():
print('from foo')
?
f = foo # 注意不要加括号,我们是把函数的地址给了f 而不是调用它
?
def func(x):
return x #函数可以当做函数的返回值
func(foo)
4 函数可以当做容器类型的元素
def foo()
print('from foo')
?
l=[foo]
l[0]()
?
?
5 非常优雅的处理if判断
dic={
'1':['登入',login],
'2':['注册',resister],
'3':['体现',withdeaw],
'4':['转账',transfer],
'5':['购物',shopping],
'6':['充值',recharge]
}
while True:
print('0 退出')
for i in dic:
print('%s %s'%(i,dic[i][0]))
choice = input('请输入编号').strip()
if choice in dic:
dic[choice][1]()
break
elif choice=='0':
break
else:
print('编号错误')
?
函数的嵌套
函数 嵌套调用:在调用过程中,该函数内部又调用了其他函数
def bar()
print('from bar')
def foo()
print('from foo')
bar()
foo()
用于比较最大值
在编写大功能的时候,里面可以嵌套一些小功能,来实现的我们的大功能
函数嵌套自己,实现循环
函数嵌套定义:在函数内又定义了其他函数--------封闭效果
?
def foo()
def bar():
print('小虎')
bar()
foo()
?
bar() #不能在函数外调用在函数内定义的函数,如果想打破限制,想在函数调用,必须将它的内存地址return 出来,注意我们是想在外层调用,而不是直接调用
def foo()
x=10
def bar():
print('小虎')
return bar
res=foo()
名称空间与作用域
名称空间Namespace:存放名字与内存地址的绑定关系
内置名称空间
放的python自带的名字
生命周期:解释器启动产生,解释器关闭则销毁
全局名称空间
放的顶级的名字
生命周期:运行python文件则立即产生,文件运行完毕则结束
局部名称空间
放的函数内的名字
生命周期,函数调用则产生,函数调用完毕则销毁
?
名字的查找优先级:
局部》全局》内置
基于自己当前所在的位置向外查找: L E G B 行业黑话
重要结论:名称空间是在函数定义阶段为准生成的,与调用无关
global 局部变全局,声明我这是全局名称
x=100
def foo():
global x
x=200
print(x)
foo() #200
print(x)#200
声明x为全局变量
?
?
?
?
在局部修改全局变量
X=[111,222,333]
def foo():
X.append(444)
foo()
print(x)# [111,222,333,444]
nonlocal
def foo():
x = 10
def func():
nonlocal x
x = 30
print(x)
foo() #30
声明 x 为外层的名称(变量)如果外层没有,将报错!
总结:
全部作用域:全局存活,全局有效
内置名称空间,全局名称空间
局部作用域:临时存活,局部有效
局部名称空间,函数内的空间
闭包函数
闭包函数=函数对象+函数嵌套定义+名称空间与作用域
闭函数:定义在函数内部的函数‘
包函数:该内部函数引用了一个外层函数的名字
def foo(x):
def wrapper():
print(x)
return wrapper
f=foo(111)
f()
def xxx():
x=222
f()
xxx()
在调用闭包函数它访问的永远是它外层的名称
闭包的函数的作用:闭包函数是一种为函数传参的方案
def outter():
X=111
def wrapper():
print(x)
return wrapper #千万不要加括号,我们是把它扔出来,而不是调用它
wrapper=uotter()
wrapper()
?
更进一步的处理
def outter(x):
def wrapper():
print(x)
return wrapper #千万不要加括号,我们是把它扔出来,而不是调用它
wrapper=uotter(111)
wrapper()
?
毕竟还是自己写的
def foo(x):
def werapper():
print(x)
return werapper
werapper=foo(100)
werapper()
'''当一个函数不能在添加形参的时候,而我们还需要给一个函数传值
,只能用函数的嵌套,让他先成为闭包函数(可以引用外层的名字),
再使用return把它仍出来,重新赋值给它原来的名字,让他看起来还是全局函数,并且可以为其传值'''
装饰器
什么是装饰器?
用来为被装饰者添加功能的工具
被装饰者:函数
装饰器:可以用函数实现装饰器这种工具
也就是说该函数可以为其他函数添加额外的功能
为什么要用装饰器?
不改动被装饰者的源代码及调用方式的前提下
为被装饰着添加上新功能
实现为一个函数添加运行时间 并且不修改源代码 并且不能修改函数的调用方式
?
import
def index(x)
print('welcome to index page %s'%x)
time.sleep(3)
方案一
import time
def index(x)
res=time.time()
print('welcome to index page %s'%x)
time.time
res1=time.time()
print(res1-res)
index(111)
#虽然我们实现了查看代码的运行时间新功能,但是修改了源代码,否定
?
方案二
import time
def index(x)
print('welcome to index page %s'%x)
time.sleep(3)
res=time.time ()
index(111)
res1=time.time
print(res1-res)
#虽然实现了不动源代码,实现了查看代码运行时间,但是我们以后要在不同的时间段,还要使用该函数,难道要一直复制吗?代码冗余,是对程序员的侮辱,方案二 否定
?
?
方案三
如果我们不让代码冗余,只有一种方案,就是函数
import time
def wrapper(funk)
res=time.time ()
index(111) > @1funk()
res1=time.time()
print(res1-res)
#但是这样我们的查看代码运行时间,只能给index用,这样就函数死了
#我们需要把它写活
#调用index的函数就必须得是一个变量(@1)了,我们通过后续在使用时,直接穿其他函数也能使用该功能
#那么此时的wrapper()函数就需要传值了
#形参传值
wrapper(index)直接传参
#实现了代码不冗余,也没有修改源代码,但是我index是直接可以调用的,你现在告诉我要修改,它的调用方式,这是不行的,但是它解决了代码的冗余问题,我们还需要使用该方案,实现在调用它,不需要修改调用方式
那么直接传参,就不适合了,要通过闭包函数,包给它
?
方案四
?
import time
def index(x)
print('welcome to index page %s'%x)
time.sleep(3)
?
?
import time
def outter(func):
def wrapper()
res=time.time()
funk(111)
res1=time.time()
print(res1-res)
return wrapper #我们的wrapper函数是全局函数,必须把它用return返回
index = outter(index)
index()
#现在我们可以直接调index了,但是你看起来像是在调index,其实你是在调wrapper,只不过是wrapper赋值给了index,但是我们之前调用index是可以传值给定义阶段的形参的,现在名字像了,还不能传值,
当一个函数需要给它的函数内的函数原封不动的传值时,*与**是最好的方案
方案5 闭包函数
import time
def index(x)
print('welcome to index page %s'%x)
time.sleep(3)
return 666
?
?
import time
def outter(func):
def wrapper(