为什么我不能从模块别名导入?

时间:2016-11-26 21:38:30

标签: python

我在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。这解释了< em>如何第二次导入失败,但为什么 python模块名称解析以这种方式工作,即这样做的规则和理由是什么。

注意:这被标记为a question的副本,与模块别名无关:问题中甚至没有提到别名(这是关于从包中导入子模块) )或最佳答案。虽然这个问题的答案提供了与这个问题相关的信息,但问题本身甚至都不相似恕我直言。

4 个答案:

答案 0 :(得分:13)

简而言之:

您可以通过这种方式考虑加载过程:

您可以以变量的形式将模块加载到您的程序中。您可以为变量命名使用模块,无论您想要什么。 加载过程,是基于模块文件的名称,而不是“模块变量”。

长版:

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 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已安装)。

答案 1 :(得分:5)

您不能将import语句中的模块名称视为变量。如果是这种情况,那么您的初始导入肯定会失败,因为re还不是声明的变量。基本上,import语句是语义糖;它是自己的规则声明。

一个这样的规则是:写入的模块名称被理解为它是一个字符串。也就是说,它不会查找名为re的变量,而是直接使用字符串值're'作为搜索模块名称。然后它搜索具有此名称的模块/包(文件)并执行导入。

这是唯一的情况(编辑:嗯,请参阅评论中的讨论...),在这种行为被看到的语言中,这是造成混淆的原因。考虑这种替代语法,它更符合Python语言的其余部分:

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

这里,在import语句中假设变量扩展。我们知道这是实际为import语句选择的语法。人们可以讨论哪种语法更好,但上面的语言语法其余部分肯定更加和谐。

答案 2 :(得分:2)

要得到一个明确的答案,你必须问设计师自己,但我认为你问的是错误的问题。

问题不应该是:为什么这样做?“但它应该是,按照你要求的方式做什么会有什么好处?当然可以完了,但为什么要这样呢?

因为import语句很简单且非常直观,你给它一个文件名,它试图找到加载它。你甚至可以看上asfrom,但是,概念很简单,就是你编写文件名然后就可以了。

什么会混淆它并使其更难理解实现,唯一的成就就是让事情变得更加复杂。

Python有寻找其设计变更背后的基本原理的历史,人们问为什么不是function对象的子类可以获得“为什么他们应该?”答复;这种行为实际上没有用例。因此,import简单,直观,让人联想到在其他语言中包含/使用文件。

答案 3 :(得分:1)

使用import时,python会尝试查找from文件以导入您请求的内容。这可能会更清楚。

import re as regexp

from regexp import search 

这基本上要求python查看名为&#39; regexp&#39;的文件。它无法找到。这就是别名不起作用的原因。