python全棧闖關--11-裝飾器初識

一、裝飾器造成

當不想修改原函數,未函數先後添加功能時,就可使用裝飾器,在函數先後增長功能。緩存

裝飾器的初始造成

import time

def timer(f):
    def inner():
        print("我是裝飾器,我來裝飾了!!!")
        start = time.time()
        f()
        end = time.time()
        print(start - end)
    return inner  # 返回inner因爲f實現了閉包,直接調用了程序

def func():
    time.sleep(1)
    print("我是小魚,要做做做。。。有本事來裝飾我!")

# 經過inner返回,在func先後進行了函數的功能的擴展
t = timer(func)
t()  # 雖然實現了功能,可是函數的調用名修改了

# 爲了避免改變調用名,能夠賦值給func
func = timer(func)
func()  # 經過裝飾器,實現了不修改函數名的裝飾

語法糖

在函數前面加,加上@函數名,就能夠實現裝飾器,叫作語法糖閉包

def timer(f):
    def inner():
        print("我是裝飾器,我來裝飾了!!!")
        start = time.time()
        f()
        end = time.time()
        print(start - end)
    return inner  # 返回inner因爲f實現了閉包,直接調用了程序

@timer
def func():
    time.sleep(1)
    print("我是小魚,要做做做。。。有本事來裝飾我!")

 

二、帶參數和返回值的裝飾器

import time

def timer(f):
    def inner(a,b):  # inner接收傳入的參數
        print("我是裝飾器,我來裝飾了!!!")
        start = time.time()
        ret = f(a,b)
        end = time.time()
        print(start - end)
        return  ("我是裝飾器的返回值!!!",start - end)  # 在閉包內部,實現返回值
    return inner  # 返回inner因爲f實現了閉包,直接調用了程序

@timer
def func(a,b):
    time.sleep(1)
    print("我是小魚,要做做做。。。有本事來裝飾我!")
    print("a=%s,b=%s" % (a,b))

ret = func(1,2)  # 參數至關於傳遞給inner
print(ret)

執行順序

 

 

 

三、傳遞任意參數的裝飾器

經過*args和**kwargs傳遞任意參數函數

def warpper(f):
    def inner(*args, **kwargs):
        ret = f(*args, **kwargs)
        return ret
    return inner

@warpper
def func(*args, **kwargs):  #*和**打散
    print("我是被裝飾的函數!")
    print(args)
    print(kwargs)

func()  # 傳空參數
func(1,2,3,4,b=1, a=2)  # 傳任意參數
dic1 = {"a":1, "b":2}
func(*(1,2,3,4),**dic1)  # 打散傳遞

四、參數位置隨感

我的觀察結論:*是按順序打散,形參位置:*args中,args打散後爲1 2 3 4,因此args爲(1,2,3,4)this

def outer(*args):
    print(args)  # (1, 2, 3, 4)
    print(*args)  # 1 2 3 4  元祖被打散
    def inner(*args):
        print('innner', args)
    inner(*args)  # 打散傳入inner(1,2,3,4)

outer = outer(1,2,3,4)

 

五、warps

函數的__doc__和__name__能夠查看函數的說明和名字。url

裝飾器後,函數名和名字都變爲裝飾器的內部函數spa

def warpeer(f):
    def inner(*args, **kwargs):
        '''
        this is warpper inner
        :param args:
        :param kwargs:
        :return:
        '''
        print("this is innser")
        ret = f(*args, ** kwargs);
        return ret
    return inner

@warpeer
def func():
    print("this is func")

print(func.__name__)
print(func.__doc__)

 

 加上wraps後,能夠識別到函數本身的doc和namecode

from functools import wraps

def warpeer(f):
    @wraps(f) def inner(*args, **kwargs):
        '''
        this is warpper inner
        :param args:
        :param kwargs:
        :return:
        '''
        print("this is innser")
        ret = f(*args, ** kwargs);
        return ret
    return inner

@warpeer
def func():
    '''
    this is func doc
    :return:
    '''
    print("this is func")

print(func.__name__)
print(func.__doc__)

 

 

 

六、練習

# 1.編寫裝飾器,爲多個函數加上認證的功能(用戶的帳號密碼來源於文件),
# 要求登陸成功一次,後續的函數都無需再輸入用戶名和密碼

uname = "小魚"
upwd = "qwe"
LOGTYPE = False


def login(func):
    def in_login():
        global LOGTYPE
        # print(LOGTYPE)
        if LOGTYPE:
            # print(LOGTYPE)
            func()
            return
        username = input("請輸入用戶名:")
        userword = input("請輸入密碼:")
        if username.strip() == uname and userword.strip() == upwd:
            ret = func()
            LOGTYPE = True
            return ret
        else:
            print("用戶名或者密碼錯誤!")
        pass

    return in_login


@login
def shoplist_add():
    print("增長一件商品!")


@login
def shoplist_del():
    print("刪除一件商品!")


shoplist_add()
shoplist_del()

 

# 1.編寫下載網頁內容的函數,要求功能是:用戶傳入一個url,函數返回下載頁面的結果
# 2.爲題目1編寫裝飾器,實現緩存網頁內容的功能:
# 具體:實現下載的頁面存放於文件中,若是文件內有值(文件大小不爲0),就優先從文件中讀取網頁內容,不然,就去下載,而後存到文件中

import os
from urllib.request import urlopen as uop

def catche(fun):
    def in_c(*args, **kwargs):
        file = "catche.txt"
        if not os.path.exists(file):
            with open(file, 'wb') as f:
                f.write("")
        if os.path.getsize(file) :
            with open(file, 'rb') as f:
                return f.read()
        else:
            ret = fun(*args, **kwargs)
            with open(file, 'wb') as f:
                f.write(b'****catche***' + ret)
            return ret
    return in_c

@catche
def get_url(url):
    ret = uop(url).read()
    return ret


print(get_url("http://www.baidu.com"))
print(get_url("http://www.baidu.com"))
相關文章
相關標籤/搜索