为什么在需要使用全名时导入?

时间:2010-07-06 18:05:10

标签: python

在python中,如果你需要来自不同包的模块,你必须导入它。来自Java背景,这是有道理的。

import foo.bar

什么是没有意义的,为什么每当我想使用酒吧时我都需要使用全名?如果我想使用全名,为什么我需要导入?不使用全名立即描述我正在寻址的模块吗?

from foo import bar应该做的事情时,import foo.bar似乎有点多余。当我打算使用全名时,为什么我必须导入它也有点模糊。

8 个答案:

答案 0 :(得分:23)

问题是,即使Python的import语句被设计为看起来类似于Java,它们也会完全不同。如您所知,在Java中,import语句实际上只是对编译器的一个提示。它基本上为完全限定的类名设置别名。例如,当你写

import java.util.Set;

它告诉编译器在整个文件中,当你写Set时,你的意思是java.util.Set。如果你写s.add(o) sSet类型的对象,编译器(或更确切地说,链接器)会在add中找到Set.class方法。并引用它。

但是在Python中,

import util.set

(顺便说一句,这是一个虚构的模块)做了一些完全不同的事情。请参阅,在Python中,包和模块不仅仅是名称,它们是实际的对象,当您在代码中编写util.set时,它指示Python访问名为util的对象,并在其上查找名为set的属性。 Python的import语句的工作是创建该对象和属性。它的工作方式是解释器查找名为util/__init__.py的文件,使用其中的代码定义对象的属性,并将该对象绑定到名称util。同样,util/set.py中的代码用于初始化绑定到util.set的对象。有一个名为__import__的函数可以处理所有这些,实际上语句import util.set基本上等同于

util = __import__('util.set')

关键是,当您导入Python模块时,您得到的是与顶级包util对应的对象。为了访问util.set,你需要经历这一点,这就是为什么你需要在Python中使用完全限定名。

当然,有办法解决这个问题。由于所有这些都是对象,一种简单的方法是将util.set绑定到一个更简单的名称,即在import语句之后,你可以拥有

set = util.set

从那时起,你可以使用set来编写util.set。 (当然这会掩盖内置的set类,所以我不建议实际使用名称set。)或者,至少在另一个答案中提到,你可以写

from util import set

import util.set as set

这仍会导入包含模块util的包set,但不是在当前范围内创建变量util,而是创建一个变量set,是指util.set。在幕后,这有点像

_util = __import__('util', fromlist='set')
set = _util.set
del _util

在前一种情况下,或

_util = __import__('util.set')
set = _util.set
del _util

在后者中(尽管两种方式基本上都是一样的)。这种形式在语义上更像是Java的import语句所做的:它将别名(set)定义为通常只能由完全限定名称(util.set)访问的内容。

答案 1 :(得分:6)

如果您愿意,可以缩短它:

import foo.bar as whateveriwant

使用全名可以防止两个具有相同命名子模块的软件包互相破坏。

答案 2 :(得分:4)

标准库中有一个名为io的模块:

In [84]: import io

In [85]: io
Out[85]: <module 'io' from '/usr/lib/python2.6/io.pyc'>

scipy中还有一个名为io的模块:

In [95]: import scipy.io

In [96]: scipy.io
Out[96]: <module 'scipy.io' from '/usr/lib/python2.6/dist-packages/scipy/io/__init__.pyc'>

如果您想在同一个脚本中使用这两个模块,那么名称空间是区分这两个模块的便捷方式。

In [97]: import this
The Zen of Python, by Tim Peters
...
Namespaces are one honking great idea -- let's do more of those!

答案 3 :(得分:3)

你对Python导入的工作方式感到有些困惑。 (我刚开始的时候也是如此。)在Python中,你不能简单地用全名来引用模块中的某些东西,这与Java不同;无论您如何计划引用导入的项目,都必须先导入模块。尝试在解释器中输入math.sqrt(5),而不先导入mathmath.sqrt,看看会发生什么。

无论如何...... import foo.bar您需要使用foo.bar而非bar的原因是为了防止意外的命名空间冲突。例如,如果您执行import foo.bar,然后import baz.bar

,该怎么办?

当然,你可以选择import foo.bar as bar(即别名),但如果你这样做,你也可以使用from foo import bar。 (编辑:除非你想导入方法和变量。然后你必须使用from ... import ...语法。这包括你想要导入没有别名的方法或变量的实例,即你不能简单地import foo.bar 1}}如果bar是方法或变量。)

答案 4 :(得分:3)

在Python中,导入不只是表明你可能会使用某些东西。导入实际上在模块级别执行代码。您可以将导入视为“解释”和创建函数的时刻。那么_____init_____.py级别的任何代码都会在函数或类定义中出现。

导入还会为整个模块的命名空间制作一个廉价的副本,并将其放在文件/模块的命名空间内/无论它在哪里导入。然后,IDE会列出您可能要为命令完成键入的函数列表。

答案 5 :(得分:3)

Python哲学的一部分是explicit is better than implicit。第一次尝试从包中访问某些内容时,Python可以自动导入,但这不是明确的。

我也猜测如果导入是自动的,那么包初始化将会更加困难,因为它不会在代码中一致地完成。

答案 6 :(得分:1)

除了Java之外,在Python import foo.bar中声明,您将使用foo.bar引用的东西。

这与Python的哲学相匹配,即显性优于隐式。有更多的编程语言使得模块间依赖关系比Java更明确,例如Ada。

使用全名可以消除来自不同模块的具有相同名称的定义。

答案 7 :(得分:1)

您不必使用全名。尝试其中一个

from foo import bar

import foo.bar as bar

import foo.bar
bar = foo.bar

from foo import *

明确导入良好的几个原因:

  • 它们可以向人类和工具发出信号,告诉您模块所依赖的包装。
  • 它们避免了在运行时动态确定必须加载(并可能编译)哪些包的开销。
  • 它们(以及sys.path)明确区分具有不同名称空间的冲突名称的符号。
  • 它们让程序员可以控制进入他工作的命名空间的内容。