2015-07-01 107 views
-1

目標: 執行__init__變量(對象創建)後動態生成方法。執行__init__後動態生成方法

第一(未動力爲例):

string_custom_method='''def custom_method(self): 
    print self.text''' 

class Foo: 
    def __init__(self): 
     self.text='foo' 

    exec string_custom_method 

Foo().custom_method() 

這個腳本是非常簡單,它的作品好。問題是,我居然需要自定義的string_custom_method內容:

string_custom_method='''def custom_method(self):\n''' 

def create_custom_method(print_end): 
    global string_custom_method 
    string_custom_method+='\t'+'print self.text\n' 
    if print_end: 
     string_custom_method+='\t'+'print "end"' 

class Faa: 
    def __init__(self): 
     self.text='faa' 
     create_custom_method(True) 

    exec string_custom_method 

Faa().custom_method() 

的問題是,我得到以下錯誤:

def custom_method(self): 
         ^
SyntaxError: unexpected EOF while parsing 

所以我的結論是,蟒蛇讀取方法的樹前執行__init__這在這種情況下是一個問題。

閱讀一些有關這之後,我想,也許通過staticmethod這樣的:self.custom_method = staticmethod(...)可以工作, 但問題是,custom_method它沒有在全球範圍內定義,我無法定義它,直到__init__是執行。

有沒有什麼辦法讓這項工作?我知道這個例子看起來不太有用,但我真的需要它來做我的程序!

+2

你願意解釋一下你的真實* *使用情況,而不是這個虛擬實例嗎?我認爲你在這裏有一個XY問題 - 他們當然是比使用exec更好的解決方案(提示:99.90%,exec和eval是錯誤的解決方案)。 –

+0

@brunodesthuilliers這個虛擬示例解釋了相當不錯的問題,但沒有發佈100行我的程序。在我的程序「custom_method」中,它實際上是增加了多個條件和變量的循環。條件和變量並不總是有用的。它依賴於'__init __(self,var1,var2,var3)'定義的變量。如果刪除無用​​的變量和條件,我會增加循環的速度,這是我需要的。 – rsm

+1

那麼,爲什麼你要以不必要的條件得到評估的方式編寫代碼呢?對於* actual *問題,可能有許多解決方案,可能是子類,方法提取,策略模式等等。但動態方法創建幾乎肯定不是它。我同意@brunodesthuilliers,這似乎是一個XY問題。 –

回答

1

工作方案,預編譯的代碼:

funtpl = """ 
def __TheFunction__(self): 
    %s 

""" 

def create_custom_method(print_end): 
    # this would be better done by a template engine I think 
    source = ['print self.text'] 
    if print_end: 
     source.append('print "end"') 

    source = funtpl % "\n ".join(source) 
    bytecode = compile(source, "<string>", "exec",) 
    locals = {} 
    eval(bytecode, globals(), locals) 
    return locals["__TheFunction__"] 



class Faa(object): 
    def __init__(self, print_end): 
     self.text='faa' 
     fun = create_custom_method(print_end) 
     self.custom_method = fun.__get__(self, type(self)) 

f = Faa(True) 
f.custom_method() 

好運運行f.custom_method直通步調試

0

__init__()在執行exec string_custom_method行後被調用。 Class首先被構造,該行在類範圍內,所以它在類正在被構造的時候被執行,然後python帶着類創建實例,在這個點上調用__init__()

1

如果這樣做的動機是你的循環執行了數十億次,我強烈推薦使用numba jit。

+0

感謝您的評論,我會實施它到我的解決方案。它會使它更快:) – rsm

0

看來,解決方案需要一個不同的方法:

def create_custom_method(print_end): 
    string_custom_method = 'print self.text\n' 
    if print_end: 
     string_custom_method = string_custom_method +'print "end"' 

    return string_custom_method 

class Faa: 
    def __init__(self): 
     self.text='faa' 
     self.cs=create_custom_method(True) 

    def custom_method(self): 
     exec self.cs 

a = Faa() 
a.custom_method() 

定義整個方法複雜太多的代碼。只是定義內容方法更容易。

+0

這也適用,但是由於你在每個函數調用時都調用了'exec',python必須解析字符串,編譯爲字節碼等,然後執行它。你以前的預編譯方法比較好。 –

+0

@AmitUpadhyay耶,但我不能讓工作的代碼。這個問題的另一個問題是,如果'string_custom_method'包含'return'關鍵字,它就不再起作用了。 – rsm