Python如何在類中定義裝飾器
如何在類中定義裝飾器
實(shí)際案例
實(shí)現(xiàn)一個(gè)能將函數(shù)調(diào)用信息記錄到日志的裝飾器:
- 把每次函數(shù)的調(diào)用時(shí)間,執(zhí)行時(shí)間,調(diào)用次數(shù)寫入日志;
- 可以對被裝飾函數(shù)分組,調(diào)用信息記錄到不同日志;
- 動態(tài)修改參數(shù),比如日志格式;
- 動態(tài)打開關(guān)閉日志輸出功能。
解決方案
為了讓裝飾器在使用上更加靈活,我們把類的實(shí)例方法作為裝飾器
此時(shí)在包裹函數(shù)中就可以持有實(shí)例對象,便于修改屬性和拓展功能。
代碼演示
# _*_ encoding:utf-8 _*_
import logging
from time import localtime, time, strftime, sleep
from random import choice
class CallingInfo(object):
# 通過name對為日志分組
def __init__(self, name):
log = logging.getLogger(name)
# 設(shè)置log的輸出級別
log.setLevel(logging.INFO)
# 輸入到文件中
fh = logging.FileHandler(name + '.log')
log.addHandler(fh)
log.info('start'.center(50, '-'))
# 將log變成實(shí)例屬性
self.log = log
# 定義日志的輸出格式,函數(shù)名、開始時(shí)間,執(zhí)行時(shí)間,調(diào)用次數(shù)
self.formatter = '%(func)s -> [%(time)s - ' \
'%(used)s - %(n_calls)s]'
# 定義裝飾器函數(shù)
def info(self, func):
def wrapper(*args, **kwargs):
wrapper.n_calls += 1
lt = localtime()
start = time()
res = func(*args, **kwargs)
used = time() - start
info = dict()
info['func'] = func.__name__
info['time'] = strftime('%x %X', lt)
info['used'] = used
info['n_calls'] = wrapper.n_calls
msg = self.formatter % info
# 輸出日志
self.log.info(msg)
return res
# 統(tǒng)計(jì)函數(shù)調(diào)用次數(shù),函數(shù)屬性類似于函數(shù)內(nèi)的靜態(tài)變量
wrapper.n_calls = 0
return wrapper
# 動態(tài)修改formatter參數(shù)
def set_formatter(self, formatter):
# 修改實(shí)例屬性
self.formatter = formatter
# 動態(tài)的打開和關(guān)閉日志輸出,設(shè)置level輸出級別
def turn_on(self):
# INFO級別會輸出日志
self.log.setLevel(logging.INFO)
def turn_off(self):
# 抬高日志輸出級別就會關(guān)閉
self.log.setLevel(logging.WARN)
# 將f和g輸出到一個(gè)日志當(dāng)中,h輸出到另一個(gè),需要創(chuàng)建2個(gè)實(shí)例
# 創(chuàng)建類的實(shí)例,使用實(shí)例的info方法去裝飾函數(shù)
c_info1 = CallingInfo('my_log1')
c_info2 = CallingInfo('my_log2')
# 將c_info1日志修改為如下格式
c_info1.set_formatter('%(func)s -> [%(time)s - %(n_calls)s]')
# 關(guān)閉c_info2的日志輸出
c_info2.turn_off()
@c_info1.info
def f():
print('in f')
@c_info1.info
def g():
print('in g')
@c_info2.info
def h():
print('in h')
# 測試代碼, 循環(huán)50次
for _ in range(50):
# 隨機(jī)調(diào)用上面三個(gè)函數(shù)中的一個(gè)
choice([f, g, h])()
# 隨機(jī)秒數(shù)的睡眠
sleep(choice([0.5, 1, 1.5]))總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python3使用pyqt5制作一個(gè)超簡單瀏覽器的實(shí)例
下面小編就為大家?guī)硪黄猵ython3使用pyqt5制作一個(gè)超簡單瀏覽器的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
Django中reverse反轉(zhuǎn)并且傳遞參數(shù)的方法
今天小編就為大家分享一篇Django中reverse反轉(zhuǎn)并且傳遞參數(shù)的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08
Linux下遠(yuǎn)程連接Jupyter+pyspark部署教程
這篇文章主要為大家詳細(xì)介紹了Linux下遠(yuǎn)程連接Jupyter+pyspark部署教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06
django 基于中間件實(shí)現(xiàn)限制ip頻繁訪問過程詳解
這篇文章主要介紹了django 基于中間件實(shí)現(xiàn)限制ip頻繁訪問過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
Python2.x和3.x下maketrans與translate函數(shù)使用上的不同
這篇文章主要介紹了Python2.x和3.x下maketrans與translate函數(shù)使用上的不同,這兩個(gè)函數(shù)建立映射來替換內(nèi)容是Python學(xué)習(xí)當(dāng)中的基礎(chǔ)知識,需要的朋友可以參考下2015-04-04
教你利用PyTorch實(shí)現(xiàn)sin函數(shù)模擬
這篇文章主要給大家介紹了關(guān)于教你利用PyTorch實(shí)現(xiàn)sin函數(shù)模擬的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01
python 統(tǒng)計(jì)代碼耗時(shí)的幾種方法分享
本文實(shí)例講述了Python中統(tǒng)計(jì)代碼片段、函數(shù)運(yùn)行耗時(shí)的幾種方法,分享給大家,僅供參考。2021-04-04

