您好,登錄后才能下訂單哦!
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')
查看顯示結果
# 裝飾器參數傳遞及相關應用
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')
結果如下:
偏函數,把函數部分的參數固定下來,相當于為部分的參數添加了一個固定的默認值,形成一個新的函數并返回
從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 已經定義并且已經賦值,不能被重復賦值
結果如下
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是通過可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))
查看結果
程序員可以方便的注冊函數到某一個命令,用戶輸入命令時,路由到注冊函數
如果此命令沒有對應的注冊函數,執行默認函數
用戶輸入用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()
結果如下
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。
關于這個編碼的規則:
①.把3個字符變成4個字符。
②每76個字符加一個換行符。
③.最后的結束符也要處理。
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')))
結果如下
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')))
結果如下
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。