2015-09-06 84 views
0

有沒有在Python 3.x中使用標準庫在運行時編譯函數並通過函數對象使用它的方法?如何在運行時編譯函數?

我試過如下:

class A:  
    def meth1(self, par1): 
     print("in A.meth1: par1 =", par1) 

a = A() 
s = '''def meth1(self, par1): 
    print("in recompiled A.meth1: par1 = ", par1)''' 
a.meth1.__func__.__code__ = compile(s, __file__, "exec") 
a.meth1("via meth1") 

但是,這給出了一個錯誤:

TypeError: <module>() takes 0 positional arguments but 2 were given

在爲compile()它writen與它編譯的代碼可以與eval()exec()運行的文檔。有沒有辦法編譯一個函數,並通過沒有eval()和exec()的函數對象來調用它?

+2

我想知道問題是什麼,需要自修改代碼作爲解決方案? –

+0

@Roland我試圖使用一些僅在運行時才知道的信息(速度增強)。 –

+0

也許你應該發表一個問題如何處理這個問題,但有更多的細節。可能有更好的方法。我假設你已經對代碼進行了剖析,以顯示程序大部分時間花在哪裏? –

回答

2

你可能有過exec()eval()運行它只是執行功能定義。您可以將它傳遞給一個單獨的環境,您必須自己從中提取該函數(正如用戶HelloWorld正確表示的那樣,Python不能「猜測」您的意思)。

回到你的例子,在這裏我首先創建一個空的環境environment,然後將編譯的代碼和字典傳遞給exec以評估定義。使用types庫中的MethodType類,必須將該函數轉換爲綁定方法,將該類或實例作爲第二個參數提供。然後,您可以將綁定方法附加到原始實例。

import types 

class A:  
    def meth1(self, par1): 
     print("in A.meth1: par1 =", par1) 

a = A() 
s = '''def meth1(self, par1): 
    print("in recompiled A.meth1: par1 = ", par1)''' 

code = compile(s, __file__, "exec") 

environment = {} 
exec(code, environment) 
a.meth1 = types.MethodType(environment["meth1"], A) 

a.meth1("via meth1") 
+0

幾乎是魔法。謝謝! –

1

jojonas給出了一個很好的答案,這個帖子是一個額外的評論比答案。

您不能簡單地編譯一個字符串並從類中替換代碼對象。在您調用compile後得到的是一個代碼對象。例如。看看下面的代碼。

obj = ''' 
def meth1(self, par1): 
    print("in recompiled A.meth1: par1 = ", par1) 

def meth2(self, par1): 
     print("in recompiled A.meth2: par1 = ", par1) 
''' 
a.meth1.__func__.__code__ = compile(obj, __file__, "exec") # What should happen here? 

正如你從這個例子中看到的,我們編譯了一個不能簡單地附加到類的整個範圍。你需要做的是從代碼對象中提取meth1函數,然後使用它。

你應該看看下面有關代碼對象的漂亮文章,它給你一些很好的見解。

http://late.am/post/2012/03/26/exploring-python-code-objects.html

+0

感謝您的鏈接,我會檢查它。 –