2013-02-03 92 views
2

python是否有辦法攔截(和更改)已編譯函數的返回值?攔截返回

的基本思路是:我有一個函數

def a (n, acc): 
    if n == 0: return acc 
    return a (n - 1, acc + n) 

,我要修補它,這樣它的行爲是這樣的:

def a (n, acc): 
    if n == 0: return acc 
    return lambda: a (n - 1, acc + n) 

是否可以寫一個函數f,如f (a)會產生一個函數,如同在第二個代碼片段中那樣?

我可以通過inspect修補函數,如果python可以找到它的源代碼然後返回新編譯的修補函數,但這不會有多大幫助。

回答

0

盧克的答案是非常詳細的,但是這可能仍然是有用的:

>>> def f(*args, **kwargs): 
...  return lambda: a(*args, **kwargs) 
... 
>>> f(10, 0)() 
55 
1

感謝您的輸入。我沒有看到明顯的:

def inject (f): 
    def result (*args, **kwargs): 
     return lambda: f (*args, **kwargs) 
    return result 

我接受了davidchambers的回答,因爲他把我推向了正確的方向。

1

如果我正確理解你想要的東西,理論上是不可能的;您似乎要描述的轉換是對等效函數有不同影響的轉換,具體取決於其源代碼的表面細節,這些細節可能不會以編譯後的形式保留。例如,考慮給定函數的以下兩個版本:

def a (n, acc): 
    print('called a(%d,%d)' % (n, acc)) 
    if n == 0: return acc 
    return a (n - 1, acc + n) 

def a (n, acc): 
    print('called a(%d,%d)' % (n, acc)) 
    if n == 0: return acc 
    ret = a (n - 1, acc + n) 
    return ret 

顯然它們在功能上是相同的。在源代碼中,唯一的區別是前者直接在某個表達式上使用return,而後者則將該表達式的結果保存到局部變量中,然後在該變量上使用return。在編制的形式中,根本不需要任何差異。

現在考慮「打補丁」的版本:

def a (n, acc): 
    print('called a(%d,%d)' % (n, acc)) 
    if n == 0: return acc 
    return lambda: a (n - 1, acc + n) 

def a (n, acc): 
    print('called a(%d,%d)' % (n, acc)) 
    if n == 0: return acc 
    ret = a (n - 1, acc + n) 
    return lambda: ret 

顯然,這些都是非常不同:例如,如果n3acc是0,那麼前者打印called a(3,0)並返回打印called a(2,3)功能和返回打印called a(1,5)並返回一個函數,該函數打印called a(0,6)並返回6,而後者打印called a(3,0)called a(2,3)called a(1,5)called a(0,6)並返回一個函數,該函數返回一個函數一個返回函數的函數,返回6

更廣泛的區別在於,每次調用新的返回值時,第一個「修補」函數執行一個計算步驟,而第二個「修補」版本執行初始調用期間所有計算步驟,以及只是爲了娛樂而安排了一系列隨後的電話。只要存在副作用(例如打印消息,或者如遞歸太深以至於溢出堆棧),這種差異就很重要。如果調用者引入了副作用也可能很重要:請注意,這些函數只會遞歸,直到其他一些代碼重新定義a,此時計劃繼續重新調用的版本之間存在差異a以及已完成所有呼叫的版本。

由於您無法區分兩個「未打補丁」版本,因此顯然無法生成您的轉換意味的獨特「已打補丁」版本。

+0

您可以很好地區分兩個未打補丁的版本。第一個以「CALL_FUNCTION RETURN_VALUE」結尾,後一個以「CALL_FUNCTION STORE_FAST LOAD_FAST RETURN_VALUE」結尾。 – Hyperboreus

+0

@Hyperboreus:Python解釋器不允許優化嗎? – ruakh

+0

我不確定是否可以優化創建局部變量。我現在不允許他們這樣做。我的不是。我最後的評論來自反彙編。 – Hyperboreus