首页 > 其他 > 详细

装饰器

时间:2020-03-23 19:41:34      阅读:62      评论:0      收藏:0      [点我收藏+]

装饰器

1 装饰器的定义

器指的是工具,函数就是一种工具
装饰指的是为其他事物添加额外的东西点缀

装饰器:
装饰器指的定义一个函数,该函数是用来为其他函数添加额外的功能

2 装饰器的作用

首先我们要明白一个原则

开放封闭原则
开放:指的是对拓展功能是开放的
封闭:指的是对修改源代码是封闭的

我们对代码进行更新时应该尽量满足开放封闭原则,

即尽量在不修改函数中的源代码,不改变函数的调用方式的状态下增加代码的功能

装饰器的作用就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能

3 装饰器的组成

装饰器是参数,函数,函数的嵌套定义,函数对象,名称空间和作用域,闭包函数等概念组合起来形成的一种产物

3.1必备知识

3.1.1 参数*args, **kwargs

如何将传入一个函数的任意个任意形态的实参原封不动地传给另一个函数

便是通过*args与**kwargs在形参位置和实参位置的不同作用完成的

def index(x,y):
    print(x,y)
def wrapper(*args,**kwargs):
    index(*args,**kwargs) # 最终传参为index(y=222,x=111)
wrapper(y=222,x=111)

3.1.2 名称空间与作用域

闭包中特殊的变量与名称空间的关系:

名称空间的的"嵌套"关系是在函数定义阶段,即检测语法的时候确定的

即需要调用的变量在定义阶段就确定了取变量的名称空间的顺序(不会确定值)

3.1.3 函数对象

函数可以被当做参数传入

函数可以当做返回值返回

def index():
    return 123

def foo(func):
    return func

print(foo(index))

3.1.4 函数的嵌套定义

def outter(func):
    def wrapper():
        pass
    return wrapper

3.1.5 传参的方式

传参的方式一:通过参数的形式为函数体传值

def wrapper(x):
    print(1)
    print(2)
    print(3)
    print(x)

wrapper(1)
wrapper(2)
wrapper(3)

传参的方式二:通过闭包的方式为函数体传值

def outter(x):
    def wrapper():
        print(1)
        print(2)
        print(3)
        print(x)
    return wrapper # return outter内的wrapper那个函数的内地址

f1=outter(1)
f1()
f2=outter(2)
f2()
f3=outter(3)
f3()

3.2 装饰器的主体

装饰器的主体是由闭包函数组成的

def outter():
    x=111
    def wrapper():
        print(x)
    return wrapper

f=outter()  # 此处f可以为任何名字,包括wrapper=outter()
f()			# wrapper(),这个与原函数同名,但是互不影响,这是名称空间的特性
# f为全局空间中的名字,而wrapper为局部空间中的名字

4 装饰器的使用

需求:在不修改index函数的源代码以及调用方式的前提下为其添加统计运行时间的功能

def index(x,y):
    time.sleep(3)
    print(‘index %s %s‘ %(x,y))

index(111,222)
index(y=111,x=222)
index(111,y=222)

解决方案一:失败
问题:没有修改被装饰对象的调用方式,但是修改了其源代码

import time

def index(x,y):
    start=time.time()
    time.sleep(3)
    print(‘index %s %s‘ %(x,y))
    stop = time.time()
    print(stop - start)

index(111,222)

解决方案二:失败
问题:没有修改被装饰对象的调用方式,也没有修改了其源代码,

? 并且加上了新功能,但是代码冗余(重复代码)

import time

def index(x,y):
    time.sleep(3)
    print(‘index %s %s‘ %(x,y))

start=time.time()
index(111,222)
stop=time.time()
print(stop - start)



start=time.time()
index(111,222)
stop=time.time()
print(stop - start)


start=time.time()
index(111,222)
stop=time.time()
print(stop - start)

解决方案三:失败
问题:解决了方案二代码冗余问题,但带来一个新问题即函数的调用方式改变了

import time

def index(x,y):
    time.sleep(3)
    print(‘index %s %s‘ %(x,y))

def wrapper():
    start=time.time()
    index(111,222)
    stop=time.time()
    print(stop - start)

wrapper()

方案三的优化一:将index的参数写活了

import time

def index(x,y,z):
    time.sleep(3)
    print(‘index %s %s %s‘ %(x,y,z))

def wrapper(*args,**kwargs):
    start=time.time()
    index(*args,**kwargs) # index(3333,z=5555,y=44444)
    stop=time.time()
    print(stop - start)

wrapper(3333,4444,5555)
wrapper(3333,z=5555,y=44444)

方案三的优化二:在优化一的基础上把被装饰对象写活了,原来只能装饰index

import time

def index(x,y,z):
    time.sleep(3)
    print(‘index %s %s %s‘ %(x,y,z))

def home(name):
    time.sleep(2)
    print(‘welcome %s to home page‘ %name)


def outter(func):
    # func = index的内存地址
    def wrapper(*args,**kwargs):
        start=time.time()
        func(*args,**kwargs) # index的内存地址()
        stop=time.time()
        print(stop - start)
    return wrapper

index=outter(index) # index=wrapper的内存地址
index()

home=outter(home) # home=wrapper的内存地址
home(‘egon‘)
home(name=‘egon‘)

方案三的优化三:将wrapper做的跟被装饰对象一模一样,以假乱真

import time

def index(x,y,z):
    time.sleep(3)
    print(‘index %s %s %s‘ %(x,y,z))

def home(name):
    time.sleep(2)
    print(‘welcome %s to home page‘ %name)

def outter(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print(stop - start)
        return res
    return wrapper
# 偷梁换柱:home这个名字指向的wrapper函数的内存地址
home=outter(home)

res=home(‘egon‘) # res=wrapper(‘egon‘)
print(‘返回值--》‘,res)

5 语法糖

在函数定义上一行写@+装饰器名字,便能省去func=wrapper(func)这一步

import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)
        stop=time.time()
        print(stop - start)
        return res
    return wrapper


# 在被装饰对象正上方的单独一行写@装饰器名字
@timmer # index=timmer(index)
def index(x,y,z):
    time.sleep(3)
    print(‘index %s %s %s‘ %(x,y,z))

@timmer # home=timmer(ome)
def home(name):
    time.sleep(2)
    print(‘welcome %s to home page‘ %name)


index(x=1,y=2,z=3)
home(‘egon‘)

6 无参装饰器模板

无参装饰器可以直接在无参装饰器模板中添加要增加的功能,完成装饰器

def outter(func):
    def wrapper(*args,**kwargs):
        # 1、调用原函数
        # 2、为其增加新功能
        res=func(*args,**kwargs)
        return res
    return wrapper
def auth(func):
    def wrapper(*args,**kwargs):
        # 1、调用原函数
        # 2、为其增加新功能
        name=input(‘your name>>: ‘).strip()
        pwd=input(‘your password>>: ‘).strip()
        if name == ‘egon‘ and pwd == ‘123‘:
            res=func(*args,**kwargs)
            return res
        else:
            print(‘账号密码错误‘)
    return wrapper

@auth
def index():
    print(‘from index‘)

index()

1

装饰器

原文:https://www.cnblogs.com/achai222/p/12554256.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!