在python中,如果你需要来自不同包的模块,你必须导入它。来自Java背景,这是有道理的。
import foo.bar
什么是没有意义的,为什么每当我想使用酒吧时我都需要使用全名?如果我想使用全名,为什么我需要导入?不使用全名立即描述我正在寻址的模块吗?
当from foo import bar
应该做的事情时,import foo.bar
似乎有点多余。当我打算使用全名时,为什么我必须导入它也有点模糊。
答案 0 :(得分:23)
问题是,即使Python的import
语句被设计为看起来类似于Java,它们也会完全不同。如您所知,在Java中,import
语句实际上只是对编译器的一个提示。它基本上为完全限定的类名设置别名。例如,当你写
import java.util.Set;
它告诉编译器在整个文件中,当你写Set
时,你的意思是java.util.Set
。如果你写s.add(o)
s
是Set
类型的对象,编译器(或更确切地说,链接器)会在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)
,而不先导入math
或math.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 *
明确导入良好的几个原因: