Python之装饰器

一 装饰器

#装饰器: 闭包函数的一种应用,只不过其传递的是函数。装饰器的返回值也是一个函数对象。

#装饰器原则:
              1. 不修改被装饰对象的 源代码  
              2. 不修改被装饰对象的 调用方式

#达到的目标: 
              在遵循1和2的前提下,为被装饰对象添加新功能     

 

        

简而言之:@a 就是将 b 传递给 a(),并返回新的 b = a(b)

例:

import time


def timer(func):
    def internal(*args, **kwargs):
        start_time = time.time()
        res = func(*args, **kwargs)
        stop_time = time.time()
        print('run time is {}'.format(stop_time - start_time))
        return res

    return internal


@timer  # 相当于 test = timer(test)
def test():
    time.sleep(3)
    print('Hello World')


test()

# 结果:
'''
Hello World
run time is 3.010805606842041
'''

 

二 装饰器使用

import time

def timer(func):
    def internal(*args,**kwargs):
        start_time = time.time()
        res = func()
        stop_time = time.time()
        print('run time is {}'.format(stop_time - start_time))
        return res
    return internal

@timer
def test():
    time.sleep(3)
    print('from test')

test()
无参装饰器
def auth2(auth_type):
    def auth(func):
        def internal(*args, **kwargs):
            if auth_type == 'file':
                name = input('username:')
                pwd = input('password:')
                if name == 'tom' and pwd == '123':
                    print('Auth Success')
                    res = func(*args, **kwargs)
                    return res
                else:
                    print('Auth error')
            elif auth_type == 'sql':
                print('sql 先停停')

        return internal

    return auth


@auth2(auth_type='file')
def index():
    print('Hello')


index()
有参装饰器

 

三 wrapper返回的不是原函数的帮助信息

    当我们使用了装饰器的时候,虽然没有修改代码本身,但是在运行的时候,比如上面这个例子,运行index其实在运行internal了,如果我们打印my_index的注释信息,会打印internal的注释信息,那么该如何处理?

 

def deco(func):
    def wrapper(*args, **kwargs):
        """世界那么大"""
        return func(*args, **kwargs)

    return wrapper


@deco
def index():
    '''Hello World'''
    print('from index')


print(index.__doc__)

""" 世界那么大 #并不是想要的 """

 

 

解决方法:

# 方式一

from functools import wraps

def deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """世界那么大"""
        return func(*args,**kwargs)

    return wrapper


@deco
def index():
    """Hello World"""
    print('from index')


print(index.__doc__)

"""
Hello World
"""


#方式二

def deco(func):
    def wrapper(*args, **kwargs):
        """世界那么大"""
        return func(*args, **kwargs)

    wrapper.__doc__ = func.__doc__
    wrapper.__name__ = func.__name__
    return wrapper


@deco
def index():
    '''Hello World'''
    print('from index')


print(index.__doc__)
View Code

 

 

四. 叠加多个装饰器

加载和执行:
   1. 加载顺序(outter函数的调用顺序):自下而上
    2. 执行顺序(wrapper函数的执行顺序):自上而下

 

def outter1(func1):  # func1=wrapper2的内存地址
    print('加载了outter1')

    def wrapper1(*args, **kwargs):
        print('执行了wrapper1')
        res1 = func1(*args, **kwargs)
        return res1

    return wrapper1


def outter2(func2):  # func2=wrapper3的内存地址
    print('加载了outter2')

    def wrapper2(*args, **kwargs):
        print('执行了wrapper2')
        res2 = func2(*args, **kwargs)
        return res2

    return wrapper2


def outter3(func3):  # func3=最原始的那个index的内存地址
    print('加载了outter3')

    def wrapper3(*args, **kwargs):
        print('执行了wrapper3')
        res3 = func3(*args, **kwargs)
        return res3

    return wrapper3


@outter1  # outter1(wrapper2的内存地址)======>index=wrapper1的内存地址
@outter2  # outter2(wrapper3的内存地址)======>wrapper2的内存地址
@outter3  # outter3(最原始的那个index的内存地址)===>wrapper3的内存地址
def index():
    print('from index')


print('=======================')
index()



"""
加载了outter3
加载了outter2
加载了outter1
=======================
执行了wrapper1
执行了wrapper2
执行了wrapper3
from index
"""
示例

posted @ 2018-04-26 09:34  shadow3  阅读(120)  评论(0)    收藏  举报