7、装饰器

1、装饰器介绍与简单实现python

  1. 什么是装饰器
        器:指的是具有某一功能的工具
        装饰:指的是为被装饰器对象添加新功能

        装饰器就是用来为被装饰器对象添加新功能的工具
        注意:装饰器自己能够是任意可调用对象,被装饰器的对象也能够是任意可调用对象


    2. 为什么要用装饰器
        开放封闭原则:封闭指的是对修改封闭,对扩展开放

        装饰器的实现必须遵循两大原则:
            1. 不修改被装饰对象的源代码
            2. 不修改被装饰器对象的调用方式

        装饰器的目标:就是在遵循1和2原则的前提下为被装饰对象添加上新功能

    3. 怎么用装饰器mysql


import time
def index():
    print('welcome to index page')
    time.sleep(2)
def outter(func): # func=最原始那个index的内存地址
    def wrapper():
        start=time.time()
        func() #最原始的那个index的内存地址()
        stop=time.time()
        print('run time is %s' %(stop - start))
    return wrapper
index=outter(index) #index=outter(最原始那个index的内存地址) #index=wrapper的内存地址
index() #wrapper的内存地址()
-------------------------------------
welcome to index page
run time is 2.0003037452697754

例1:(无参装饰器)sql

import time
def outter(func):       # func=最原始那个index的内存地址
    def wrapper():
        start=time.time()
        func()          #最原始的那个index的内存地址()
        stop=time.time()
        print('run time is %s' %(stop - start))
    return wrapper
#@outter        # 语法糖 等于 但 语法格式是 index=outer(index)要写在被装饰函数的下面
def index():
    print('welcome to index page')
    time.sleep(3)
index = outter(index)    #没有语法糖的须要写在装饰器与函数下面
index()

例二、(无参装饰器)缓存

import time
def outter(func):  # func 表示的是Index 的函数当参数来用
    def wrapper(*args,**kwargs):
        start=time.time()
        func(*args,**kwargs)         # 这里其实用的就是index()
        stop=time.time()
        print('run time is %s' %(stop - start))
    return wrapper
@outter        # 有语法糖必须写在装饰器与函数的中间
def index(x):   # 例如:(写活,不要写死,例如要传递参数x)     若是函数中须要传递参数,那么就须要在装饰器中接受加参数来接受
    print('welcome to index page')
    time.sleep(2)
index(1)

2、装饰器升级版闭包

import time
def index():
    print('welcome to index page')
    time.sleep(3)
def home(name):
    print('welcome %s to home page' %name)
    time.sleep(2)
    return 123
def timmer(func): #func=最原始那个home函数的内地址
    def wrapper(*args,**kwargs): #args=('egon',) kwargs={}
        start=time.time()
        res=func(*args,**kwargs) #最原始那个home函数的内地址('egon')
        stop=time.time()
        print('run time is %s' %(stop - start))
        return res
    return wrapper
# index=timmer(index)
index()
home=timmer(home) #home=outter(最原始那个home函数的内地址) #home=wrapper函数的内地址
res=home('egon') # res=wrapper函数的内地址('egon')
print(res)
---------------------------------------------------------------------------------------------------
welcome to index page
welcome egon to home page
run time is 2.000187635421753
123

3、装饰器的语法糖app

# 装饰器的语法糖:在被装饰对象正上方单独一行写@装饰器的名字
# 运行原理:ide

python解释器一旦运行到@装饰器的名字,就会调用装饰器,而后将被装饰函数的内存地址看成参数
#传给装饰器,最后将装饰器调用的结果赋值给原函数名函数

import time
def timmer(func): #func=最原始那个home函数的内地址
    def wrapper(*args,**kwargs): #args=('egon',) kwargs={}
        start=time.time()
        res=func(*args,**kwargs) #最原始那个home函数的内地址('egon')
        stop=time.time()
        print('run time is %s' %(stop - start))
        return res
    return wrapper

@timmer #index=timmer(index)
def index():
    print('welcome to index page')
    time.sleep(3)

@timmer #home=timmer(home)
def home(name):
    print('welcome %s to home page' %name)
    time.sleep(2)
    return 123
index()
res=home('egon') # res=wrapper函数的内地址('egon')
print(res)

import time
# 装饰器模板
def outter(func):
    def wrapper(*args,**kwargs):
        #在调用函数前加功能
        res=func(*args,**kwargs) #调用被装饰的\也就是最原始的那个函数
        #在调用函数后加功能
        return res
    return wrapper
@outter #index=outter(index) #index=wrapper
def index():
    print('welcome to index page')
    time.sleep(3)
index()

4、练习认证功能装饰器工具

import time

def auth(func):
    def wrapper(*args,**kwargs):
        inp_user = input('please input your username: ').strip()
        inp_pwd = input('please input your password: ').strip()
        if inp_user == 'egon' and inp_pwd == '123':
            print('login successfull')
            res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数
            return res
        else:
            print('username or password error')
    return wrapper

@auth # index=auth(index) #index=wrapper
def index():
    print('welcome to index page')
    time.sleep(3)

index() #wrapper()

5、叠加多个装饰器url

import time

def timmer(func):  #func=wrapper2
    def wrapper1(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)  #res=wrapper2(*args,**kwargs)
        stop=time.time()
        print('run time is %s' %(stop - start))
        return res
    return wrapper1

