2013-11-03 62 views
4

我在某處讀到python中的函數內部定義函數是不好的,因爲它使python在外部函數被調用時創建一個新的函數對象。有人基本上這樣說:當在python中使用函數時,需要創建哪些對象?

#bad 
def f(): 
    def h(): 
     return 4 
return h() 

#faster 
def h(): 
    return 4 

def f(h=h): 
    return h() 

這是真的嗎?此外,當我有一個什麼樣的情況下這樣一噸常量:

x = # long tuple of strings 
# and several more similar tuples 
# which are used to build up data structures 

def f(x): 
    #parse x using constants above 
    return parse dictionary 

它更快,如果我把所有的常數f的定義中?或者我應該將它們留在外面並將它們綁定到關鍵字參數中的本地名稱上?不幸的是,我沒有任何數據做計時,所以我想我正在問你有關類似事情的經驗。

+3

我不擔心速度問題,並專注於最易讀/可維護的內容,如果代碼成爲瓶頸,您可以隨後對其進行優化。 – GWW

+2

正如有人說每次有關時間的事情出現時,「過早優化是萬惡之源」!只有當程序很慢時才擔心速度(儘管我很欣賞你可能仍然想知道答案是出於好奇)。 – rlms

+1

另外,如果您關心執行不同版本的相同代碼所需的時間,請使用'timeit'模塊。至於在函數中做函數有時候有一個函數甚至可以返回一個函數。 –

回答

0

在我的測試中,做所需的最快方法是定義我需要的所有常量,然後製作需要這些常量的函數列表,然後將函數列表傳遞給主函數。我使用了dis.dis,cProfile.runtimeit.timeit進行了測試,但我無法找到基準測試腳本,因此無法重新編寫並提供結果。

5

簡短的回答你的問題 - 這是真的。每次調用外部函數時都會創建內部函數,這需要一些時間。與對局部變量的訪問相比,對功能以外定義的對象的訪問速度也較慢。

但是,您還問了一個更重要的問題 - 「我應該關心嗎?」。回答這個,幾乎總是,NO。性能差異將非常小,並且您的代碼的可讀性更有價值。所以,如果你認爲這個函數屬於其他函數的主體,在其他地方沒有任何意義 - 只要把它放在裏面,並不關心性能(至少,直到你的分析器告訴你,否則)。

0

當執行一個函數時,需要執行裏面的所有代碼。所以當然,簡單地說,放在函數中的越多,執行此操作所需的Python就越多。特別是當你需要在函數的運行時構建而不是,那麼你可以通過將它放在一個較高的範圍中來節省很多,以便Python只需要查看它而不是再次生成它並分配(臨時)內存以在函數的短時間內保存它。

所以在你的情況下,如果你有一個大的元組或任何不依賴於輸入x的函數f,那麼是的,你應該把它存儲在外面。

現在您提到的另一件事是使用關鍵字參數的函數或常量的作用域查找。一般來說,在外部範圍查找變量比在本地範圍內查找變得更加昂貴。所以是的,當你在模塊級別定義這些常量並在函數內部訪問它們時,查找將比在函數內定義常量更加昂貴。但是,實際上在函數內部定義它們(使用內存分配和實際的數據生成)可能會更昂貴,所以它不是一個好選擇。

現在,您可以將常量作爲關鍵字參數傳遞給函數,因此函數內部的查找將是本地作用域查找。但很多時候,你並不需要那些常量。你可能會在函數中訪問它一次或兩次,這絕對不值得爲函數添加另一個參數的開銷,並且可能會傳遞不同的/不兼容的東西(中斷函數)。

如果你知道你訪問某些全球東西多次,然後在它看起來,全球東西了一次然後使用局部變量在所有進一步的地方函數的頂部創建一個局部變量。這也適用於成員查找,這也可能很昂貴。

一般來說,這些都是相當微觀的優化,如果你這樣或那樣做,你不可能遇到任何問題。所以我建議你先寫清楚代碼,並確保其餘部分運行良好,如果你確實遇到性能問題,那麼你可以檢查問題出在哪裏。

相關問題