装饰器相关知识

装饰器的相关知识点
1. 装饰器的原理及为什么要用装饰器
装饰器原理:在不修改源代码,不修改调用方式的基础上扩展新功能
 
开放封闭原则:软件一旦上线后,就应该遵循开放封闭原则,即对修改源代码是封闭的,对功能的扩展是开放的。也就是说我们必须找到一种解决方案:能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能。
 
1. 装饰器的基本用法
def outer(func):
   def inner(*args,**kwargs):
       res=func(*args,**kwargs)
       return res
   return inner
 
1. 带参数的装饰器
再包上一层,函数的参数可以为一个,也可为多个
def auth(engine):
   def auth2(func):
       def wrapper(*args,**kwargs):
           if engine=='file':
                if current_user['username']:
                    print('login already')
                    res=func(*args,**kwargs)
                    return res
                uname=input('username>>: ').strip()
                pwd=input('password>>: ').strip()
                if uname=='egon' and pwd=='123':
                   print('login successfully')
                   current_user['username']=uname
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('wrong username or password')
           elif engine=='mysql':
                print('based on mysql')
           elif engine=='idap':
                print('based on ldap')
       return wrapper
   return auth2
 
@auth('mysql')
def f():
   pass
 
f()
 
1. 被装饰的函数有返回值怎么处理
res=func(*args,**kwargs)
return res
 
1. 多个装饰器的执行顺序
叠加多个装饰器,上面的装饰器的作用为: 下方装饰器+原函数

装饰器函数的执行顺序是分为定义阶段和执行阶段的,装饰器函数在被装饰函数定义好后立即执行

  • 在函数定义阶段:执行顺序是从最靠近函数的装饰器开始,自内而外的执行
  • 在函数执行阶段:执行顺序由外而内,一层层执行


 
6. 装饰类的装饰器
@classmethod
将被装饰的函数变成绑定给类的方法;应该由类来调用,会主动将类作为第一个参数传入
 
@staticmethod
将被装饰的函数变成非绑定方法;既不跟类绑定,也不跟对象绑定,这意味着谁都能用;谁来用都是一个普通函数,也就是说没有自动传值的特性了
 
7、 装饰器修复技术
from functools import wraps   (强烈推荐写上这一行)
def wrapper(func):
# 装饰器修复技术
    @wraps(func)
    def inner(*args, **kwargs):
        print("start")
        ret = func(*args, **kwargs)
        print("end")
        return ret
    return inner
 
@wrapper
def f(*args, **kwargs):
    """
    这是一个测试装饰器的函数,没什么其他的用法
    :param args:
    :param kwargs:
    :return:
    """
    print("2018-06-04")
 
f()
print(f.__doc__)   # 如果不加装饰器的修复技术,打出的inner函数的__doc__
print(f.__name__)  # 如果不修复,打出的是inner

原文地址:https://www.cnblogs.com/maojiang/p/9135547.html