def auth(func): #func=最原始的那个index的内存地址
    def wrapper2(*args,**kwargs):
        inp_user = input('please input your username: ').strip()
        inp_pwd = input('please input your password: ').strip()
        if inp_user == 'egon' and inp_pwd == '123':
            print('login successfull')
            res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数
            return res
        else:
            print('username or password error')
    return wrapper2

# 解释@语法的时候是自下而上运行
# 而执行装饰器内的那个wrapper函数时的是自上而下
@timmer # index=timmer(wrapper2) #index=wrapper1
@auth # index=auth(最原始的那个index的内存地址) #index=wrapper2
def index():
    print('welcome to index page')
    time.sleep(2)

index() #wrapper1()
import time
def timmer(func):
    print('timmer')
    def wrapper1(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)  #res=wrapper2(*args,**kwargs)
        stop=time.time()
        print('run time is %s' %(stop - start))
        return res
    return wrapper1
def auth(func):
    print('auth')
    def wrapper2(*args,**kwargs):
        inp_user = input('please input your username: ').strip()
        inp_pwd = input('please input your password: ').strip()
        if inp_user == 'egon' and inp_pwd == '123':
            print('login successfull')
            res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数
            return res
        else:
            print('username or password error')
    return wrapper2
@auth   # index=auth(wrapper1) #index=wrapper2
@timmer #timmer(最原始的index)返回wrapper1
def index():
    print('welcome to index page')
    time.sleep(3)
index() #wrapper2()
'''
outter2
outter1
wrapper1
wrapper2

'''

6、有参装饰器

import time

current_user={'username':None}

# 补充:全部的数据类型的值自带布尔值,能够直接看成条件去用,只须要记住布尔值为假的那一些值便可(0,空,None)


def login(engine='file'): #engine='mysql'
    def auth(func): #func=最原始那个index的内存地址
        def wrapper(*args,**kwargs):                          ##若是被装饰的函数有参数须要传递,那么这里也须要接收传递的参数
            if current_user['username']:
                print('已经登陆过了,无需再次登录')
                res=func(*args,**kwargs)
                return res

            if engine == 'file':
                inp_user = input('please input your username: ').strip()
                inp_pwd = input('please input your password: ').strip()
                if inp_user == 'egon' and inp_pwd == '123':
                    print('login successfull')
                    current_user['username']=inp_user # 在登录成功以后马上记录登陆状态
                    res=func(*args,**kwargs) # res=最原始那个index的内存地址(*args,**kwargs)    ## 这里是被装饰函数须要传递参数时,也须要加(*args,**kwargs)
                    return res
                else:
                    print('username or password error')
            elif engine == 'mysql':
                print('基于mysql的认证机制')
            elif engine == 'ldap':
                print('基于ldap的认证机制')
            else:
                print('没法识别的认证源')
        return wrapper
    return auth

@login('file')  #@auth # index=auth(最原始那个index的内存地址) #index=wrapper
def index():
    print('welcome to index page')
    time.sleep(3)

@login('file')
def home(name):
    print('welcome %s to home page' %name)
    time.sleep(2)
    return 123


index() #wrapper()
res=home('egon')
print(res)

# 有参装饰器的模板

def outter1(x,y,z):
    def outter2(func):
        def wrapper(*args,**kwargs):
            res=func(*args,**kwargs)
            return res
        return wrapper
    return outter2

# 无参装饰器的模板

def outter(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper

装饰器补充:

#wraps装饰器应该加到装饰器最内层的函数上
from functools import wraps
import time
def deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        return res
    # wrapper.__name__=func.__name__
    # wrapper.__doc__=func.__doc__
    return wrapper
@deco #index=deco(index) #index=wrapper函数的内存地址
def index():
    """
    index 功能
    """
    print('welcome to index page')
    time.sleep(3)
print(index.__name__)
print(help(index)) #index.__doc__
index()
print(index.__name__)
print(index.__doc__)
---------------------------------------------------------------------------------
index
Help on function index in module __main__:

index()
    index 功能

None
welcome to index page
index

    index 功能

做业:

今日做业:
默写:
    开闭原则
    什么样的函数称为闭包
    python中什么是装饰器
    装饰器的两个原则
    

一:编写函数,(函数执行的时间是随机的)
二:编写装饰器,为函数加上统计时间的功能
三:编写装饰器,为函数加上认证的功能

四:编写装饰器,为多个函数加上认证的功能(用户的帐号密码来源于文件),要求登陆成功一次,后续的函数都无需再输入用户名和密码
注意:从文件中读出字符串形式的字典,能够用eval('{"name":"egon","password":"123"}')转成字典格式

五:编写装饰器,为多个函数加上认证功能,要求登陆成功一次,在超时时间内无需重复登陆,超过了超时时间,则必须从新登陆

六:编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果

七:为题目五编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,若是文件内有值(文件大小不为0),就优先从文件中读取网页内容,不然,就去下载,而后存到文件中

扩展功能:用户能够选择缓存介质/缓存引擎,针对不一样的url,缓存到不一样的文件中

八:还记得咱们用函数对象的概念,制做一个函数字典的操做吗,来来来,咱们有更高大上的作法,在文件开头声明一个空字典,而后在每一个函数前加上装饰器,完成自动添加到字典的操做

九 编写日志装饰器,实现功能如:一旦函数f1执行,则将消息2017-07-21 11:12:11 f1 run写入到日志文件中,日志文件路径能够指定
注意:时间格式的获取
import time
time.strftime('%Y-%m-%d %X')
相关文章
相关标签/搜索