1. 程式人生 > >Python全棧(第一期)Day12

Python全棧(第一期)Day12

今日主要內容:
裝飾器的進階
1,functools.wraps
2,帶引數的裝飾器
3,多個裝飾器裝飾同一個函式

一,裝飾器複習

def wrapper(func):
    def inner(*args,**kwargs):
        print('在被裝飾的函式執行之前做的事')
        ret = func(*args, **kwargs)
        print('在被裝飾的函式執行之後做的事')
        return ret
    return inner

@wrapper   #holiday = wrapper(holiday)
def holiday(day):
    print('全體放假%s天' % day)
    return '好開心'

ret = holiday(3)
print(ret)

輸出結果:
在被裝飾的函式執行之前做的事
全體放假3天
在被裝飾的函式執行之後做的事
好開心

知識補充:

#區分這幾種情況一起*的作用!
#*args不是在哪兒都能用的  只是print這裡可以  因為print有一個引數:*args
def outer(*args):
    print(args)
    print(*args)
    def inner(*args):
        print('inner : ', args)
    inner(*args)


outer(1, 2, 3, 4)   #==outer(*[1,2,3,4])  #==outer(*(1,2,3,4))


#  接收的時候聚合 呼叫的時候打散

輸出結果;
(1, 2, 3, 4)
1 2 3 4
inner : (1, 2, 3, 4)

二,實戰

1,編寫裝飾器,求登入成功一次,後續的函式都無需再輸入使用者名稱和密碼。

FLAG = False
def login(func):
    def inner(*args, **kwargs):
        global FLAG
        '''登入程式'''
        if FLAG:
            ret = func(*args, **kwargs)  # func是被裝飾的函式
            return ret
        else:
            username = input('username : ')
            password = input('password : ')
            if username == 'nanshan' and password == '520':
                FLAG = True
                ret = func(*args, **kwargs)      #func是被裝飾的函式
                return ret
            else:
                print('登入失敗')
    return inner

@login
def shoplist_add():
    print('增加一件物品')

@login
def shoplist_del():
    print('刪除一件物品')

shoplist_add()
shoplist_del()

輸出結果:
username : nanshan
password : 520
增加一件物品
刪除一件物品
很明顯:shoplist_del() 並沒有要求重新輸入使用者名稱。

2,編寫裝飾器,為多個函式加上記錄呼叫功能,要求每次呼叫函式都將被呼叫的函式名稱寫入檔案。

def log(func):
    def inner(*args, **kwargs):
        with open('log', 'a', encoding='utf-8') as f:
            f.write(func.__name__+'\n')
        ret = func(*args, **kwargs)
        return ret
    return inner

@log
def shoplist_add():
    print('增加一件物品')

@log
def shoplist_del():
    print('刪除一件物品')

shoplist_add()
shoplist_del()
shoplist_del()
shoplist_del()
shoplist_del()
shoplist_del()

輸出結果:
增加一件物品
刪除一件物品
刪除一件物品
刪除一件物品
刪除一件物品
刪除一件物品

開啟log檔案:
shoplist_add
shoplist_del
shoplist_del
shoplist_del
shoplist_del
shoplist_del

3,進階作業

1.編寫下載網頁內容的函式,要求功能是:使用者傳入一個url,函式返回下載頁面的結果。
2.為題目1編寫裝飾器,實現快取網頁內容的功能:
具體:實現下載的頁面存放於檔案中,如果檔案內有值(檔案大小不為0),就優先從檔案中讀取網頁內容,否則,就去下載,然後存到檔案中。

import os
from urllib.request import urlopen
def cache(func):
    def inner(*args, **kwargs):
        if os.path.getsize('web_cache'):
            with open('web_cache', 'rb') as f:
                return f.read()  #return 之後 程式結束
        ret = func(*args, **kwargs)
        with open('web_cache','wb') as f:
            f.write(b'*********'+ret)   #這個地方是為了方便判斷:究竟是在哪讀的。
        return ret
    return inner

@cache
def get(url):
    code = urlopen(url).read()
    return code


# {'網址':"檔名"}
ret = get('http://www.baidu.com')
print(ret)
ret = get('http://www.baidu.com')
print(ret)
ret = get('http://www.baidu.com')
print(ret)

輸出結果:
b’
b’*********
b’*********

三,wraps

1,基本知識

from functools import wraps
def wahaha():
    '''
    一個列印娃哈哈的函式
    :return:
    '''
    print('娃哈哈')

print(wahaha.__name__) #檢視字串格式的函式名
print(wahaha.__doc__)  #document

輸出結果:
wahaha
‘’‘
一個列印娃哈哈的函式
’‘’

2,進階

from functools import wraps
def wrapper(func):  #func = holiday
    @wraps(func)
    def inner(*args,**kwargs):
        print('在被裝飾的函式執行之前做的事')
        ret = func(*args,**kwargs)
        print('在被裝飾的函式執行之後做的事')
        return ret
    return inner

@wrapper   #holiday = wrapper(holiday)
def holiday(day):

    print('全體放假%s天' % day)
    return '好開心'

print(holiday.__name__)    #這裡就是wraps的功能
print(holiday.__doc__)
ret = holiday(3)
print(ret)
#因為wraps的功能,是的holiday's name is holiday

輸出結果:
holiday
None
在被裝飾的函式執行之前做的事
全體放假3天
在被裝飾的函式執行之後做的事
好開心

四,裝飾器進階

需求:
帶引數的裝飾器
500個函式
我們如果現在不再需要裝飾器該怎麼辦呢?
note:我們以後還會使用。

import time
FLAGE = True
def timmer_out(flag):
    def timmer(func):
        def inner(*args,**kwargs):
            if flag:
                start = time.time()
                ret = func(*args,**kwargs)
                end = time.time()
                print(end-start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret
        return inner
    return timmer

# timmer = timmer_out(FLAGE)
@timmer_out(FLAGE)
def wahaha():
    time.sleep(0.1)
    print('娃哈哈娃哈哈')

@timmer_out(FLAGE)
def erguotou():
    time.sleep(0.1)
    print('二鍋頭二鍋頭')

wahaha()
erguotou()

輸出結果:
娃哈哈娃哈哈
0.10094165802001953
二鍋頭二鍋頭
0.10095953941345215

多個裝飾器修飾一個函式

#記住執行過程
def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')
        ret = func()
        print('wrapper1 ,after func')
        return ret
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        ret = func()
        print('wrapper2 ,after func')
        return ret
    return inner2

def wrapper3(func):
    def inner3():
        print('wrapper3 ,before func')
        ret = func()
        print('wrapper3 ,after func')
        return ret
    return inner3

@wrapper3
@wrapper2
@wrapper1
def f():
    print('in f')
    return '哈哈哈'

print(f())

輸出結果:
wrapper3 ,before func
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func
wrapper3 ,after func
哈哈哈