2011-07-06 39 views
4

我們使用另一個內部團隊提供的庫。 (搖搖欲墜的比喻現在開始)Python:將所有函數包裝在一個庫中

from externalTeam import dataCreator 
datacreator.createPizza() 
datacreator.createBurger() 
datacreator.createHotDog() 

最近我們發現他們正在採取超過一分鐘在某些情況下執行一個方法。爲了調試這個,我必須進入我們的代碼並在每次調用此方法時添加超時。

import time 
from externalTeam import dataCreator 
start = time.clock() 
datacreator.createPizza() 
stop = time.clock() 
print "It took %s seconds to perform createPizza" % (str(stop-start)) 

現在回想起來,那是因爲我們調用createPizza所有的地方,我們不控制createPizza本身(比喻開始打破此處略)。我寧願只在一個地方調用createPizza,並且能夠在其中添加計時器。我首先想到的是創建一個包裝他們所有的方法在我自己的包裝類。這是乾的對面,雖然,他們隨時添加其他方法我不得不更新我們的庫來包裝,以及:

import time 
from externalTeam import dataCreator 
def createPizza(self): 
    start = time.clock() 
    datacreator.createPizza() 
    stop = time.clock() 
    print "It took %s seconds to perform createPizza" % (str(stop-start)) 

def createBurger(self): 
    start = time.clock() 
    datacreator.createPizza() 
    stop = time.clock() 
    print "It took %s seconds to perform createBurger" % (str(stop-start)) 

def createHotDog(self): 
    start = time.clock() 
    datacreator.createPizza() 
    stop = time.clock() 
    print "It took %s seconds to perform createHotDog" % (str(stop-start))  

我想是始終執行的幾行代碼周圍的每一個方法函數是從dataCreator調用的。必須通過一箇中間類來做到這一點,它的方法可以被動態地定義 - 或者說左邊沒有定義,對嗎?

+2

看看裝修。 – utdemir

+0

我們是在談論函數還是類的方法? – tjollans

+0

我知道裝修。我裝飾什麼? createPizza和createBurger是它們的功能。 – Nathan

回答

3

我會創造一個dataCreator適配器類,將工作是這樣的:

  1. 有來自dataCreator需要被包裝成調試/定時功能的方法methods2wrap列表。
  2. 重寫了__getattribute__(),它將1:1映射到dataCreator方法上,將methods2wrap中的方法封裝爲定時調試消息。

概念證明代碼(例如包裝類list並在其方法append周圍插入調試時間戳)。

import time 

class wrapper(list): 

    def __getattribute__(self, name): 
     TO_OVERRIDE = ['append'] 
     if name in TO_OVERRIDE: 
      start = time.clock() 
     ret = super(list, self).__getattribute__(name) 
     if name in TO_OVERRIDE: 
      stop = time.clock() 
      print "It took %s seconds to perform %s" % (str(stop-start), name) 
     return ret 

profiled_list = wrapper('abc') 
print profiled_list 
profiled_list.append('d') 
print profiled_list 
profiled_list.pop() 
print profiled_list 

當然你可以建立在這個例子中,並使其參數,這樣在初始化時可以設置包裝一下班,應定時用什麼方法的...

編輯:請注意,TO_OVERRIDE在每個__getattribute__調用中重新分配。這是設計。如果你將它作爲一個類的屬性,__getattribute__會遞歸循環(你應該使用顯式調用父__getattribute__方法來檢索它,但這可能會比從頭開始重建列表慢。

HTH

+0

這似乎不處理返回的方法內的執行時間。在這個解決方案中,'profiled_list.append('d')'將只包含檢索append方法花費的時間,而不是實際追加的時間。我認爲可能有必要返回該方法的包裝版本。 – Gattster

5

如果您嘗試對Python代碼進行概要分析,則應該使用Python內置的profiling libraries而不是手動嘗試。

+0

我主要想分析一個庫的調用,並在調試級輸出到我們的日誌。似乎分析庫可能能夠做到這一點,所以我會查看該鏈接,謝謝! – Nathan

3

爲什麼不是一個只調用它的參數的包裝函數?

def wrapper(func, *args, **kwargs): 
    ... timing logic ... 
    response = func(*args, **kwargs) 
    ... more timing logic 
    return response 

,並稱之爲:

wrapper(datacreator.createPizza, arg1, arg2, kwarg1=kwarg) 

音符傳遞函數本身,但不調用它。

+0

像裝飾者,對不對?這會起作用,但我必須從我們調用的庫中爲每個函數編寫一行代碼,比如'wrapper(datacreator.createPizza,arg1,arg2,kwarg1 = kwarg)'。每當他們引入新的功能,我不得不添加另一行...我想知道是否有辦法避免這種情況。 – Nathan

+0

@caribou - 不完全 - Python裝飾器返回一個函數對象。但把它變成裝飾器是微不足道的。 –

+0

@caribou - 你沒有評論我的答案,但這是我的解決方案試圖解決的問題。當然,你仍然需要指定你想要的時間,但是他們的名字就是你必須插入的東西......或者我錯過了什麼? – mac

相關問題