2010-07-06 51 views
9

在python中,如果你需要一個來自不同包的模塊,你必須導入它。來自Java背景,這是有道理的。爲什麼在需要使用全名時導入?

import foo.bar 

雖然什麼沒有意義,爲什麼我需要使用全名,只要我想使用欄?如果我想使用全名,爲什麼我需要導入?不使用全名立即描述我正在尋找哪個模塊?

from foo import bar應該是import foo.bar時,看起來有點多餘。也有點模糊,爲什麼我要使用全名時必須導入。

+0

你是什麼意思「需要導入」?你希望foo.bar的工作,而不必先導入它?那麼你怎麼知道foo是一個模塊而不是普通變量 – mb14 2010-07-06 18:12:40

+4

@ mb14,在Java中,你可以直接使用另一個包中的類,而不需要通過在代碼中顯式使用完全限定的類名和包名來導入。例如,您可以在源代碼中將Java的List接口引用爲「java.util.List」,或者先將其導入,然後將其簡稱爲「List」。 Python對它的用法,對於來自Java的用戶,感覺就像你在導入java.util.List,但是你仍然需要在你的代碼中寫出「java.util.List」而不是「List」。 – Jeff 2010-07-06 18:25:26

回答

23

的事情是,即使Python的import聲明旨在類似於Java的,他們做的引擎蓋下完全不同的東西。如您所知,在Java中,import語句實際上只不過是編譯器的提示。它基本上爲一個完全限定的類名設置了一個別名。例如,當你寫

import java.util.Set; 

它告訴,在整個該文件中,當你寫Set,你的意思是java.util.Set編譯器。並且如果寫s.add(o)其中sSet類型的對象,則編譯器(或更確切地說,接頭)熄滅並發現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)訪問的內容。

6

可以縮短它,如果你想:

import foo.bar as whateveriwant 

使用全稱防止兩個包具有相同名稱的子模塊從重挫對方。

+1

+1,這是OP正在尋找的正確答案。也許編輯說「酒吧」,而不是「whateveriwant」?這可能會使它更清楚地表明它提供了所需的功能。 – Cam 2010-07-06 18:15:41

+3

它接近於正確的答案,但不能解釋*爲什麼* Python展示了這種行爲。 – Philipp 2010-07-06 18:18:01

+1

而且它比'from foo import bar'略微更加冗長。 「import foo.bar as bar」== 21個字符,「從foo導入欄」== 19個字符。 – JAB 2010-07-06 18:24:44

3

您對Python導入工作方式感到困惑。 (我剛開始的時候也是這樣。)在Python中,不能像Java中那樣簡單地用全名來引用模塊中的某些內容;無論您如何參考導入的項目,您都必須先導入模塊。嘗試在解釋器中輸入math.sqrt(5),而不先導入mathmath.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或可變)。

+0

'因爲某些技術原因,我無法再找到''import foo.bar as bar'似乎比'from foo import bar'更受歡迎。 – Philipp 2010-07-06 18:24:28

+1

@Philipp:如果是這樣,那對我來說是新聞。 – 2010-07-06 18:29:00

+1

@Philipp:http://docs.python.org/py3k/howto/doanddont.html#from-module-import-name1-name2沒有提及那裏的任何偏好。實際上,在所有情況下都不能使用前者,因爲在嘗試導入方法或數據成員時失敗。 – JAB 2010-07-06 18:35:41

1

除了在Java中,Python import foo.bar聲明,您將使用foo.bar所提及的東西。

這符合Python的哲學,明確比隱含更好。有更多的編程語言使得模塊間依賴關係比Java更明確,例如Ada。

使用全名可以消除來自不同模塊的相同名稱的定義歧義。

3

在Python中,導入並不僅僅表明您可能會使用某些東西。導入實際上在模塊級執行代碼。您可以將導入視爲「解釋」和創建函數的時刻。然後,處於_____init_____.py級別或不在函數或類定義內的任何代碼都會發生。

導入還可以製作整個模塊名稱空間的廉價副本,並將其放入文件/模塊/其導入的任何位置的名稱空間中。然後IDE會列出您可能開始爲命令完成鍵入的功能。

+0

請注意,當多次導入模塊或程序包時,模塊或程序包的__init __。py'文件中的任何可執行代碼將僅在首次導入時執行。這很好。 – JAB 2010-07-06 18:22:43

4

有一個在標準庫中的模塊調用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! 
3

Python哲學的一部分是explicit is better than implicit。第一次嘗試從包中訪問某些東西時,Python可以自動導入,但這並不明確。

我還猜測,包初始化會更加困難,如果進口自動的,因爲它不會始終如一的代碼來完成。

1

您不必使用全名。試試這些

from foo import bar 

import foo.bar as bar 

import foo.bar 
bar = foo.bar 

from foo import * 

爲什麼明確的進口都不錯的幾個原因之一:

  • 他們幫助信號對人體和工具包什麼你的模塊依賴。
  • 它們避免了在運行時動態確定哪些軟件包必須被加載(並且可能被編譯)的開銷。
  • 它們(和sys.path一起)明確地區分具有來自不同名稱空間的衝突名稱的符號。
  • 他們給程序員一些控制什麼進入他工作的命名空間。
相關問題