2016-11-26 64 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简单,直观,让人联想到包含/使用其他语言的文件。

相关问题