[英]Why can't I import using alias? Ex: `from tf import keras`
[英]Why can't I import from a module alias?
我剛剛在 python(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 並且我想使用pickle
的 C 版本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
包含真正的模塊名稱( re
或cPickle
,但不是別名regexp
或pickle
。這解釋了第二次導入如何失敗,但不是為什么python 模塊名稱解析以這種方式工作,即規則和這樣做的理由是。
注意:這被標記為與模塊別名無關的問題的重復:在問題(這是關於從包中導入子模塊)或最佳答案中甚至沒有提到別名。 雖然該問題的答案提供了與該問題相關的信息,但恕我直言,這些問題本身甚至都不相似。
你可以這樣想加載過程:
您可以將模塊以變量的形式加載到您的程序中。 您可以隨意命名用於使用模塊的變量。 但是,加載過程基於模塊文件的名稱,而不是“模塊變量”。
import re
創建一個名為re
的全局變量,用作“模塊門戶”,以提供使用模塊操作的能力。
最相似的是, import re as regex
在名為regex
的變量下創建了這樣一個“門戶”。
但是,在創建此類門戶並將模塊功能加載到其中時,導入程序不使用此類引用。 相反,它會在你的Python模塊\\Lib
目錄或當前工作目錄,文件名為re.py
(或者是導入模塊的名稱)。
import
指令不針對變量,而是針對文件,例如 C 中的#include<stdio.h>
。它們有自己的“語法”和指令集,由解釋器結構決定,在這種情況下,的解釋re
為文件名,而不是一個變量, as
對執政模塊“門戶”之稱。
這就是為什么regex
是re
門戶的操作別名,而不是模塊的導入別名(為此,您必須使用文件名)。
我使用了諸如“模塊門戶”和“操作別名”之類的術語,因為我沒有找到任何標准術語。 大多數模塊和導入器機制都與解釋器實現有關。 在CPython的(其中C API的使用是常見的開發者),例如, create_module
對於進口商(的形式創建模塊PyObject
多個)使用所提供的規格為模塊,並且PyModule_NewObject
和PyModule_New
對於模塊功能具有模塊屬性的實例創建。 這些可以在C API 模塊 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 安裝位置而改變)。
您不能將 import 語句中的模塊名稱視為變量。 如果是這種情況,您的初始導入肯定會失敗,因為re
還不是已聲明的變量。 基本上,import 語句是語義糖; 它是自己的聲明,有自己的規則。
一個這樣的規則是:寫入的模塊名稱被理解為一個字符串。 也就是說,它不查找名稱為re
的變量,而是直接使用字符串值're'
作為尋求的模塊名稱。 然后它搜索具有此名稱的模塊/包(文件)並進行導入。
這是在語言中看到這種行為的唯一情況(編輯:嗯,請參閱評論中的討論...),這是造成混淆的原因。 考慮這種替代語法,它更符合 Python 語言的其余部分:
import 're'
# Or alternatively
module_name = 're'
import module_name
此處,在 import 語句中假定變量擴展。 正如我們所知,這不是為 import 語句實際選擇的語法。 可以討論哪種語法更好,但以上肯定與其他語言語法更和諧。
要獲得明確的答案,您必須詢問設計師自己,但是,我認為您問錯了問題。
問題不應該是:為什么要這樣做?”但是,應該是,按照您的要求這樣做有什么好處?當然可以做到,但為什么要這樣做?
由於import
語句非常簡單且非常直觀,您給它一個文件名,它會嘗試查找加載它。 你甚至可以幻想as
和from
但是,這個概念是簡單的,你寫的文件名,你順其自然。
什么會混淆它並使它更難理解實現,唯一的成就是使事情可以說更復雜。
Python 有尋找其設計變化背后的基本原理的歷史,人們在問為什么function
對象不能被子類化時會得到一個“為什么他們應該?” 回復; 這種行為並沒有真正的用例。 照原樣, import
簡單、直觀,讓人聯想到包含/使用其他語言的文件。
當使用 from import 時,python 嘗試查看 from 文件以導入您所請求的內容。 這可能會更清楚。
import re as regexp
from regexp import search
這實質上是要求 python 查看它無法找到的名為“regexp”的文件。 這就是別名不起作用的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.