第八章、函数进阶之装饰器02

第八章、函数进阶之装饰器02

一、无参装饰器

1. 什么是装饰器?

装饰器指的是为被装饰对象添加功能,因此定义装饰器就是定义一个函数,只不过是该函数是用来为其他函数添加额外的功能

注意

  • 装饰器本身是可以任意调用的对象
  • 被装饰的对象也可以是任意可调用了的对象

2. 为什么要用装饰器

装饰器的实现必须遵循两大原则

  • 不修改被装饰的源代码

  • 不修改被装饰的对象的调用方式

    装饰器就是在遵循以上两个原则的前提下被装饰对象添加功能

    #真正的装饰器
    import time
    def index():
        print('您好啊!')
        time.sleep(1)
    
    def deco(func):    # func = 原index
        '''装饰器'''
        def f1():    #重新创建后的index
            start = time.time()
            func()      #原index
            end = time.time()
            print(end-start)
        return f1
    
    index = deco(index)
    index()     #f1
    

3. 怎么用装饰器

第一种传参方式:

def index():
    print('welcome to index')
    time.sleep(1)


def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"func time is {start-end}")
    return wrapper

f = time_count(index)
f()
#index = time_count(index)  # index为被装饰函数的内存地址,即index = wrapper
#index()  # wrapper()
welcome to index
func time is -1.0008289813995361

下面方式是对第一种的再优化

第二种传参函数:包给函数——外包(指的是再定义命名为原函数的名字的变量,被赋予了原函数的内存地址,再调用被装饰后的函数名字(),以后就可以直接用原来函数的名字调用了)

import time


def index():
    print('welcome to index')
    time.sleep(1)


def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"{func} time is {start-end}")
    return wrapper

# f = time_count(index)
# f()


index = time_count(index)  # index为被装饰函数的内存地址,即index = wrapper
index()  # wrapper()
welcome to index
func time is -1.0008289813995361

4. 完善装饰器

上述的装饰器,最后调用index()(实际上是被装饰后的index())的时候,其实是在调用wrapper(),因此如果原始的index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们**需要同步原始的index()和wrapper()方法的返回值。 **具体怎么做:

import time


def index():
    print('welcome to index')
    time.sleep(1)

    return 123


def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        res = func()
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return wrapper


index = time_count(index)
res = index()
print(f"res: {res}")
#此处return就已经把原始的index的返回值接收过来了
		res = func()
        end = time.time()
        print(f"{func} time is {start-end}")

        return res

welcome to index

<function index at 0x102977620> time is -1.0050289630889893

res: 123

如果原始的home()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有timeinner()=home(),所以给timeinner()方法传参即可。

import time

def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name


def time_count(func):
    # func = 最原始的index
    def timeinner(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return timeinner


home = time_count(home)#就相当于把time_count()的函数返回值(其实是内部函数的地址)赋值给另一个变量名(其实就是被装饰后的原函数的名字)

res = home('egon')#调用了timeinner("egon")
print(f"res: {res}")

5. 装饰器语法糖

被装饰的函数正上方单独写上@装饰器名

import time


def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"{func} time is {start-end}")
    return wrapper

@time_count
def index():
    print('welcome to index')
    time.sleep(1)
welcome to index
func time is -1.000335454940796

6. 装饰器模板

#双层装饰器
def deco(func):
    def wrapper(*args,**kwargs):
        res = func(*args,**kwargs)
        return res
    return wrapper
#三层装饰器
# 三层装饰器:给双层装饰器加参数
def sanceng (engine):
    def outter(func):
        def wrapper(*args,**kwargs):  # wrapper是未来要运行的函数
            #加功能
            print(engine)
            res = func(*args,**kwargs)  #func是被装饰的函数
            return  res
        return wrapper
    return outter

@sanceng('db')
def shopping():
    print('shopping')

shopping()

二、有参函数

1. 三层闭包

# 三层装饰器:给双层装饰器加参数
def sanceng (engine):
    def outter(func):
        def wrapper(*args,**kwargs):  # wrapper是未来要运行的函数
            #加功能
            print(engine)
            res = func(*args,**kwargs)
            print(res)#func是被装饰的函数
            return  res
        return wrapper
    return outter

@sanceng('db')
def shopping(x="666"):
    print('shopping')
    return x

shopping()
db
shopping
666
posted @ 2019-08-12 17:25  得淼  阅读(134)  评论(0编辑  收藏  举报