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')
相關文章
相關標籤/搜索