一、闭包
1. 作用
内部函数保存外部函数的参数
2.闭包定义
- 函数嵌套
 - 内部函数使用外部函数的参数
 - 外部函数返回了内部函数
 
3.代码格式
def func_out(num1):
    def func_inner(num2):
        num = num1+num2
        return num
    return func_inner
f = func_out(10)
print(f(1))
print(f(2))
4.内部函数修改外部函数变量
def func_out(num1):
    def func_inner(num2):
        # 这里声明num1,是外部函数变量
        nonlocal num1
        # 如果不声明nonlocal,则会创建局部变量num1
        num1 = num1 + num2
        return num1
    print(num1)
    func_inner(10)
    print(num1)
    return func_inner
func_out(10)
二、装饰器
1. 作用
- 给已有函数增加额外功能的函数,它本质上就是一个闭包函数
 - 装饰器的功能特点:
    
- 不修改已有函数的源代码
 - 不修改已有函数的调用方式
 - 给已有函数增加额外的功能
 
 
2.代码实现
def check(f):
	def inner():
	    print('开始验证')
	    f()
	    print('登陆成功')
	return inner
@check
def login():
    print('开始登陆!')
login()
# 注意:@check等价于 login = check(login)
3.多个装饰器,返回值和不定长参数
def check1(f):
    def inner(*args, **kwargs):
        print('校验1开始!')
        result = f(*args, **kwargs)
        print('校验1结束!')
        return result
    return inner
def check2(f):
    def inner(*args, **kwargs):
        print('校验2开始!')
        # 这里接收 不定长参数,并用result接收返回值
        result = f(*args, **kwargs)
        print('校验2结束!')
        return result
    return inner
@check1
@check2
def login(*args, **kwargs):
	# *args,**kwargs , 其中args是元组,kwargs是dict
	# */** 的作用是解包
    print(args, kwargs)
    print('开始登陆!')
    # print(*args, **kwargs)
    return
login(1,2,3, name='aaa',age=123)
# 输出结果:
# 校验1开始!
# 校验2开始!
# (1, 2, 3) {'name': 'aaa', 'age': 123}
# 开始登陆!
# 校验2结束!
# 校验1结束!
4. 装饰器传参
通过参数,使装饰器更通用(可以根据不同参数,实现不同功能)
def func(a, b):
    def logging(f):
        def inner():
            if a == '1':
                print('begin:', time.time())
                print(b)
                f()
                print('end:', time.time())
            else:
                print('---')
                f()
                print('---')
        return inner
    return logging
@func('1', '+')
def main():
    for i in range(10000):
        pass
main()
# 装饰器等价于:
# a = func('1', '+')
# main = a(main)
# main()
5.类装饰器
- 重写__init__方法
 - 重写__call__方法
 
class check():
    def __init__(self, f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print('开始校验')
        self.f()
        print('校验完成')
# 这里等价于 c = check(comment)
@check
def comment():
    print('正在评论!')
# 这里等价调用 c(), 即调用对象的__call__方法
comment()