簡體   English   中英

為什么我不能從模塊別名導入?

[英]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包含真正的模塊名稱( recPickle ,但不是別名regexppickle 。這解釋了第二次導入如何失敗,但不是為什么python 模塊名稱解析以這種方式工作,即規則和這樣做的理由是。

注意:這被標記為與模塊別名無關的問題的重復:在問題(這是關於從包中導入子模塊)或最佳答案中甚至沒有提到別名。 雖然該問題的答案提供了與該問題相關的信息,但恕我直言,這些問題本身甚至都不相似。

簡而言之:

你可以這樣想加載過程:

您可以將模塊以變​​量的形式加載到您的程序中。 您可以隨意命名用於使用模塊的變量 但是,加載過程基於模塊文件的名稱,而不是“模塊變量”。


長版:

import re創建一個名為re的全局變量,用作“模塊門戶”,以提供使用模塊操作的能力。

最相似的是, import re as regex在名為regex的變量下創建了這樣一個“門戶”。

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

import指令不針對變量,而是針對文件,例如 C 中的#include<stdio.h> 。它們有自己的“語法”和指令集,由解釋器結構決定,在這種情況下,的解釋re為文件名,而不是一個變量, as對執政模塊“門戶”之稱。

這就是為什么regexre門戶的操作別名,而不是模塊的導入別名(為此,您必須使用文件名)。

  • 我使用了諸如“模塊門戶”和“操作別名”之類的術語,因為我沒有找到任何標准術語。 大多數模塊和導入器機制都與解釋器實現有關。 在CPython的(其中C API的使用是常見的開發者),例如, create_module對於進口商(的形式創建模塊PyObject多個)使用所提供的規格為模塊,並且PyModule_NewObjectPyModule_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語句非常簡單且非常直觀,您給它一個文件名,它會嘗試查找加載它。 你甚至可以幻想asfrom但是,這個概念是簡單的,你寫的文件名,你順其自然。

什么會混淆它並使它更難理解實現,唯一的成就是使事情可以說更復雜。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM