中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

裝飾器進階

發布時間:2020-07-13 02:21:25 來源:網絡 閱讀:683 作者:長跑者1號 欄目:編程語言

一 functools 模塊

1 update_wrapper模塊

Functools.update_wrapper(wrapper,wrapped,assigned=WRAPPER_ASSIGNMENTS,updated=WRAPPER_UPDATES)
類似 copy_properties功能
Wrapper 包裝函數
wrapped 被包裝函數(源函數)
元祖 WRAPPERA_ASSIGNMENTS中是被覆蓋的屬性
'_module_','_name_','_qualname_','_doc_','_annotations_'
模塊名。名稱。限定名。文檔。參數注解
元祖WRAPPER_UPDATES是要被更新的屬性__dict__屬性字典。將自己字典中的東西添加進去,而不是覆蓋別人的東西,key相同,則是覆蓋,key不同,則是增加
增加一個__wrapped__屬性,保留著wrapped函數

# 裝飾器參數傳遞及相關應用
import  functools
import  datetime,time  
def  x(t):
    def _logger(fn):
        def  _wapper(*args,**kwargs):
            '''This  is  wapper'''
            print ("login.....")
            start=datetime.datetime.now()
            ret = fn(*args,**kwargs)
            du=datetime.datetime.now()-start
            if  du.total_seconds()<5:
                print  (fn.__name__,du)
            else:
                print  ("goods")
            print ("logout....")
            return  ret 
        functools.update_wrapper(_wapper,fn)
        return  _wapper
    return  _logger

@x(5)
def  add(x,y):
    '''This is add'''
    time.sleep(5)
    return  x+y

print (add(5,6),add.__name__,add.__doc__,sep='\n')

查看顯示結果
裝飾器進階

2 wraps ,類似上述的變種

# 裝飾器參數傳遞及相關應用
import  functools
import  datetime,time  
def  x(t):
    def _logger(fn):
        @functools.wraps(fn)#通過閉包和裝飾器完成,其和上面的_cpoy的是實現原理相似
        def  _wapper(*args,**kwargs):
            '''This  is  wapper'''
            print ("login.....")
            start=datetime.datetime.now()
            ret = fn(*args,**kwargs)
            du=datetime.datetime.now()-start
            if  du.total_seconds()<5:
                print  (fn.__name__,du)
            else:
                print  ("goods")
            print ("logout....")
            return  ret 
        return  _wapper
    return  _logger

@x(5)
def  add(x,y):
    '''This is add'''
    time.sleep(5)
    return  x+y

print (add(5,6),add.__name__,add.__doc__,sep='\n')

結果如下:
裝飾器進階

3 partial 方法

偏函數,把函數部分的參數固定下來,相當于為部分的參數添加了一個固定的默認值,形成一個新的函數并返回
從partial 生成新函數,是對原函數的封裝

import  inspect
import   functools
def add(x,y)->int:
    return  x+y
newadd=functools.partial(add,y=5)  # 構建新函數,使用y=5稱為其默認值
print (newadd(3))   # 默認是x傳值
print (newadd(4,y=6))  
print (newadd(x=6,y=7))
sig1=inspect.signature(add)   
sig2=inspect.signature(newadd)
print (sig1.parameters)
print (sig2.parameters)

結果如下
裝飾器進階

import  inspect
import   functools
def  add(x,y,*args)->int:
    print (x,y,args)
newadd= functools.partial(add,1,2,3,4,5,6)
print (inspect.signature(add).parameters.items())
print (inspect.signature(newadd).parameters.items())
print (newadd())
print (newadd(7))
print (newadd(8,9))
print (newadd(10,11,y=4,x=5))  #此處的x,y 已經定義并且已經賦值,不能被重復賦值

結果如下
裝飾器進階

4 lru_cache

functools.lru_cache(maxsize=128,typed=False)
least-recently-used裝飾器,lru,最近最少使用,cache緩存
如果maxsize設置為None,則禁用LRU功能,并且緩存可以無限制增長,當maxsize是二的冪時,LRU功能執行得最好 。
如果typed設置為True,則不同類型的函數參數將單獨存儲,如f(3)和f(3.0)將被視為具有不同結果的不同調用

實例

import   functools
import  datetime
import  time
def  logger(fn):
    def _wapper(*args,**kwargs):
        start_time=datetime.datetime.now()
        ret = fn(*args,**kwargs)
        send=(datetime.datetime.now()-start_time).total_seconds()
        print  ("{} 函數執行時間為: {}".format(fn.__name__,send))
        return   ret
    return   _wapper
@logger  # 此處的調用不分先后次序,其結果都一樣
@functools.lru_cache()
def  add(x,y,z=3):
    time.sleep(3)
    return  x+y+z
print (add(3,4))
print  (add(3,4))
print  (add(3.0,4.0))
print (add(3,4,3))  # 此處是重新計算
print (add(3,4.0,3.0))

執行結果為

裝飾器進階

lru_cache 裝飾器基礎應用

import   functools
import  datetime
import  time
def  logger(fn):
    def _wapper(*args,**kwargs):
        start_time=datetime.datetime.now()
        ret = fn(*args,**kwargs)
        send=(datetime.datetime.now()-start_time).total_seconds()
        print  ("{} 函數執行時間為: {}".format(fn.__name__,send))
        return   ret
    return   _wapper
@logger  # 此處的調用不分先后次序,其結果都一樣
@functools.lru_cache()
def  Fib(n):
    while  n < 2:
        return   n
    return   Fib(n-1)+Fib(n-2)
print  ([Fib(x)  for x  in range(10)])

結果如下
裝飾器進階

總結

lrucache 裝飾器應用
使用前提
同樣的函數參數一定得到同樣的結果
函數執行時間很長,且要多次執行
本質是函數調用的參數=> 返回值
缺點
不支持緩存過期,key無法過期,失效
不支持清除操作
不支持分布式,是一個單機的緩存
使用場景,單機上需要空間換取時間的地方,可以使用緩存來計算變成快速的查詢*

二 裝飾器練習

1 實現一個cache裝飾器,實現可過期,可刪除的功能,可以不換出

思想:
1 cache是通過可hash對象進行存儲和調用的,因此其存入的key必須是不可變類型
2 通過前面的inspect模塊取出對應的形參,及key,通過傳入的實參獲取到其對應的值,進行鍵和值的處理

實例如下
初步代碼實現如下:

#!/usr/bin/poython3.6
#conding:utf-8
import   functools
import  datetime
import  time
import  inspect
def  logger(fn):
    local_cache={}  # 此處定義一個緩沖器
    @functools.wraps(fn)
    def  _wapper(*args,**kwargs):
        list_dict={}  #此處定義一個構建key的字典
        sig=inspect.signature(fn)
        param=sig.parameters
        param_list=list(param.keys())
        for  i,v  in  enumerate(args):    # 此處的作用是取出形參和傳入實參的對應關系
            list_dict[param_list[i]]=v
        list_dict.update(kwargs)
        key = tuple(sorted(list_dict.keys()))  # 通過此處獲取字典的鍵的固定順序的元祖,因為元祖是不可變數據類型
        if  key  not  in  local_cache.keys():  #查詢這個key是否在此緩存中
            ret = fn(*args,**kwargs)  #此處調用外部參數獲取值
            local_cache[key]=ret  # 此處對值進行處理
        return  local_cache[key]  # 此處將值返回,用于返回,此處若返回為ret,則緩存變失去了意義,
    return   _wapper
def  functime(fn):
    @functools.wraps(fn)
    def _wapper(*args,**kwargs):
        start_time=datetime.datetime.now()
        ret  =  fn(*args,**kwargs)
        send=(datetime.datetime.now()-start_time).total_seconds()
        print ("{} 函數的執行時間為:{}".format(fn.__name__,send))
        return   ret
    return   _wapper
@functime
@logger
def  add(x,y=4):
    time.sleep(3)
    return  x+y
print (add(x=3,y=4))
print (add(3,4))
print  (add(y=4,x=3))

執行結果如下
裝飾器進階

添加默認值參數

import   functools
import  datetime
import  time
import  inspect
def  logger(fn):
    local_cache={}  # 此處定義一個緩沖器
    @functools.wraps(fn)
    def  _wapper(*args,**kwargs):
        list_dict={}  #此處定義一個構建key的字典
        sig=inspect.signature(fn)
        param=sig.parameters
        param_list=list(param.keys())
        for  i,v  in  enumerate(args):    # 此處的作用是取出形參和傳入實參的對應關系
            list_dict[param_list[i]]=v
        list_dict.update(kwargs)
        for  i  in  param.keys():  #檢測形式參數
            if  i not  in  list_dict.keys():  # 判斷形參是否在傳入的對應參數中,若不存在,則由默認情況,則進行加入對應的字典中
                list_dict[i]=param[i].default
        key = tuple(sorted(list_dict.keys()))  # 通過此處獲取字典的鍵的固定順序的元祖,因為元祖是不可變數據類型
        if  key  not  in  local_cache.keys():  #查詢這個key是否在此緩存中
            ret = fn(*args,**kwargs)  #此處調用外部參數獲取值
            local_cache[key]=ret  # 此處對值進行處理
        return  local_cache[key]  # 此處將值返回,用于返回,此處若返回為ret,則緩存變失去了意義,
    return   _wapper
def  functime(fn):
    @functools.wraps(fn)
    def _wapper(*args,**kwargs):
        start_time=datetime.datetime.now()
        ret  =  fn(*args,**kwargs)
        send=(datetime.datetime.now()-start_time).total_seconds()
        print ("{} 函數的執行時間為:{}".format(fn.__name__,send))
        return   ret
    return   _wapper
@functime
@logger
def  add(x,y=4):
    time.sleep(3)
    return  x+y
print (add(x=3,y=4))
print (add(3,4))
print  (add(y=4,x=3))
print (add(3))

結果如下
裝飾器進階

配置過期功能

import  functools
import  datetime
import  time
import  inspect
def  logger(times):
    def  _logger(fn):
        local_cache={}  # 此處定義一個緩沖器
        @functools.wraps(fn)
        def  _wapper(*args,**kwargs):
            pop_key_list=[]
            for  k,(_,item)  in  local_cache.items():
                if datetime.datetime.now().timestamp()- item> times:
                    pop_key_list.append(k)
            for  i in pop_key_list:
                local_cache.pop(i)
            list_dict={}  #此處定義一個構建key的字典
            sig=inspect.signature(fn)
            param=sig.parameters
            param_list=list(param.keys())
            for  i,v  in  enumerate(args):    # 此處的作用是取出形參和傳入實參的對應關系
                list_dict[param_list[i]]=v
            list_dict.update(kwargs)
            for  i  in  param.keys():  #檢測形式參數
                if  i not  in  list_dict.keys():  # 判斷形參是否在傳入的對應參數中,若不存在,則由默認情況,則進行加入對應的字典中
                    list_dict[i]=param[i].default
            key = tuple(sorted(list_dict.keys()))  # 通過此處獲取字典的鍵的固定順序的元祖,因為元祖是不可變數據類型
            if  key  not  in  local_cache.keys():  #查詢這個key是否在此緩存中
                ret = fn(*args,**kwargs)  #此處調用外部參數獲取值
                local_cache[key]=(ret,datetime.datetime.now().timestamp())  # 此處將值返回,用于返回,此處若返回為ret,則緩存變失去了意義,
            return  local_cache[key]
        return   _wapper
    return  _logger
def  functime(fn):
    @functools.wraps(fn)
    def _wapper1(*args,**kwargs):
        start_time=datetime.datetime.now()
        ret=fn( *args,**kwargs)
        send=(datetime.datetime.now()-start_time).total_seconds()
        print ("{} 函數的執行時間為:{}".format(fn.__name__,send))
        return   ret
    return   _wapper1
@functime
@logger(5)  #傳入過期時間為5s進行處理
def  add(x,y=4):
    time.sleep(3)
    return  x+y
print (add(x=3,y=4))
print (add(3,4))
time.sleep(5)
print  (add(y=4,x=3))
print (add(3))

查看結果
裝飾器進階

2 寫一個命令分發器

程序員可以方便的注冊函數到某一個命令,用戶輸入命令時,路由到注冊函數
如果此命令沒有對應的注冊函數,執行默認函數
用戶輸入用input(">>")


分析:
輸入一個命令映射到一個函數,并執行這個函數,應該是cmd,fn 形式,此時字典整好滿足此中需求
如果輸入了某一個cmd命令后,沒有找到函數,就要調用缺省的函數執行,這整好是字典的缺省函數
cmd是字符串

基本代碼如下

#!/usr/bin/poython3.6
#conding:utf-8
#定義一個字典,其保存命令和函數的集合
commds={}
# 創建函數
def  fun1():
    print  ("hello  fun1")
def  fun2():
    print ("hello  fun2")
#創建默認函數
def  fundefault():
    print  ("hello  default")

# 創建注冊函數
def  register(name,fn):
    commds[name]=fn
# 創建查詢函數
def  printf():
    while  True:
        cmd=input(">>")
        if cmd.strip() == 'quit':
            return
        commds.get(cmd,fundefault)()  #調用函數,若無存在,則調用默認函數
# 調用注冊函數進行注冊
register("fun1",fun1)
register("fun2",fun2)
#調用顯示函數
printf()

查看結果如下
裝飾器進階

改善注冊函數如下

#!/usr/bin/poython3.6
#conding:utf-8
#定義一個字典,其保存命令和函數的集合
commds={}
# 創建注冊函數
def  register(name):  #通過柯里化進行處理
    def  _warpper(fn):
        commds[name]=fn
    return  _warpper
# 創建查詢函數
def  printf():
    while  True:
        cmd=input(">>")
        if cmd.strip() == 'quit':
            return
        commds.get(cmd,fundefault)()  #調用函數,若無存在,則調用默認函數
# 調用注冊函數進行注冊
# 創建函數
@register('fun1')
def  fun1():
    print  ("hello  fun1")
@register('fun2')
def  fun2():
    print ("hello  fun2")
#創建默認函數
def  fundefault():
    print  ("hello  default")
#調用顯示函數
printf()

將調用函數和顯示函數進行合并,并進行集中輸入,如下

#!/usr/bin/poython3.6
#conding:utf-8
#定義一個字典,其保存命令和函數的集合
commds={}
# 創建注冊函數
def  comm():
    def  register(name):  #通過柯里化進行處理
        def  _warpper(fn):
            commds[name]=fn
        return  _warpper
    # 創建查詢函數
    def  printf():
        while  True:
            cmd=input(">>")
            if cmd.strip() == 'quit':
                return
            commds.get(cmd,fundefault)()  #調用函數,若無存在,則調用默認函數
    return   register,printf
register,printf=comm()
# 調用注冊函數進行注冊
# 創建函數
@register('fun1')
def  fun1():
    print  ("hello  fun1")
@register('fun2')
def  fun2():
    print ("hello  fun2")
#創建默認函數
def  fundefault():
    print  ("hello  default")
#調用顯示函數
printf()

裝飾器進階

#!/usr/bin/poython3.6
#conding:utf-8
from   functools  import partial
def  dispatcher():
    commads={}
    def reg(cmd,*args,**kwargs):
        def _reg(fn):
            func=partial(fn,*args,**kwargs)
            commads[cmd]=func
            return  func
        return _reg
    def  run():
        while True:
            cmd=input('>>')
            if  cmd.strip()  == 'q'  or  cmd.strip() =='quit':
                break
            else:
                commads.get(cmd,defaunlt)()

    def  defaunlt():
        print ('default')
    return   reg,run
reg,run=dispatcher()
@reg('add',1,2,3,4)
def add(x,y,z,w):
    print   (x+y+z+w)
@reg('sub',20,10)
def  sub(x,y):
    print  (x-y)
run()

結果如下
裝飾器進階

3 實現base64編碼和解碼

1 簡介

Base64是網絡上最常見的用于傳輸8Bit字節碼的編碼方式之一,Base64就是一種基于64個可打印字符來表示二進制數據的方法。
Base64編碼是從二進制到字符的過程,可用于在HTTP環境下傳遞較長的標識信息。采用Base64編碼具有不可讀性,需要解碼后才能閱讀。
Base64由于以上優點被廣泛應用于計算機的各個領域,然而由于輸出內容中包括兩個以上“符號類”字符(+, /, =),不同的應用場景又分別研制了Base64的各種“變種”。為統一和規范化Base64的輸出,Base62x被視為無符號化的改進版本。


標準的Base64并不適合直接放在URL里傳輸,因為URL編碼器會把標準Base64中的“/”和“+”字符變為形如“%XX”的形式,而這些“%”號在存入數據庫時還需要再進行轉換,因為ANSI SQL中已將“%”號用作通配符。
為解決此問題,可采用一種用于URL的改進Base64編碼,它在末尾填充'='號,并將標準Base64中的“+”和“/”分別改成了“-”和“_”,這樣就免去了在URL編解碼和數據庫存儲時所要作的轉換,避免了編碼信息長度在此過程中的增加,并統一了數據庫、表單等處對象標識符的格式。

Base64要求把每三個8Bit的字節轉換為四個6Bit的字節(3*8 = 4*6 = 24),然后把6Bit再添兩位高位0,組成四個8Bit的字節,也就是說,轉換后的字符串理論上將要比原來的長1/3。

2 規則

關于這個編碼的規則:
①.把3個字符變成4個字符。
②每76個字符加一個換行符。
③.最后的結束符也要處理。

3 base64編碼

import base64
source = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def Base64(src):
    ret = bytearray()  # 定義可變字節列表,一個字節為8bit
    length = len(src)
    r = 0  # r為記錄的補0的數量
    for offset in range(0, length, 3):  # 進行三位切割,三位8bbit切割成4位6bit,
        if offset <= length - 3:  #此處是匹配前面的整3位的
            triple = src[offset:offset + 3]
        else:
            triple = src[offset:]  # 截取后面的小于3位的
            r = 3 - len(triple)  # 獲取需要補0的位數
            triple = triple + '\x00' * r  # 補幾個0    bin(0x00)       '0b0'
        # print  (triple,r)
        b = int.from_bytes(triple.encode(), 'big')  # 大端模式為big,小端模式為little
        for i in range(18, -1, -6):  # 進行移位操作
            if i == 18:
                index = b >> i
            else:
                index = b >> i & 0x3F  # 此處是進行運算 ,轉換為二進制是 bin(0x3f)     '0b111111'
            #  In [24]: int('0x3d',16)
            # Out[24]: 61
            # In [25]: chr(61)
            # Out[25]: '='
            ret.append(source[index])
        for i in range(1, r + 1):
            ret[-i] = 0x3D  # 0x3D 表示等號
    return bytes(ret)
print('Base64',Base64('123456'))
print ('base64',base64.b64encode('123456'.encode('utf-8')))

結果如下
裝飾器進階

4 Base64解碼

import  base64
#base64一定是四的倍數
from  collections  import OrderedDict
base_tb1="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
alphabet=OrderedDict(zip(base_tb1,range(64)))
def  Base64decode(src):
    ret=bytearray()
    length=len(src)
    step=4
    for offset  in  range(0,length,step):
        tmp=0x00
        block=src[offset:offset+step]  # 4位進行截取,abcd
        for  i,c in  enumerate(reversed(block)):  # 進行反向操作處理,第一個是0 d
            index= alphabet.get(c)  # 通過值找索引 ,其中負數表示沒找到,find不拋異常
            if  index==-1: #表示沒找到
                continue   #直接操作下一個
            tmp += (index  << i*6)  # 此處第一個d是最后面的低6位,向左是高位,右邊位低位,,第一次i=0表示沒移動,
            # 第二次i=1表示向左移動6位,依次類推abcd,最后將其加在一起。此處相當于將其進行了拼接,此時已經成為了24
        ret.extend(tmp.to_bytes(3,'big')) # 將4個段進行切成3段,若有等號,則先不管
    return   bytes(ret.rstrip(b'\x00'))  # 去掉多余的右邊的0,是asscii的0,在最后的4變3的過程中,才會出現0,因為前面的都是整取

print ('Base64',Base64decode('abcd'))
print ('base64',base64.b64decode('abcd'.encode('utf-8')))

結果如下
裝飾器進階

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

盖州市| 宁波市| 丰原市| 布尔津县| 拉孜县| 西峡县| 观塘区| 集贤县| 贵阳市| 江达县| 临猗县| 武川县| 卓资县| 门源| 静安区| 库伦旗| 东丰县| 明星| 砚山县| 博兴县| 中阳县| 共和县| 松滋市| 肇州县| 潮州市| 永济市| 塔城市| 静乐县| 徐汇区| 凤山县| 米泉市| 满洲里市| 施甸县| 阿荣旗| 大渡口区| 大洼县| 苍南县| 武夷山市| 昌宁县| 越西县| 乐山市|