问题是,尽管 Python 的 import 语句被设计为看起来类似于 Java 的,但它们在底层做的事情却完全不同。如您所知,在 Java 中,import 语句实际上只是对编译器的提示。它基本上为完全限定的类名设置了一个别名。例如,当你写
import java.util.Set;
它告诉编译器在整个文件中,当你写Set 时,你的意思是java.util.Set。如果你写s.add(o),其中s 是Set 类型的对象,编译器(或者更确切地说,链接器)会出去并在Set.class 中找到add 方法并引用它。
但在 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,而是创建一个引用util.set的变量set。在幕后,这有点像
_util = __import__('util', fromlist='set')
set = _util.set
del _util
在前一种情况下,或
_util = __import__('util.set')
set = _util.set
del _util
在后者中(尽管两种方式基本上做同样的事情)。这种形式在语义上更像 Java 的 import 语句所做的:它为通常只能通过完全限定名称 (util.set) 访问的东西定义别名 (set)。