2008-10-11 57 views
70

我有點困惑於你可以用Python導入模塊的多種方式。Python導入有什麼好的經驗法則?

import X 
import X as Y 
from A import B 

我一直在閱讀了關於作用域和命名空間,但我想對什麼是最好的策略,在哪些情況下,爲什麼一些實用的建議。應該導入模塊級別還是方法/功能級別?在__init__.py還是在模塊代碼本身?

我的問題並沒有真正回答「Python packages - import by class, not file」,但它顯然是相關的。

+0

請參閱http://stackoverflow.com/questions/187453/import-package-vs-import-packagespecifictype – 2008-10-11 10:33:53

+0

請參閱http://stackoverflow.com/questions/186472/from-x-import-a-versus-import -x-xa – 2008-10-11 10:35:11

回答

63

在我們公司的生產代碼,我們嘗試遵循以下規則。

我們將進口的文件的開頭,主文件的文檔字符串之後,例如:

""" 
Registry related functionality. 
""" 
import wx 
# ... 

現在,如果我們進口一類是進口模塊中爲數不多,我們導入了直接命名,因此,在代碼中,我們只需要使用的最後部分,例如:

from RegistryController import RegistryController 
from ui.windows.lists import ListCtrl, DynamicListCtrl 

然而有模塊,包含幾十個類,如所有可能的例外列表。然後我們導入模塊本身和借鑑它的代碼:

from main.core import Exceptions 
# ... 
raise Exceptions.FileNotFound() 

我們使用import X as Y儘可能少,因爲它使搜索特定模塊或類困難的使用。然而,有時候,你有,如果你想導入具有相同名稱的兩個班,但在不同的模塊存在,例如,使用它:

from Queue import Queue 
from main.core.MessageQueue import Queue as MessageQueue 

一般來說,我們不這樣做內進口的方法 - 他們只是讓代碼更慢,更不可讀。有些人可能會發現這是一種輕鬆解決循環導入問題的好方法,但更好的解決方案是代碼重組。

+4

「他們只是讓代碼變慢」並非如此。它已經在這裏測試:http://stackoverflow.com/a/4789963/617185 – kmonsoor 2015-06-08 07:17:25

12

我通常在模塊級使用import X。如果您只需要模塊中的單個對象,請使用from X import Y

只有使用import X as Y以防萬一您遇到名稱衝突。

我只用在功能級別進口導入的東西,我需要當模塊作爲主模塊,如:

def main(): 
    import sys 
    if len(sys.argv) > 1: 
    pass 

HTH

0

如果您有相同模塊/類的不同實現,則import X as Y很有用。

對於一些嵌套的try..import..except ImportError..import,您可以隱藏代碼中的實現。見lxml etree import example

try: 
    from lxml import etree 
    print("running with lxml.etree") 
except ImportError: 
    try: 
    # Python 2.5 
    import xml.etree.cElementTree as etree 
    print("running with cElementTree on Python 2.5+") 
    except ImportError: 
    try: 
     # Python 2.5 
     import xml.etree.ElementTree as etree 
     print("running with ElementTree on Python 2.5+") 
    except ImportError: 
     try: 
     # normal cElementTree install 
     import cElementTree as etree 
     print("running with cElementTree") 
     except ImportError: 
     try: 
      # normal ElementTree install 
      import elementtree.ElementTree as etree 
      print("running with ElementTree") 
     except ImportError: 
      print("Failed to import ElementTree from any known place") 
2

我一般儘量選用正規import modulename,除非模塊名稱是長,或者經常使用..

例如,我會做..

from BeautifulSoup import BeautifulStoneSoup as BSS 

..所以我可以做的,而不是soup = BSS(html)BeautifulSoup.BeautifulStoneSoup(html)

或..

from xmpp import XmppClientBase 

..instead進口XMPP的全時我只用XmppClientBase

的使用import x as y是方便的,如果你想要導入非常長的方法名稱,或者防止破壞現有的import/variable/class/method(so mething你應該儘量完全避免,但它並不總是可能的)

說我要運行從另一種語言的main()函數,但我已經有一個main()函數..

from my_other_module import main as other_module_main 

..wouldn't取代我main功能與my_other_module的main

哦,一兩件事 - 不要做from x import * - 它使你的代碼很難理解,因爲你不能輕易看到的方法,由(from x import *; from y import *; my_func()出來 - 其中是my_func定義的?)

在任何情況下,你可能只是import modulename,然後做modulename.subthing1.subthing2.method("test") ...

from x import y as z東西純粹是爲了方便 - 使用它時,它會讓你的代碼更易於讀取或寫入!

+2

恕我直言,這裏有一些誤解...... 1)*「導入整個xmpp時,我只使用...」*:這錯誤地暗示這種方法是「更輕」的,但無論您導入了多少個對象,Python都會加載並初始化整個模塊。至於「命名空間污染」,兩者都會向本地命名空間添加一個* single *條目:`xmpp`或`XmppClientBase`。所以這個基本原理是無效的 – MestreLion 2012-04-13 19:46:48

