在python中,如果你需要一個來自不同包的模塊,你必須導入它。來自Java背景,這是有道理的。爲什麼在需要使用全名時導入?
import foo.bar
雖然什麼沒有意義,爲什麼我需要使用全名,只要我想使用欄?如果我想使用全名,爲什麼我需要導入?不使用全名立即描述我正在尋找哪個模塊?
當from foo import bar
應該是import foo.bar
時,看起來有點多餘。也有點模糊,爲什麼我要使用全名時必須導入。
在python中,如果你需要一個來自不同包的模塊,你必須導入它。來自Java背景,這是有道理的。爲什麼在需要使用全名時導入?
import foo.bar
雖然什麼沒有意義,爲什麼我需要使用全名,只要我想使用欄?如果我想使用全名,爲什麼我需要導入?不使用全名立即描述我正在尋找哪個模塊?
當from foo import bar
應該是import foo.bar
時,看起來有點多餘。也有點模糊,爲什麼我要使用全名時必須導入。
的事情是,即使Python的import
聲明旨在看類似於Java的,他們做的引擎蓋下完全不同的東西。如您所知,在Java中,import
語句實際上只不過是編譯器的提示。它基本上爲一個完全限定的類名設置了一個別名。例如,當你寫
import java.util.Set;
它告訴,在整個該文件中,當你寫Set
,你的意思是java.util.Set
編譯器。並且如果寫s.add(o)
其中s
是Set
類型的對象,則編譯器(或更確切地說,接頭)熄滅並發現add
方法在Set.class
和對它的引用提出。
但是在Python,
(這是一個虛構的模塊的方式)做完全不同的事情。由於Python是一種具有動態分辨率的解釋型語言,因此沒有編譯器可以查找任何util.set
模塊的代碼。會發生什麼事在Python是解釋查找一個名爲util
與命名set
裏面模塊封裝和裝載包和模塊,並且在這個過程中,它實際上創建了一個名爲util
名爲set
屬性的對象。 (沒錯,包和模塊是Python中實際的第一類對象。)你可以把上面的語句作爲
util = __import__('util.set')
其中函數__import__
產生具有所謂set
屬性的對象。事實上,實際上,當你導入模塊時會發生什麼 - 請參閱documentation for __import__
。所以你看,當你導入一個Python模塊時,你真正得到的僅僅是一個對應於頂級包util
的對象,並且爲了訪問set
,你需要經歷這個。
正如在至少一種其他的答案中提到,你可以寫
from util import set
或
import util.set as set
這仍然與模塊set
進口它包util
,而是創建一個變量util
,它會創建一個變量set
,它指的是util.set
。在幕後,這工作有點像
_util = __import__('util', fromlist='set')
set = _util.set
del _util
在前者的情況下
,或者
_util = __import__('util.set')
set = _util.set
del _util
在後者(雖然這兩個方面基本上做同樣的事情)。這種形式在語義上更像Java所做的;它將別名(set
)定義爲通常只能由完全限定名稱(util.set
)訪問的內容。
可以縮短它,如果你想:
import foo.bar as whateveriwant
使用全稱防止兩個包具有相同名稱的子模塊從重挫對方。
您對Python導入工作方式感到困惑。 (我剛開始的時候也是這樣。)在Python中,不能像Java中那樣簡單地用全名來引用模塊中的某些內容;無論您如何參考導入的項目,您都必須先導入模塊。嘗試在解釋器中輸入math.sqrt(5)
,而不先導入math
或math.sqrt
,看看會發生什麼。
無論如何...原因import foo.bar
你需要使用foo.bar
而不是bar
是爲了防止意外的命名空間衝突。例如,如果你做import foo.bar
,然後import baz.bar
?
你當然可以選擇做import foo.bar as bar
(即別名),但如果你這樣做,你可以只使用from foo import bar
。 (編輯:除了當你想要導入方法和變量的時候,那麼你必須使用from ... import ...
語法,這包括你想要導入一個方法或變量而沒有別名的例子,也就是說,如果bar
是一個方法,你不能簡單地做import foo.bar
或可變)。
'因爲某些技術原因,我無法再找到''import foo.bar as bar'似乎比'from foo import bar'更受歡迎。 – Philipp 2010-07-06 18:24:28
@Philipp:如果是這樣,那對我來說是新聞。 – 2010-07-06 18:29:00
@Philipp:http://docs.python.org/py3k/howto/doanddont.html#from-module-import-name1-name2沒有提及那裏的任何偏好。實際上,在所有情況下都不能使用前者,因爲在嘗試導入方法或數據成員時失敗。 – JAB 2010-07-06 18:35:41
除了在Java中,Python import foo.bar
聲明,您將使用foo.bar
所提及的東西。
這符合Python的哲學,明確比隱含更好。有更多的編程語言使得模塊間依賴關係比Java更明確,例如Ada。
使用全名可以消除來自不同模塊的相同名稱的定義歧義。
在Python中,導入並不僅僅表明您可能會使用某些東西。導入實際上在模塊級執行代碼。您可以將導入視爲「解釋」和創建函數的時刻。然後,處於_____init_____.py級別或不在函數或類定義內的任何代碼都會發生。
導入還可以製作整個模塊名稱空間的廉價副本,並將其放入文件/模塊/其導入的任何位置的名稱空間中。然後IDE會列出您可能開始爲命令完成鍵入的功能。
請注意,當多次導入模塊或程序包時,模塊或程序包的__init __。py'文件中的任何可執行代碼將僅在首次導入時執行。這很好。 – JAB 2010-07-06 18:22:43
有一個在標準庫中的模塊調用io
:
In [84]: import io
In [85]: io
Out[85]: <module 'io' from '/usr/lib/python2.6/io.pyc'>
也有在scipy
一個模塊調用io
:
In [95]: import scipy.io
In [96]: scipy.io
Out[96]: <module 'scipy.io' from '/usr/lib/python2.6/dist-packages/scipy/io/__init__.pyc'>
如果你想在同一腳本中使用這兩個模塊,那麼命名空間是區分這兩者的便利方式。
In [97]: import this
The Zen of Python, by Tim Peters
...
Namespaces are one honking great idea -- let's do more of those!
Python哲學的一部分是explicit is better than implicit。第一次嘗試從包中訪問某些東西時,Python可以自動導入,但這並不明確。
我還猜測,包初始化會更加困難,如果進口自動的,因爲它不會始終如一的代碼來完成。
您不必使用全名。試試這些
from foo import bar
import foo.bar as bar
import foo.bar
bar = foo.bar
from foo import *
爲什麼明確的進口都不錯的幾個原因之一:
你是什麼意思「需要導入」?你希望foo.bar的工作,而不必先導入它?那麼你怎麼知道foo是一個模塊而不是普通變量 – mb14 2010-07-06 18:12:40
@ mb14,在Java中,你可以直接使用另一個包中的類,而不需要通過在代碼中顯式使用完全限定的類名和包名來導入。例如,您可以在源代碼中將Java的List接口引用爲「java.util.List」,或者先將其導入,然後將其簡稱爲「List」。 Python對它的用法,對於來自Java的用戶,感覺就像你在導入java.util.List,但是你仍然需要在你的代碼中寫出「java.util.List」而不是「List」。 – Jeff 2010-07-06 18:25:26