闭包和装饰器
闭包函数
闭包如何产生的?
因为函数内部又有嵌套函数,
嵌套函数定义:定义在内部的函数无法在全局被调用
所以产生了闭包问题
def func1() def func2() a = 1 return a func2()
闭包产生的问题?
就是func1 拿不到func2 的变量a
怎么才能拿到呢?
我们知道,函数是第一类对象(第一类对象说白了你可以把函数当成变量使用),你可以把func1中的变量(func2)通过return返回
def func1() def func2() a = 1 return a return func2 x = func1() #这样就拿到了func2 并赋值给了变量x x() # x()等同于 func2() 看明白了吧 就得到了一个返回值a 这样就拿到func2 的变量a了
而如果:
def func1(para1) para1 def func2() a = 1 return para1 + a return func2 func1(5) #如果把5传给func1 就会把def func2 这个函数打包,
注意内部函数:
def func2() a = 1 return 5 + a
func1(5)() #等同于func2()
就变相调用函数func2() 得到返回值 6
print(func1(5)()) # 6
如果func1(8), 那么func2打包后:
def func2() a = 1 return 8 + a
每次调用func1,就会返回(打包)一个新的闭包实例
所以:
闭包 = 函数 + 引用环境
闭包:python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
装饰器
装饰器函数:
装饰器函数本质 就是闭包的一种应用
装饰器功能目的 就是实现 不修改原函数及其调用方式的情况下对原函数功能进行扩展
def timmer(func): def inner(): print(1) func() #内部函数引用外部函数的参数变量 产生闭包函数 print(2) return inner def func(): print('hello') timmer(func) #得到 inner函数名 f = timmer(func) # f = inner f() # inner() # 1 # hello # 2
应用中涉及到的函数:
被装饰函数
装饰函数
内嵌包装函数
装饰器书写格式:
def wrapper(func): ------------装饰函数 def inner(*args,**kwargs): ------------内嵌包装函数 #功能添加(被装饰函数执行之前扩展的功能代码)(把这两行功能添加代码注释掉,等于去掉所有的装饰器) ret = func(*args,**kwargs) #功能添加(被装饰函数执行之后扩展的功能代码) return ret return inner
使用:
@wrapper #@wrapper 语法糖 等价于 func = wrapper(func) def func(): # 被装饰函数 return 1111 #带返回
装饰器 开放封闭原则:
1.对 扩展 开放 允许代码扩展、添加新功能。(修复 bug)
2.对 修改 封闭 修改函数,有可能牵一发动全身
小示例:一次登录,处处使用
flag = True def login(args): def inner(): global flag if flag: #第一次调用函数,进入登录,要输入用户名和密码 如果第一次调用函数用户名密码正确, flag为False,不用进入登录 username = input("Please enter your user name:") pwd = input("Please enter your password:") if username == 'kitty' and pwd == '123': print("Login successfully!") flag = False #用户名密码正确,就把条件改变, if not flag: #如果flag发生变化,说明登录成功,否则,就进不去if语句,执行不了args() args() return inner @login #语法糖 def article(): print("Welcome to article!") @login def diary(): print("Welcome to diary!") article() diary() #Please enter your user name:kitty # Please enter your password:123 # Login successfully! # Welcome to article! # Welcome to diary!
小示例:写日志
"%s"%函数名.__name__ #函数的格式化输出 def log(func): def inner(): print(1) ret = func() with open('log_track','a',encoding='utf-8') as f: #打开日志文件,没有就创建一个新文件 f.write('\nlog:%s'%func.__name__) #把函数名字写入日志文件 (%func.__name__)双下划綫 return ret return inner @log def f1(): print("flowers") @log def f2(): print("book") f1() f2() # 1 # flowers # 1 # book log文件: #log:f1 #日志文件 #log:f2
使用装饰器计算代码运行时间
import time print(time.time()) #1970年1月1日00:00:00:000开始计秒 def timer(func): def inner(): start_time = time.time() time.sleep(0.1) func() end_time = time.time() print(end_time - start_time) return inner @timer def func(): print(1111) func()
取消装饰器函数:
def outer(flag): def wrapper(func): def inner(): if flag: #falg = False 就不执行扩展功能 print("扩展功能") ret = func() if flag: ##falg = False 就不执行扩展功能 print("扩展功能") return ret return inner return wrapper @outer(False) #@outer(True) def func(): print('kitty') func()
多个装饰器装饰一个函数
def wrapper1(func): def inner(): print(111) func() print(222) return inner def wrapper2(func): def inner(): print('aaa') func() print('bbb') return inner @wrapper2 @wrapper1 def func(): print('kitty') func() aaa # 111 # kitty # 222 # bbb