2012-11-20 37 views
1

我有一個python哈希,它包含函數名稱映射到函數。我想修改每個散列條目來調用相關的函數BUT,然後調用最終的自定義函數。這有點像退出鉤子。Python嵌套功能範圍

def original(): 
    print "original work" 

成爲

def replacement(): 
    original() 
    print "notify somebody..." 

我的問題是,我認爲我得到我的範圍界定等,錯誤如下面的代碼的輸出並不如預期。也許如果我能問,是否有更好的方法來做到這一點?我想堅持修改原來的cb,因爲它的第三方代碼和更少的地方我變得更好。

#!/usr/bin/python 

def a(): 
    print "a" 

def b(): 
    print "b" 

def c(): 
    print "c" 


orig_fxn_cb = dict() 

" basic name to function callback hash " 
orig_fxn_cb['a'] = a 
orig_fxn_cb['b'] = b 
orig_fxn_cb['c'] = c 

" for each call back routine in the hash append a final action to it " 
def appendFxn(fxn_cb): 
    appended_fxn_cb_new = dict() 
    for i in orig_fxn_cb.keys(): 
     cb = fxn_cb[i] 
     def fxn_tail(): 
      cb() 
      print cb.__name__, "tail" 

     appended_fxn_cb_new[i] = fxn_tail 
     appended_fxn_cb_new[i]() 
    return appended_fxn_cb_new 

" make up a modified callback hash " 
xxx = appendFxn(orig_fxn_cb) 
print xxx 

for i in xxx: 
    print xxx[i]() 
+1

如果我可以,你的變量名稱不是最具描述性的。這肯定會讓我們難以跟蹤發生的事情。 – jathanism

+1

如何使用裝飾器? – jterrace

+0

@jterrace我會張貼作爲答案。 –

回答

4

你後:

from functools import wraps 

def notifier(f): 
    @wraps(f) 
    def wrapped(*args, **kwargs) 
     res = f(*args, **kwargs) 
     print "notify somebody..." 
     return res 
    return wrapped 

@notifier 
def original(): 
    print "original work" 

# or: original = notifier(original) 

original() 
original work 
notify somebody... 
+0

裝修者來拯救!順便說一句,你不必使用'functools.wraps',但它確保保留包裝(修飾)函數的文檔字符串和參數簽名,因此記住它是件好事。 – jathanism

+1

@jathanism:_「它確保保留參數簽名」_--很確定情況並非如此,您必須爲此獲取「裝飾器」模塊。 (通過生成python代碼作爲一個字符串)。 – Eric

+1

值得注意的是,你也可以明確地調用裝飾器。例如,當從名稱到函數創建你的'dict'時,你可以做'd ['foo'] = notifier(foo)''。 – abarnert

0

我不知道什麼是預期的輸出做,它似乎很好地工作在這裏。它將字典中的所有功能替換爲調用原件的副本,然後打印原始名稱和「尾部」。由於它取代了功能,它也執行它們。最後,您遍歷結果字典並再次執行它們。

如果您多次調用appendFxn,可能會給您帶來意想不到的行爲的是for i in orig_fxn_cb.keys():行。它引用全局orig_fxn_cb而不是參數fxn_cb,因此進一步調用不會更改地圖中的函數。

2

您遇到的問題與您在appendFxn函數中使用的cb變量有關。你的內部函數定義通過名稱來訪問這個值,所以它們最終都會引用相同的內部回調函數(無論哪個函數在迭代中最後出現)。

您可以在您的包裝功能的默認參數解決這個問題:

def appendFxn(fxn_cb): 
    appended_fxn_cb_new = dict() 
    for i in orig_fxn_cb.keys(): 
     cb = fxn_cb[i] 
     def fxn_tail(cb = cb):   # fix is here! 
      cb() 
      print cb.__name__, "tail" 

     appended_fxn_cb_new[i] = fxn_tail 
     appended_fxn_cb_new[i]() 
    return appended_fxn_cb_new 

使用默認參數結合的cb內部函數內電流值cb名。這樣,即使當原始cb變量設置爲新值時,現有函數也會保留舊值。 (你也可以使函數的參數爲​​cb = fxn_cb[i],如果需要,可以去掉外部的cb變量。)

+0

謝謝。這解決了我遇到的問題。 –