2016-11-26 87 views
12

我只是碰到這種意外的行爲在無意中發現蟒蛇(包括2.7和3.x):爲什麼我無法從模塊別名導入?

>>> import re as regexp 
>>> regexp 
<module 're' from '.../re.py'> 
>>> from regexp import search 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ImportError: No module named 'regexp' 

當然from re import search中成功,就像我創建的別名之前會有。但爲什麼我不能使用現在是已知模塊的別名regexp作爲導入名稱的來源?

無論何時存在多個模塊變體,這都會帶給您一個令人討厭的驚喜:假設我仍在使用Python 2,並且想使用C版本pickle,cPickle。如果我再嘗試從pickle導入一個名稱,這將是獲取從簡單pickle模塊(我不會注意到,因爲它不拋出一個錯誤!)

>>> import cPickle as pickle 
>>> from pickle import dump 
>>> import inspect 
>>> inspect.getsourcefile(dump) 
'.../python2.7/pickle.py' # Expected cPickle.dump 

糟糕!

閒逛我看到sys.modules包括真正的模塊名稱(recPickle,而不是別名regexppickle。這也解釋了如何第二導入失敗,但不爲什麼 Python模塊名稱解析這種方式工作,即什麼樣的規則和原理都是做這種方式

注:這被標記爲a question重複有無關模塊別名:別名是不是在這個問題甚至提到的(這是關於imp從一個軟件包中刪除子模塊)或最佳答案。雖然這個問題的答案提供了與這個問題有關的信息,但這些問題本身甚至不是類似於恕我直言。

+1

因爲導入機制'import X'或'from X import Y'不檢查變量X的值,它搜索名爲'X'的文件/文件夾 – Copperfield

+1

而不是'from regexp import search'和'從pickle import dump',爲什麼不只是'search = regexp.search'和'dump = pickle.dump'? –

+0

@suspiciousdog,爲什麼_wouldn't_我使用'從X導入Y'形式?它是標準的語法,非常非常pythonic(只需要在PEP 8中提到)。 – alexis

回答

9

簡而言之:

你可以認爲以這種方式加載過程:

可以模塊加載到你的程序,在變量的形式。您可以使用模塊命名變量,無論您想要什麼。 但是,加載過程,是基於模塊的文件的名稱,而不是「模塊變量」。


龍版本:

import re創建一個名爲re一個全局變量充當「模塊門戶」,它提供了使用該模塊操作的能力的方式。

最相像,import re as regex創造這樣一個「門戶」命名regex變量下。

但是,當要創建這樣的入口並將模塊功能加載到其中時,導入程序不會使用此類引用。相反,它會在你的Python \Lib目錄或當前工作目錄的模塊,爲文件命名re.py(或者是導入模塊的名稱)。

import說明沒有解決變量,但文件,像C. #include<stdio.h>他們有他們「自己的語法」,和指令集,由翻譯結構,這是裁定,該案件,將re解釋爲文件名而不是變量,並且as用於規定模塊「門戶」的名稱。

這就是爲什麼regex對於門戶re操作別名,但輸入別名的模塊(用於這一目的,你必須使用文件的名稱) 。

  • 我已經使用了諸如「module portal」和「operation alias」之類的術語,因爲我還沒有找到這些標準術語。大多數模塊和導入器機制都與解釋器實現有關。在CPython的(其中C API的使用是常見的開發者),例如,create_module對於進口商(在PyObject S中的形式)使用所提供的規格爲模塊創建模塊,以及該模塊的PyModule_NewObjectPyModule_New功能創建具有模塊屬性的實例。這些可以在C API modules decumentation中查看。

  • 當我提到的術語「門戶」,以此來引用由import語句創建的變量,我的意思是指它作爲一個靜態門戶網站,而不是一個動態之一。模塊文件中的更改不會反映到已經導入它的正在運行的程序中(只要它沒有重新加載它),因爲它將加載模塊的副本並使用它,而不是要求模塊文件遇到需要時的操作。


這是相當多的可變裝載如何去實時:

>>> import re 
>>> re 
<module 're' from 'C:\\Programs\\Python35\\lib\\re.py'> 
>>> import re as regex 
>>> regex 
<module 're' from 'C:\\Programs\\Python35\\lib\\re.py'> 

你可以看到,re是引用模塊,它是從文件加載C:\Programs\Python35\lib\re.py (可能會根據您的python安裝位置而改變)。

+0

此外,如果您將're導入爲regexp',則不能使用're.find',您必須使用'regexp.find'。 –

+0

您能給出「模塊門戶」(或「觸發器」)和「操作別名」的概念的任何參考嗎?我不記得在閱讀Python的原理時遇到他們。 – alexis

+0

當然,我積極地尋找你的有趣答案,我並不覺得有什麼好處。 –

0

當從導入用於蟒蛇試圖在把目光從文件導入你所要求的東西。這可能會使它更清晰。

import re as regexp 

from regexp import search 

這實質上要求蟒蛇在一個名爲「正則表達式」,它無法找到文件的樣子。這就是別名不起作用的原因。

4

您不能在import語句作爲變量處理模塊的名字。如果是這種情況,肯定會導致您的初始導入失敗,因爲re尚未聲明變量。基本上,進口聲明是語義糖;這是它自己的規則。

一個這樣的規則是這樣的:因爲如果它是一個字符串寫入模塊名稱瞭解。也就是說,它不查找名稱爲re的變量,而是直接使用字符串值're'作爲模塊名稱。然後它用這個名字搜索一個模塊/包(文件)並進行導入。

這是唯一的情況(編輯:好了,看到的討論在評論...),在這種行爲被認爲是語言,這是混亂的原因。考慮這種替代語法,這更符合Python語言的其餘部分:

import 're' 
# Or alternatively 
module_name = 're' 
import module_name 

這裏,在導入語句中假定變量擴展。我們知道這是而不是實際上爲導入語句選擇的語法。人們可以討論哪種語法更好,但上述語言與其他語言語法更爲和諧。

+1

我認爲這個答案解釋_why_ /理論比其他答案更好解釋力學。 –

+0

關於您的更新:'import'語句執行名稱綁定,因此它需要一個有效的標識符,而不是任何任意字符串。支持一個假設的語法,比如'import '會提供比可能更大的靈活性。它與涉及名稱綁定的其他語法相一致,如'del','global','nonlocal'。如果我們事後提出了一些建議,我寧願有一個更普遍的能力來引用被綁定名稱的字符串,例如'Record = namedtuple('Record',<...>)','uid =數據['uid']'等。 –

+0

我不同意''del'和'nonlocal'語句直接對原始標識符進行操作,就像'import'一樣。在前兩種情況下,您提供一個現有對象作爲參數(就像使用任何函數調用一樣),並完成一些操作。在'import'的情況下,你提供一個標識符,它不會*映射到任何現有的對象。在「全球化」的情況下,你是對的;標識符也不必映射到任何現有的對象,使我以前的陳述「這是在這種行爲被看到的語言中唯一的情況」是錯誤的。我想我們現在有兩種情況 –

2

爲了得到一個明確的答案,你必須問設計師自己,但是,我想你問的是錯誤的問題。

這個問題不應該是:爲什麼這樣做?「但是,它應該是,按照你要求的方式做這件事的好處是什麼?當然可以,但爲什麼要這樣做?它?

由於是import說法是死的簡單和非常直觀的,你給它一個文件名,它會嘗試找到加載它。你甚至可以幻想asfrom但是,這個概念很簡單,你寫文件名,你讓它成爲。

什麼會混淆它,使它更難理解一個唯一的成就是讓事情變得更加複雜。

Python有一個尋找其設計變化背後的理論的歷史,人們問爲什麼沒有function對象的子類會得到一個「他們爲什麼要這樣做?」回覆;這種行爲並沒有真正的用例。因爲import簡單,直觀,讓人聯想到包含/使用其他語言的文件。

相關問題