Python之闭包函数、装饰器
1、闭包函数
#作用域关系在函数定义阶段时就已经固定死了,与调用位置无关 # 即:在任意位置调用函数都需要跑到定义函数时寻找作用域关系 # def f1(): # x=1 # def inner(): # print(x) #闭包的含义:内部函数中的变量x引用外部作用域的x,而非全局作用域的x # return inner # func=f1() #f1()=inner # # # def f2(): # x=111111 # func() #func()=inner() # f2() # 闭包函数: # 闭指的是:该函数是一个内部函数 # 包指的是:指的是该函数包含对外部作用域(非全局作用域)名字的引用 # def outter(): # x = 1 # def inner(): # print(x) #内部函数inner中的x是对外部作用域的引用,而非全局作用域的引用 # # return inner # # f=outter() # # def f2(): # x=1111111 # f() # # f2() # # # def f3(): # x=4444444444444 # f() # # f3() # 为函数传值的两种方式: # 为函数体传值的方式一:使用参数的形式 # def inner(x): # print(x) # # inner(1) # inner(1) # inner(1) # 为函数体传值的方式二:包给函数 ''' def outter(x): # x=1 def inner(): print(x) #通过闭包函数将值报给内部函数 return inner f=outter(1) f() ''' # 例子: # 方法一:通过传参的形式将值传给函数内的变量 # import requests # def get(url): # response=requests.get(url) # if response.status_code == 200: # print(response.text) # # get('https://www.baidu.com') # get('https://www.baidu.com') # get('https://www.baidu.com') # # get('https://www.python.org') # get('https://www.python.org') # get('https://www.python.org') # get('https://www.python.org') # 方法二:通过闭包函数将值包给其内部的函数 import requests def outter(url): #通过传参的形式,可以爬去任意网页的源代码 # url='https://www.baidu.com' #功能被写死,所以改成传参的形式 def get(): response=requests.get(url) #url是通过outter函数,将值包给函数get内的函数体代码用的 if response.status_code == 200: #成立说明,成功爬去网页的源代码 print(response.text) return get #返回get给外部的调用者,打破层级的限制(函数对象的知识) baidu=outter('https://www.baidu.com') #本质就是传入了参数的get的内存地址 python=outter('https://www.python.org') baidu() #本质就是已经给url传入了参数的get的内存地址,加括号即调用 baidu() python() python()
2、装饰器
''' 1、什么是装饰器 器指的是工具,而程序中的函数就具备某一功能的工具 装饰指的是为被装饰器对象添加额外功能 就目前的知识来看: 定义装饰器就是定义一个函数,只不过该函数的功能是用来为 其他函数添加额外的功能 其实: 装饰器本身其实可以是任意可调用的对象 被装饰的对象也可以是任意可调用的对象 2、为什么要用装饰器 软件的维护应该遵循开放封闭原则 开放封闭原则指的是: 软件一旦上线运行后对修改源代码是封闭的,对扩展功能的是开放的 这就用到了装饰器 装饰器的实现必须遵循两大原则: 1、不修改被装饰对象的源代码 2、不修改被装饰对象的调用方式 装饰器其实就在遵循1和2原则的前提下为被装饰对象添加新功能 3、如何用装饰器 ''' # 方式一 # 给原函数添加上了新功能,没有改变原函数的调用方式,但是却改变了源代码 import time # def index(): # start=time.time() # print('welcom to index') # time.sleep(3) # stop=time.time() # print('run time is %s' %(stop-start)) # index() # 方法二 # 没有改变源代码,也没有改变调用方式,但是给不同函数扩展相同的功能时,是在重复写代码的过程 import time # def index(): # print('welcom to index') # time.sleep(3) # # def f2(): # print('from f2') # time.sleep(2) # 以下为两个函数添加上了引得功能,但是重复写代码 # start=time.time() # index() # stop=time.time() # print('run time is %s' %(stop-start)) # # # start=time.time() # f2() # stop=time.time() # print('run time is %s' %(stop-start)) # 方法三 # 将重复写代码的过程,定义为一个函数的功能,虽然没有该源代码,但是改变了函数的调用方式 # import time # # def index(): # print('welcom to index') # time.sleep(3) # # def timmer(func): # start=time.time() # func() # stop=time.time() # print('run time is %s' %(stop-start)) # # timmer(index) # 方法四 # 利用闭包函数,为函数添加上新的功能 ''' import time def index(): print('welcom to index') time.sleep(3) def timmer(func): #func=最原始的index # func=index #这样就把被装饰的对象写死了,所以需要以传参的形式将,被装饰的函数传进来 def inner(): start=time.time() func() stop=time.time() print('run time is %s' %(stop-start)) return inner # f=timmer(index) # f() # index=timmer(被装饰函数的内存地址) index=timmer(index) #index=inner index() #inner() ''' import time def index(): print('welcom to index') time.sleep(3) def timmer(func): #将被装饰的函数传进来,不至于将被装饰的对象写死,固定是某一个,而是可以装饰任意一个函数 #func=最原始的index ,即被装饰函数的的内存地址 def wrapper(): #该函数即是为被装饰函数添加上的新功能 start=time.time() func() #最原始的index加括号即使调用最原始的函数 stop=time.time() print('run time is %s' %(stop - start)) return wrapper #函数对象知识:返回给外部函数调用,打破层级限制 index=timmer(index) #左边的index=wrapper函数的内存地址,右边的index即是我们要装饰的函数 index() #本质调用的是wrapper函数
三、装饰器修正
import time def index(): #被装饰的函数无参,有返回值 print('welcome to index') time.sleep(3) return 123 def home(name): #被装饰的函数有参,没有返回值 print('welcome %s to home page' %name) time.sleep(2) def timmer(func): #func=最原始的index def wrapper(*args,**kwargs): #wrapper会将接收的参数,原封不动的传给被装饰的函数 start=time.time() res=func(*args,**kwargs) #因为被装饰的对象可能有的有参,有的是无惨,所以调用时用*args,**kwargs,无论有无参数都不会报错 stop=time.time() print('run time is %s' %(stop - start)) return res #接收被装饰函数的返回值,被装饰的函数没有返回值则为None,有则返回被装饰的返回值 return wrapper #该返回值则是返回给外部函数用的,可以打破层级的限制,这样内部函数即给被装饰函数添加的新功能就可以被调用到 index=timmer(index) #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数 home=timmer(home) #将被装饰的函数传入,调用装饰器,本质就是调内部被加上新功能的函数 res=index() #拿到调用函数的返回值,打印即可看到返回值 home('egon') #被装饰的函数为有参,为被装饰函数进行传参 print(res) #装饰器语法糖 # 在被装饰对象正上方,并且是单独一行写上@装饰器名 # import time # def timmer(func): # #func=最原始的index # def wrapper(*args,**kwargs): # start=time.time() # res=func(*args,**kwargs) # stop=time.time() # print('run time is %s' %(stop - start)) # return res # return wrapper # # @timmer # index=timmer(index) #timmer即一个名字,所以装饰器的代码块要写在timmer的上方,@timmer本质就是调用了timmer(传入被装饰的函数名) # def index(): # print('welcome to index') # time.sleep(3) # return 123 # # @timmer # home=timmer(home) # def home(name): # print('welcome %s to home page' %name) # time.sleep(2) # # res=index() # home('egon') # 装饰器的万能模板: def deco(func): #func即是要接收的被砖石的函数名 def wrapper(*args,**kwargs): #可以根据被装饰的函数需不需要传参,给被装饰的对象传入参数 res=func(*args,**kwargs) #本质就是调用被装饰的函数, 接收传进来的参数 return res #接收被装饰函数的返回值,没有则返回None return wrapper #外部函数将内部函数的内存地址返回,打破层级限制
python之基础知识大全