14、闭包函数与装饰器

一、闭包函数

1、什么是闭包函数

闭函数:被封闭起来的函数,定义函数内部的函数,闭函数的特点是只能在函数内使用

包函数:该函数引用一个名字,该名字来自于e这一层

总结:闭包函数指的是定义在函数内部的函数引用了一个来自外层函数作用域中的名字

def outter():
    x = 100

    def wrapper():
        print(x)

    return wrapper


wrapper = outter()
wrapper()
# 运行结果
100

二、装饰器

1、什么是装饰器

‘装饰’是指为其他对象(被装饰对象)添加新的功能,器就是‘工具’

2、为什么要用装饰器

装饰器的作用就是遵循开放封闭原则,在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。 

开放:指的是对拓展功能是开放的

封闭:指的是对修改源代码是封闭的 

接下来让我们详细的分析一下实现装饰器的步骤吧

def index():
    time.sleep(1)
    print('我是要成为海贼王的男人')


index()
# 需求:为上面的程序添加一个显示运行时间的功能

方案一

import time  # 时间模块


def index():
    start = time.time()
    time.sleep(1)
    print('我是要成为海贼王的男人')
    stop = time.time()
    print('运行时间为:%s' %(stop - start))

index()

我们简单粗暴的为这段代码添加了显示运行时间的功能,但是也修改了源代码,不符合装饰器的封闭原则。


方案二

import time


def index():
    time.sleep(1)
    print('我是要成为海贼王的男人')


start = time.time()
index()
stop = time.time()
print('运行时间为:%s' % (stop - start))

没有修改源代码和调用方式,但如果index在很多处都要调用,那岂不是每一次都要在它上面和下面添加代码,重复编写,造成了代码冗余。


方案三

mport time


def index():
    time.sleep(1)
    print('我是要成为海贼王的男人')

def wrapper():
    start = time.time()
    index()
    stop = time.time()
    print('运行时间为:%s' % (stop - start))

wrapper()

把index写到了另外一个函数里,看似方便,可改变了调用方式,原本用index()调用,现在变成wrapper()来调用了,如果index()调用已经写在很多处怎么办呢,难道把所有index全改成wrapper吗,很显然,不行。


方案四

import time


def index():
    time.sleep(1)
    print('我是要成为海贼王的男人')


def outter(func):
    def wrapper():
        start = time.time()
        func()  # 本质上就是index()
        stop = time.time()
        print('运行时间为:%s' % (stop - start))

    return wrapper  # 返回封装好的函数内存地址


index = outter(index)  # 这里我们把实参里的index指向的内存地址给了形参的func
index()

这里,我们就基本实现装饰器的思想了,我们还可以再优化一下,更加完美。

def outter(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print('运行时间为:%s' % (stop - start))
        return res  # 万一index会有返回值呢,加上更完美
    return wrapper  # 返回封装好的函数内存地址

方案五:语法糖

import time
from functools import wraps  # 导入一个模块,可以更加完美的把装饰器伪装成被装饰函数。

# 把被装饰对象放在代码最上
def outer(func):
    @wraps(func)  # wraps模块应用
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        stop = time.time()
        print('运行时间为:%s' % (stop - start))
		return res
    return wrapper


@outer  # 语法糖,相当于index=outer(index)
def index():
    time.sleep(1)
    print('我是要成为海贼王的男人')


@outer  # 相当于home=outer(home)
def home():
    print('橡皮橡皮·火箭炮')
    time.sleep(0.8)


index()
home()

3、无参装饰器模板

# 无参装饰器标准模板
def outter(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper

4、有参装饰器模板

有参装饰器需要在无参装饰器上再套一层函数,这样才能再给内部的数据传参。

# 有参装饰器模板
def outter(x,y):
    def deco(func):
        def wrapper(*args,**kwargs):
            print(x,y)
            res = func(*args,**kwargs)
            return res
        return wrapper
    return deco


@outter(11,22)
def index():
    print('index')

index()

有参装饰器案例

def outter(engine='file'):
    def deco2(func2):
        def wrapper2(*args, **kwargs):
            if engine == 'file':
                inp_user = input('username>>>: ').strip()
                inp_pwd = input('password>>>: ').strip()
                if inp_user == 'poco' and inp_pwd == '123':
                    print("登录成功")
                    res2 = func2(*args, **kwargs)
                    return res2
                else:
                    print("登录失败")
            elif engine == "mysql":
                print("基于mysql的认证")
            elif engine == "ldap":
                print("基于ladp的认证")

        return wrapper2

    return deco2


@outter(engine='file')
def index():
    print('index功能')


index()
posted @ 2021-03-29 20:32  黑影Poco  阅读(69)  评论(0)    收藏  举报