2014-01-08 92 views
0

我寫了順序地運行幾個功能,每一個取作其輸入前一個函數的輸出,從而以運行它,我要運行這行代碼清理嵌套調用

make_list(cleanup(get_text(get_page(URL)))) 

我只是覺得這個醜陋而且效率低下,有沒有更好的方法來進行順序函數調用?

+0

合併多個功能爲一體?查看[代碼氣味](http://en.wikipedia.org/wiki/Code_smell)。欲瞭解更多信息,我們需要更多關於你的功能的細節。 –

+0

我可能是一個異常,但我不覺得難以理解。而且由於你必須實際進行所有這些函數調用,所以其他任何方法都會帶來額外的開銷,儘管很小,所以我認爲任何其他方式都不會更高效。然而,調試有點困難,因爲所有的中間臨時對象...... –

回答

5

真的,這與任何相同您想要重構常用複雜表達式或語句的情況:只需將表達式或語句轉換爲函數即可。事實上,你的表達恰好是函數調用的組合並沒有什麼區別(但在下面看到)。

所以,很明顯的事情是寫在一個地方組成的功能整合在一起的包裝功能,因此在其他地方你可以做一個簡單的調用包裝:

def get_page_list(url): 
    return make_list(cleanup(get_text(get_page(url)))) 

things = get_page_list(url) 
stuff = get_page_list(another_url) 
spam = get_page_list(eggs) 

如果你不需要總是調用完全相同的函數鏈,你總是可以分解出你經常調用的部分。例如:

def get_clean_text(page): 
    return cleanup(get_text(page)) 
def get_clean_page(url): 
    return get_clean_text(get_page(url)) 

這個重構也將打開大門,使代碼有點冗長,但容易調試了很多,因爲它僅出現多次,一旦改爲:

def get_page_list(url): 
    page = get_page(url) 
    text = get_text(page) 
    cleantext = cleanup(text) 
    return make_list(cleantext) 

如果您發現自己需要經常對組合函數進行這種重構,您總是可以編寫一個幫助程序來生成重構函數。例如:

def compose1(*funcs): 
    @wraps(funcs[0]) 
    def composed(arg): 
     for func in reversed(funcs): 
      arg = func(arg) 
     return arg 
    return composed 

get_page_list = compose1(make_list, cleanup, get_text, get_page) 

如果你想要一個更復雜的compose功能(即,例如,允許各地傳遞多個ARGS /返回值),它可以得到一個有點複雜的設計,所以你可能想看看周圍用於各種現有實現的PyPI和ActiveState。

2

你可以嘗試這樣的事情。我總是喜歡把火車殘骸分開(「Clean Code」這本書稱這些嵌套功能爲火車殘骸)。這是更容易閱讀和調試。請記住,您可能花費兩倍的時間閱讀代碼,而不是編寫代碼,以便更易於閱讀。你稍後會感謝你。

url = get_page(URL) 
url_text = get_text(url) 
make_list(cleanup(url_text)) 

# you can also encapsulate that into its own function 
def build_page_list_from_url(url): 
    url = get_page(URL) 
    url_text = get_text(url) 
    return make_list(cleanup(url_text)) 
+0

是的,這就是我正在做的 –

0

選項:

  1. 重構:實現這個系列的函數調用爲一體,恰當地命名法。
  2. 調查裝飾。它們是以這種方式用於「鏈接」功能的句法糖。例如。作爲裝飾者實施cleanupmake_list,然後用它們裝飾get_text
  3. 撰寫功能。請參閱this answer中的代碼。
0

你可以縮短這樣的結構有類似以下內容:

class ChainCalls(object): 
    def __init__(self, *funcs): 
     self.funcs = funcs 
    def __call__(self, *args, **kwargs): 
     result = self.funcs[-1](*args, **kwargs) 
     for func in self.funcs[-2::-1]: 
      result = func(result) 
     return result 

def make_list(arg): return 'make_list(%s)' % arg 
def cleanup(arg): return 'cleanup(%s)' % arg 
def get_text(arg): return 'get_text(%s)' % arg 
def get_page(arg): return 'get_page(%r)' % arg 

mychain = ChainCalls(make_list, cleanup, get_text, get_page) 

print(mychain('http://is.gd')) 

輸出:

make_list(cleanup(get_text(get_page('http://is.gd'))))