闭包函数、装饰器
一、补充知识点
1、可调用的callable(可以加括号执行某个特定功能):函数名,类名
2、import this:查看Python之禅
二、闭包函数
1、定义
闭:定义在函数内部的函数
包:内部函数引用了外部函数作用域的名字
2、形式
1 2 3 4 5 6 7 8 | def outter(x,y): def inner(): 代码 1 代码 2 return inner res = outter( 1 , 2 ) res() |
3、作用
给函数体传参有两种方式,第一种是直接给函数体传参,第二种就是用闭包函数,它是利用外部函数给内部函数传参,这样在调用内部函数的时候,就可以不写参数。
4、举例
1 2 3 4 5 6 7 8 9 | import requests # requests是python实现的简单易用的HTTP库 def outter(url): def my_get(): response = requests.get(url) if response.status.code = = 200 : print ( len (response.text)) return my_get my_jd = outter( "https://www.jd.com" ) my_jd() |
三、装饰器
1、定义
器:就是一个工具
装饰:给被装饰对象添加新的功能
2、开放封闭原则
开放:对扩展开放
封闭:对修改封闭
3、装饰器必须遵守的两个原则
①、不改变被装饰对象源代码
②、不改变被装饰对象(可调用对象)调用方式
4、装饰器简单版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | """ 统计index函数执行的时间 """ import time # 导入时间模块 def index(): time.sleep( 1 ) #让程序暂停1秒,测量程序运行时间时,如果时间过短,测量时间会是0,加上延时后就可以测量 print ( '澳门最大线上赌场开业啦 性感tank在线发牌!' ) def outter(func): # func = 最原始的index函数的内存地址 def get_time(): start = time.time() func() # func = index函数的内存地址() 直接调用 end = time.time() print ( 'index run time:%s' % (end - start)) return get_time index = outter(index) # outter(最原始的index函数内存地址) # index指向get_time函数的内存地址 index() |
5、装饰器升级版
解决了函数参数的问题,无参函数和有参函数都可以直接调用,可以接收任意数量的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import time def index(): time.sleep( 1 ) print ( 'from index' ) return index res = index() # from index def login(name): time.sleep( 1 ) print (name) return login res1 = login( 'egon' ) # egon def outter(func): def get_time( * args, * * kwargs): # 可以传入任意参数,放入元组和字典中 start = time.time() res = func( * args, * * kwargs) # 将元组和字典打散,将参数原封不动的传给func函数 end = time.time() print (end - start) return res return get_time index = outter(index) login = outter(login) index() # from index # 1.0002615451812744 # 此时的index()已经多了计时功能 login( 'egon' ) # egon # 1.0002918243408203 # 此时的login()已经多了计时功能 print (res) # <function index at 0x00DFA660> print (res1) # <function login at 0x028435D0> print (index) # <function outter.<locals>.get_time at 0x028436F0> print (login) # <function outter.<locals>.get_time at 0x02843660> |
6、装饰器语法糖
①、形式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | import time def outter(func): def get_time( * args, * * kwargs): start = time.time() res = func( * args, * * kwargs) end = time.time() print ( 'func run time:%s' % (end - start)) return res return get_time @outter def index(): time.sleep( 1 ) print ( '澳门最大线上赌场开业了!' ) return 'index' @outter def login(name): time.sleep( 1 ) print ( '%s is sb' % name) return 'login' @outter def home( * args, * * kwargs): time.sleep( 1 ) return 'home' res = index() res1 = login( 'egon' ) res2 = home() print (res, res1, res2) # 输出 澳门最大线上赌场开业了! func run time: 1.0009095668792725 egon is sb func run time: 1.0010344982147217 func run time: 1.0009922981262207 index login home |
②、作用
书写代码的时候省去了login = outter(login),index = outter(index),home = outter(home)这三行代码,因为@outter自动帮你做了这件事,它会将下面最靠近它的函数的函数名当做参数传入outter()函数,并将返回值(内部函数的函数名)赋值给与该函数名同名的变量名,虽然这个地方并未出现函数名加括号,实际上已经调用了outter函数,如果outter函数内部除了定义新函数外还有打印操作,此时运行函数就会打印出内容。
③、书写规范
语法糖在书写的时候应该与被装饰对象紧紧挨着,两者之间不要有空格。
7、多层装饰器
①、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | import time user_dic = { 'is_login' : None } def outter(func): def get_time( * args, * * kwargs): start = time.time() res = func( * args, * * kwargs) end = time.time() print ( 'func run time:%s' % (end - start)) return res return get_time def login_auth2(data_source,x,t): def login_auth(func): def inner( * args, * * kwargs): if user_dic[ 'is_login' ]: res = func( * args, * * kwargs) return res else : if data_source = = 'file' : username = input ( 'please input your username:' ) password = input ( 'please input your password:' ) if username = = 'jason' and password = = '123' : user_dic[ 'is_login' ] = True res = func( * args, * * kwargs) return res else : print ( 'username or password error' ) elif data_source = = 'MySQL' : print ( 'from MySQL' ) elif data_source = = 'ldap' : print ( 'ldap' ) else : print ( '暂无该数据来源' ) return inner return login_auth @login_auth2 ( 'file' , 1 , 2 ) # 这一步相当于 # res = login_auth2('file',1,2) # 这里的res就是login_auth2()的返回值login_auth # @res @outter def index(): time.sleep( 1 ) print ( 'index' ) return 'index' index() # 装饰器在装饰的时候,顺序从下往上 # 装饰器在执行的时候,顺序从上往下 # 这里就实现了给index函数增加了两个功能:计时和认证 # 这里的认证函数是三层嵌套的,最外层函数的作用就是给里层函数传参 |
②、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | def outter1(func1): print ( '加载了outter1' ) def wrapper1( * args, * * kwargs): print ( '执行了wrapper1' ) res1 = func1( * args, * * kwargs) return res1 return wrapper1 def outter2(func2): print ( '加载了outter2' ) def wrapper2( * args, * * kwargs): print ( '执行了wrapper2' ) res2 = func2( * args, * * kwargs) return res2 return wrapper2 def outter3(func3): print ( '加载了outter3' ) def wrapper3( * args, * * kwargs): print ( '执行了wrapper3' ) res3 = func3( * args, * * kwargs) return res3 return wrapper3 @outter1 @outter2 @outter3 def index(): print ( 'from index' ) index() # 输出 # 加载了outter3 # 加载了outter2 # 加载了outter1 # 执行了wrapper1 # 执行了wrapper2 # 执行了wrapper3 # from index |
8、装饰器修复技术
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | from functools import wraps def outter(func): @wraps (func) def inner( * args, * * kwargs): """ 我是inner函数 :param args: :param kwargs: :return: """ print ( '执行被装饰函数之前,你可以执行的操作' ) res = func( * args, * * kwargs) print ( '执行被装饰函数之后,你可以执行的操作' ) return res return inner @outter def index(): """ 这是index函数 :return: """ print ( 'from index' ) print (index) # <function index at 0x037646F0> print ( help (index)) # Help on function index in module __main__: # # index() # 这是index函数 # :return: # # None print (index.__name__) # index index() # 执行被装饰函数之前,你可以执行的操作 # from index # 执行被装饰函数之后,你可以执行的操作 # 无论是打印index的函数名,还是查看函数的注释,还是查看函数名字的字符串形式,都与原来的index函数一样 |
9、装饰器模板
①、无参装饰器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | from functools import wraps def outter(func): @wraps (func) def inner( * args, * * kwargs): # * **在形参中使用 # 执行被装饰函数之前你可以做的操作 res = func( * args, * * kwargs) # * **在实参中使用 # 执行被装饰函数之后你可以做到操作 return res return inner @outter def index(username, * args, * * kwargs): """index注释""" pass print (index) |
②、有参装饰器
1 2 3 4 5 6 7 8 9 10 11 | def wrappers(data): # data = 'file' def outter(func): def inner( * args, * * kwargs): if data = = 'file' : # 执行被装饰函数之前你可以做的操作 res = func( * args, * * kwargs) # * **在实参中使用 # 执行被装饰函数之后你可以做到操作 return res return inner return outter |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步