闭包、装饰器

2019-07-20  本文已影响0人  xiaohan_zhang

闭包

在函数嵌套的前提下,内部函数使用了外部函数的变量,把这个内部函数成为闭包。

def func_out1():
    num1 = 10
    def func_inner(num2):
        result = num1 + num2
        print(f'result = {result}')
    return func_inner


# 闭包保存了外部函数的变量num1,执行闭包都是在num1 = 10的基础上进行计算。
func_out1()(2)  # result = 13
f = func_out1()
f(3)    # result = 14


def func_out2(num1):
    def func_inner(num2):
        result = num1 + num2
        print(f'result = {result}')
    return func_inner


f = func_out2(1)
f(1)    # result = 2
def func_out3(num1):
    def func_inner():
        # 在闭包内修改外部函数变量,需要使用nonlocal关键字修饰
        nonlocal num1
        num1 += 1

    print(f'修改前:num1 = {num1}')
    func_inner()
    print(f'修改后:num1 = {num1}')
    return func_inner


func_out3(1)()


def func_out4(num1):
    def func_inner():
        nonlocal num1
        num1 += 1
        return num1

    return func_inner


f = func_out4(10)
print(f())  # 11

装饰器

装饰器本质是一个闭包函数,可以对已有函数进行额外的功能扩展。
装饰器执行时机:
当前模块加载完成时,装饰器会立即执行,对已有函数进行装饰

  1. 不修改已有函数的源代码
  2. 不修改已有函数的调用方式
  3. 给已有函数增加额外功能
def decorator(func):    # func被装饰的目标函数
    def inner():
        '''执行函数之前'''
        func()      # 执行被装饰的目标函数
        '''执行函数之后'''
    return inner
# 装饰器语法糖用法:
@装饰器名称 修饰被装饰函数
# 如果闭包函数有且只有一个参数,并且是函数类型,那么这个闭包函数称为装饰器
def outter(func):
    def inner():
        print("登录验证")
        func()
    return inner

# 装饰器语法糖写法 等价于comment = outter(comment)
@outter
def comment():
    print("发表评论")


comment()
# 调用装饰器对已有函数进行装饰
# comment = outter(comment)
# comment()
"""
登录验证
发表评论
"""
  1. 装饰有参数的函数
def decorator_add(func):
    def inner(num1, num2):
        print('正在努力执行加法运算....')
        func(num1, num2)
    return inner


@decorator_add
def add_num(num1, num2):
    result = num1 + num2
    print(f'结果为:{result}')


add_num(1, 4)
"""
正在努力执行加法运算....
结果为:5
"""
  1. 装饰器带有返回值的函数
def decorator_add2(func):
    def inner(num1, num2):
        print('2正在努力执行加法运算....')
        return func(num1, num2)
    return inner

@decorator_add2
def add_num2(num1, num2):
    return num1 + num2


result = add_num2(1, 2)
print(f'有返回值函数:result = {result}')
'''
正在努力执行加法运算....
有返回值函数:result = 3
'''
  1. 装饰带有不定长参数的函数
def decorator_add3(func):
    def inner(*args, **kwargs):
        print('3正在努力执行加法运算....')
        return func(*args, **kwargs)    # 拆包
    return inner

@decorator_add3
def add_num3(*args, **kwargs):
    print("-----call_func:args =", args, ",kwargs =", kwargs)
    result = 0
    for value in args:
        result += value
    for value in kwargs.values():
        result += value
    return result


result = add_num3(1, 3)
print(f'不定长参数函数:result = {result}')
result = add_num3(1, 3, num=4)
print(f'不定长参数函数:result = {result}')
'''
3正在努力执行加法运算....
-----call_func:args = (1, 3) ,kwargs = {}
不定长参数函数:result = 4
3正在努力执行加法运算....
-----call_func:args = (1, 3) ,kwargs = {'num': 4}
不定长参数函数:result = 8
'''
  1. 通用装饰器
def decorator(func):
    def inner(*arg, **kwargs):
        print('通用装饰器')
        res = func(*arg, **kwargs)
        return res
    return inner


@decorator
def show():
    print('哈哈哈哈哈哈')


show()
  1. 多个装饰器对同一个函数装饰
"""
多个装饰器的执行过程:
由内到外装饰,先执行内部装饰器,再执行外部装饰器
"""
def make_p(func):
    print('make_p装饰器执行了')
    def inner():
        content = '<p>' + func() + '</p>'
        return content
    return inner

def make_div(func):
    print('make_div装饰器执行了')
    def inner():
        content = '<div>' + func() + '</div>'
        return content
    return inner

@make_div
@make_p
def content():
    return "装饰器使用练习"


print(content())
"""
make_p装饰器执行了
make_div装饰器执行了
<div><p>装饰器使用练习</p></div>
"""
  1. 带有参数的装饰器
    带有参数的装饰器就是使用装饰器的时候,可以传入指定参数;
    语法格式:@装饰器(参数...)
    带有参数的装饰器其实就是在装饰器外面又包了一层函数,使用该函数接收参数,返回装饰器。
def return_decorator(flag):
    def decorator(func):
        def inner(num1, num2):
            if flag == '+':
                print('正在努力执行加法运算')
            elif flag == '-':
                print('正在努力执行减法运算')
            func(num1, num2)
        return inner
    return decorator

@return_decorator('+')
def add_num(a, b):
    res = a + b
    print(res)

@return_decorator('-')
def sub_num(a, b):
    res = a - b
    print(res)


add_num(2, 5)
sub_num(5, 2)
'''
正在努力执行加法运算
7
正在努力执行减法运算
3
'''
  1. 类装饰器
class Check(object):
    def __init__(self, func):
        self._func = func

    # 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。
    def __call__(self, *args, **kwargs):
        print('添加装饰功能')
        self._func()

@Check
def show():
    print('快要下雪了')


show()
'''
添加装饰功能
快要下雪了
'''

上一篇 下一篇

猜你喜欢

热点阅读