Python高级语法(一)

闭包、装饰器

Posted by 新宇 on January 10, 2020

一、闭包

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. 作用

  1. 给已有函数增加额外功能的函数,它本质上就是一个闭包函数
  2. 装饰器的功能特点:
    • 不修改已有函数的源代码
    • 不修改已有函数的调用方式
    • 给已有函数增加额外的功能

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.类装饰器

  1. 重写__init__方法
  2. 重写__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()