+2

2)*「因爲你不能容易地看到方法來自哪裏」*:對*進口是真的,但*也*對於使用`as`來說只是爲了縮短模塊/對象名稱。 `BSS()`從哪裏來?使用`from`也會遭受(一點):`from mymod import MyClass`。現在有300行,你會看到MyOtherClass(MyClass)類:`...現在,MyClass又是從哪裏來的?讀者被迫總是回頭查看從 – MestreLion 2012-04-13 19:57:42

5

其他人已經覆蓋了這裏的大部分地方,但我只想添加一個案例,我將使用import X as Y(暫時),當我嘗試新版本的類或模塊時。

因此,如果我們正在遷移到模塊的新實現,但不想一次性削減代碼庫,我們可能會編寫一個xyz_new模塊,並在我們遷移的源文件中執行此操作:

import xyz_new as xyz 

然後,一旦我們削減了整個代碼庫,我們剛剛與xyz_new更換xyz模塊和更改所有的進口回

import xyz 
+0

導入哪個對象的地方。你擊敗了我。 'X import *'的 – 2008-10-11 14:30:29

3

不這樣做:

from X import * 

除非你確定你會使用該模塊中的每一件東西。即便如此,你也應該重新考慮採用不同的方法。

除此之外,這只是一個風格問題。

from X import Y 

很好,可以節省您很多打字的時間。我傾向於使用,當我使用的東西在裏面相當頻繁,但如果你從一個模塊中導入了很多,你可以用import語句看起來像這樣結束:

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P 

你得到的理念。那時進口像

import X 

變得有用。要麼這樣,要麼我非常頻繁地使用X中的任何東西。

+0

'確實有其用途 - 例如與pyparsing。 – 2008-10-12 21:44:51

34

讓我貼的談話對由Guido van Rossum的開始Django的開發郵件列表中的一部分:

[...] 例如,它是谷歌的Python風格指南的部分[1]所有 導入必須導入模塊,而不是該模塊的類或函數。有更多的類和功能比 模塊更多,因此如果它帶有模塊名稱前綴,那麼回顧某個特定事物的來源是多麼容易。通常多個模塊 碰巧定義了具有相同名稱的東西 - 因此,代碼 的讀者不必返回到文件的頂部以查看哪個 模塊導入了給定名稱。

來源:http://groups.google.com/group/django-developers/browse_thread/thread/78975372cdfb7d1a

1:http://code.google.com/p/soc/wiki/PythonStyleGuide#Module_and_package_imports

1

當你有一個良好的書面圖書館,有時情況蟒蛇,你應該只需要導入它,使用它,因爲它。編寫良好的圖書館往往需要自己的生活和語言,導致愉快的閱讀代碼,你很少參考圖書館。當一個圖書館寫得很好時,你不需要重新命名或其他任何東西。

import gat 

node = gat.Node() 
child = node.children() 

有時候不可能這樣寫,或者你想從你導入的庫中刪除東西。

from gat import Node, SubNode 

node = Node() 
child = SubNode(node) 

有時候你的很多事情做,如果你的進口串溢出80列,這是好主意,這樣做:

from gat import (
    Node, SubNode, TopNode, SuperNode, CoolNode, 
    PowerNode, UpNode 
) 

的最佳策略是把所有這些進口上的文件頂部。按字母順序排序,首先導入表達式,然後從導入表格中導入。

現在我告訴你爲什麼這是最好的約定。

Python完全可以有一個自動導入,當從全局名稱空間中找不到時,它會從主導入中查找該值。但這不是一個好主意。我很快解釋爲什麼。除了實現比簡單導入更復雜之外,程序員不會考慮依賴關係,並且從導入的東西中找出應該採取其他方式而不是僅僅關注導入。

需要找出依賴性是人們討厭「從...進口*」憎恨的一個原因。儘管存在一些你需要這樣做的不好的例子,例如opengl -wrappings。

因此,導入定義對定義程序的依賴性實際上很有價值。這是你應該如何利用它們的方式。從他們你可以快速檢查一些奇怪的功能從哪裏進口。

0

我在不使用

from X import * 

的事實,但在我的情況下,與賈森是(我不是專家程序員,所以我的代碼不符合編碼風格太清楚)我通常做在我的節目中包含的程序版本,作者,錯誤信息和所有的東西,所以文件中的所有常量的文件只是定義,那麼我做進口

from const import * 

這爲我節省了很多時間。但它是唯一具有該導入的文件,這是因爲該文件內的所有文件都只是變量聲明。

在具有類和定義的文件中執行這種導入可能很有用,但是當您必須閱讀該代碼時,您會花費大量時間來查找函數和類。上述

8

有人說

from X import A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P 

相當於

import X 

import X允許直接修飾A-P,而from X import ...創建A-P的拷貝。對於from X import A..P,如果修改了變量,則不會更新變量。如果你修改它們,你只修改你的副本,但X確實知道你的修改。

如果A-P是功能,您將不會知道區別。

相關問題