導入語句是否應該始終位於模塊的頂部?

PEP 08指出: 程序員

導入老是放在文件的頂部,緊隨任何模塊註釋和文檔字符串以後,以及模塊全局變量和常量以前。 api

可是,若是僅在極少數狀況下使用我要導入的類/方法/函數,那麼在須要時進行導入確定會更有效嗎? 模塊化

這不是嗎? 函數

class SomeClass(object):

    def not_often_called(self)
        from datetime import datetime
        self.datetime = datetime.now()

比這更有效? 單元測試

from datetime import datetime

class SomeClass(object):

    def not_often_called(self)
        self.datetime = datetime.now()

#1樓

當函數被調用零次或一次時,第一種變體的確比第二種變體更有效。 可是,在第二次及其後的調用中,「導入每一個調用」方法實際上效率較低。 請參閱此連接以獲取延遲加載技術,該技術經過執行「延遲導入」結合了兩種方法的優勢。 測試

可是,除了效率以外,還有其餘緣由致使您可能會偏心一個。 一種方法是使閱讀該模塊相關代碼的人更加清楚。 它們還具備很是不一樣的故障特徵-若是沒有「 datetime」模塊,第一個將在加載時失敗,而第二個在調用該方法以前不會失敗。 spa

補充說明:在IronPython中,導入可能比CPython中昂貴得多,由於代碼基本上是在導入時進行編譯的。 調試


#2樓

我沒必要擔憂過多地預先加載模塊的效率。 模塊佔用的內存不會很大(假設它足夠模塊化),啓動成本能夠忽略不計。 code

在大多數狀況下,您但願將模塊加載到源文件的頂部。 對於閱讀您的代碼的人來講,分辨哪一個函數或對象來自哪一個模塊變得容易得多。 對象

將模塊導入代碼中其餘地方的一個很好的理由是,若是該模塊用於調試語句中。

例如:

do_something_with_x(x)

我可使用如下命令調試它:

from pprint import pprint
pprint(x)
do_something_with_x(x)

固然,將模塊導入代碼中其餘位置的另外一個緣由是是否須要動態導入它們。 這是由於您幾乎別無選擇。

我沒必要擔憂過多地預先加載模塊的效率。 模塊佔用的內存不會很大(假設它足夠模塊化),啓動成本能夠忽略不計。


#3樓

在大多數狀況下,這樣作對於保持清晰性和明智性頗有用,但並不是老是如此。 如下是幾個可能會在其餘地方導入模塊的狀況的示例。

首先,您能夠擁有一個帶有如下形式的單元測試的模塊:

if __name__ == '__main__':
    import foo
    aa = foo.xyz()         # initiate something for the test

其次,您可能須要在運行時有條件地導入一些不一樣的模塊。

if [condition]:
    import foo as plugin_api
else:
    import bar as plugin_api
xx = plugin_api.Plugin()
[...]

在其餘狀況下,您可能會將導入放置在代碼的其餘部分中。


#4樓

這是一個折衷,只有程序員才能決定進行。

狀況1經過在須要以前不導入datetime模塊(並進行可能須要的任何初始化)來節省一些內存和啓動時間。 請注意,「僅在調用時」執行導入也意味着「在調用時每次」執行導入操做,所以,第一個調用以後的每一個調用仍會產生執行導入的額外開銷。

狀況2經過預先導入datetime來節省一些執行時間和延遲,這樣not_often_drawn()在調用時將更快地返回,而且也不會在每次調用時都致使導入開銷。

除了效率外,若是import語句在...前面,則更容易在前面看到模塊依賴性。 將它們隱藏在代碼中會使您更難於找到所需的模塊。

就我的而言,除了單元測試之類的東西外,我一般都遵循PEP,所以我不但願老是加載它,由於我知道除了測試代碼以外不會使用它們。


#5樓

Curt提出了一個很好的觀點:第二個版本更清晰,它將在加載時而不是之後失敗,而且出乎意料地失敗。

一般,我沒必要擔憂模塊的加載效率,由於它的速度(a)很是快,而(b)大多僅在啓動時發生。

若是必須在乎外的時刻加載重量級模塊,則使用__import__函數動態加載它們可能更有意義,並確保捕獲ImportError異常並以合理的方式對其進行處理。

相關文章
相關標籤/搜索