python3.5.2之裝飾器(1)

 1、本次實驗環境python

在騰訊雲虛擬主機centos7上配置pyenv多版本python管理器,並安裝交互式web編輯器jupyter,python版本爲3.5.2。

 2、裝飾器:mysql

裝飾器的本質是一個函數,接收一個函數做爲參數,而且返回一個函數
帶參數的裝飾器是一個函數,返回一個裝飾器
帶參數的裝飾器最多容許一層,timeit()()(不容許)

 

在python中,一個函數能夠做爲參數傳遞給另一個函數,還可返回一個函數(不瞭解此請看高階函數)所以,咱們能夠把一個函數傳遞給另外一個函數後,在這個被傳遞的函數的外部補充一些操做(裝飾),然後把這個額外添加了補充裝飾的函數得新return回來,裝飾器也是高階函數的一種。

 

一、不帶參數的裝飾器:web

#裝飾器的本質是一個函數,接收一個函數做爲參數,而且返回一個函數
#帶參數的裝飾器是一個函數,返回一個裝飾器
#帶參數的裝飾器最多容許一層@timeit()()(不容許)
#@abs
#@all
#@callable
#def func():
#    pass
#abs(all(callable(func)))
def fun(fn):#接收一函數做爲參數
    print('numner1')
    def wrap(*args,**kwargs):#接收函數的參數
        print('number2')
        ret = fn(*args,**kwargs)#被裝飾的函數
        print('number3')
        return ret
    print('number4')
    return wrap
@fun
def func(*args,**kwargs):
    print(args)
    print('run')
    return args
z = func(1,2,3,4,5,6)
print(z)
#等價於
def func(*args,**kwargs):
    print(args)
    print('run')
    return args
z = fun(func)
f = z(1,2,3,4,5,6)
print(f)
#等價於
def func(*args,**kwargs):
    print(args)
    print('run')
    return args
z = fun(func)(1,2,3,4,5,6)
print(z)
print('############################################')
#func被多個裝飾器裝飾
@fun
@fun
@fun
def func(*args,**kwargs):
    print(args)
    print('run')
    return args
z = func(1,2,3,4,5,6)
print(z)
#等價於
print('############################################')
def func(*args,**kwargs):
    print(args)
    print('run')
    return args
z = fun(fun(fun(func)))(1,2,3,4,5,6)
print(z)
#根據結果,先執行最外層函數與次內層函數的語句,而後執行次內層與次次內層的語句
#以此類推到最內層函數時,即爲被裝飾的函數func

 

二、帶參數的裝飾器:redis

#(1)、判斷一個用戶是否在容許列表中,若在,則執行fn功能函數
from functools import wraps 
def check(allows):
    def dec(fn):
        @wraps(fn)#這裏的@wraps(fn)意思是裝飾wrap函數,將fn做爲參數,
        def wrap(username,*args,**kwargs):#此時函數wrap函數的方法(wrap.__name__等)即爲fn.__name__
            if username in allows:
                return fn(username,*args,**kwargs)
            return 'not allow'#拋出異常 
        return wrap
    return dec
@check(['i','you','he'])
def test(username):
    print('congratulations')
result = test('he')
print(result)
#等價於
def test(username):
    print('congratulations')
result = check(['i','you','he'])(test)('she')#高階函數理解了,這裏也就多了一層函數,而這個函數接收了一個參數
print(result)

 

#(2)、default_user
from functools import wraps
def inject_user(default_user):
    def inject(fn):
        @wraps(fn)
        def wrap(*args,**kwargs):
            if 'user' not in kwargs.keys():
                kwargs['user'] = default_user
            ret = fn(*args,**kwargs)#拿到咱們想要的結果
            return ret
        return wrap
    return  inject
@inject_user('comyn')
def do_something(*args,**kwargs):
    print(kwargs.get('user'))
    return 23
ret = do_something(user='magedu')
print(ret)

 

 三、裝飾器的應用:sql

(1)、裝飾器本質上是一個函數,該函數用來處理其餘函數,它可讓其餘函數在不須要修改代碼的前提下增長額外的功能
(2)、裝飾器常常用於有切面需求的場景,好比:插入日誌、性能測試、事務處理、緩存、權限校驗等應用場景
(3)、裝飾器是解決這類問題的絕佳設計,有了裝飾器,咱們就能夠抽離出大量與函數功能自己無關的雷同代碼並繼續重用
(4)、歸納的講,裝飾器的做用就是爲已經存在的對象添加額外的功能。
#(1)、cache緩存
import time
from functools import wraps
from functools import lru_cache#python內置的cache裝飾器
def cache(instance):#instance爲cache接口的封裝
    def dec(fn):
        @wraps(fn)
        def wrap(*args,**kwargs):
            #key =>fn_name::params
            pos = ','.join((str(x) for x in args))
            kw = ','.join('{}={}'.format(k,v) for k,v in sorted(kwargs.items()))
            key = '{}::{}::{}'.format(fn.__name__,pos,kw)#生成key
            ret = instance.get(key)#判斷key是否在cache中
            print(key)
            print(ret)
            if ret is not None:#從cache中獲得
                return ret
            ret = fn(*args,**kwargs)#這裏咱們也能夠裝飾一個到騰訊雲mysql數據庫取數據的函數
            instance.set(key,ret)#放進緩存(這裏指DictCache)
            return ret
        return wrap
    return dec
class DictCache:#這裏用一個字典來做爲緩存,騰訊雲緩存也能夠
    def __init__(self):
        self.cache = dict()
    def get(self,key):
        return self.cache.get(key)
    def set(self,key,value):
        self.cache[key] = value
    def __str__(self):
        return str(self.cache)
    def __repr__(self):
        return repr(self.cache)
if __name__ == '__main__':
    cache_instance = DictCache()#緩存實例能夠是騰訊雲memcached,redis,mongodb
    @cache(cache_instance)
    def long_time_fun(x):
        time.sleep(x)
        return x
    x = long_time_fun(3)
    print(x)
    y = long_time_fun(3)
    print(y)

    #拿標準庫來實現
    @lru_cache()#具備換出策略lru
    def time_fun(x):
        time.sleep(x)
        return x
    x = time_fun(3)
    print(x)
    y = time_fun(3)
    print(y)

 

 

#(2)、監控
import logging
import time
from functools import wraps
def mertic(prefix,instance):#instance爲各類不一樣類型監控平臺的對象,
    def timeit(fn):# prefix爲監控對象的前綴,屬於哪一個APP、主機的一個標記
        @wraps(fn)
        def wrap(*args,**kwargs):
            start = time.time()
            ret = fn(*args,**kwargs)#取數據
            key = '{}.{}.{}'.format(prefix,fn.__module__,fn.__name__)
            instance.send(key,time.time()-start)#發送到監控處理的地方,好比statsd上
            return ret
        return wrap
    return timeit
#influxdb,grafana展現
class LoggingMetric:
    def send(self,key,value):
        logging.warning('{}=>{}'.format(key,value))

@mertic(prefix='mysql',instance=LoggingMetric())
def long_time_fun(x):
    time.sleep(x)
    return x
print(long_time_fun(1))

 

(3)、身份驗證(4)、路由

 未完待續!!!請看python3.5.2之裝飾器(2)mongodb

相關文章
相關標籤/搜索