用 Python 导入包

我可能遗漏了一些显而易见的东西,但无论如何:

在 Python 中导入类似 os的包时,可以立即使用任何子模块/子包。例如:

>>> import os
>>> os.path.abspath(...)

然而,我有我自己的一揽子计划,其结构如下:

FooPackage/
__init__.py
foo.py

在这里,同样的逻辑是行不通的:

>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'

我做错了什么?

103201 次浏览

您需要导入子模块:

import FooPackage.foo

你要做的是在 FooPackage/__init__.py中寻找 foo。您可以通过在 FooPackage/__init__.py中放入 import FooPackage.foo as foo(或 from . import foo)来解决这个问题,那么 Python 将能够在那里找到 foo。但我建议使用我的第一个建议。

导入 FooPackage时,Python 会搜索 PYTHONPATH 上的目录,直到找到一个名为 FooPackage.py的文件或一个名为 FooPackage的目录,其中包含一个名为 __init__.py的文件。但是,在找到包目录之后,它执行 没有,然后扫描该目录并自动导入所有。Py 文件。

这种行为有两个原因。首先,导入一个模块会执行 Python 代码,这可能需要时间、内存或者有副作用。因此,您可能希望导入 a.b.c.d,而不必导入所有的大包 a。由包设计人员来决定是否显式地导入 __init__.py的模块和子包,以便它们始终可用,或者是否让客户机程序能够挑选和选择加载的内容。

第二个更微妙一些,也是一个精彩的表演。如果没有显式的 import 语句(无论是在 FooPackage/__init__.py中还是在客户机程序中) ,Python 不一定知道应该将 foo.py导入为什么名称。在不区分大小写的文件系统(例如在 Windows 中使用的)上,这可以表示一个名为 fooFooFOOfOofoOFoOFOofOO的模块。所有这些都是有效的、不同的 Python 标识符,因此 Python 没有从文件中获得足够的信息来理解您的意思。因此,为了在所有系统上保持一致,它需要在某个地方显式地导入语句以澄清名称,即使在可以获得完整大小写信息的文件系统上也是如此。

您需要将 from . import foo添加到包中的 __init__.py文件中。

可以使用 import 语句从库导入包。

Import module _ name

     ex: import math

通过使用 Blow 语法,只能从包中导入特定的方法

语法: from module _ name import function _ name

     ex: from math import radians

有一些重要的误解需要解决,特别是在术语方面。首先,通常,当您认为要在 python 中导入一个 package时,实际导入的是一个 module。在考虑帮助组织代码的文件系统子结构时,应该使用术语 package。但是从代码的角度来看,无论何时导入 package,Python 都将其视为一个模块。所有包都是模块。并非所有的模块都是软件包。具有 __path__属性的模块被视为包。

您可以检查 os是否是一个模块:

import os
print(type(os)) # will print: <type 'module'>

在您的示例中,当执行 import FooPackage时,FooPackage也被视为一个模块,其属性(函数、类等)应该在 __init__.py中定义。因为 __init__.py是空的,所以它找不到 foo

import语句之外,不能使用 '.'表示法来处理模块内部的模块。唯一的例外是,如果在预期的父包 __init__.py文件中导入了 module。为了清楚起见,让我们在这里举几个例子:

考虑一下你的原始结构:

FooPackage/
__init__.py
foo.py

案例1: _ _ init _ _. py 是一个空文件

#FooPackage imported as a module
import FooPackage


#foo is not a name defined in `__init__.py`. Error
FooPackage.foo


#FooPackage.foo imported as a module
import FooPackage.foo


#Error, foo has not been imported. To be able to use foo like this,
#you need to do: import FooPackage.foo as foo
foo.anything


#Not error, if anything is defined inside foo.py
FooPackage.foo.anything

案例2: _ _ init _ _. py 中有一行 import foo:

import FooPackage


#Now this is good. `foo` is sort of considered to be an attribute of
#FooPackage
FooPackage.foo

现在,假设 foo 不再是 module,而是您在 __init__.py中定义的 function。如果执行 import FooPackage.foo,它将抛出一个错误,说明 foo不是一个模块。

之所以可以使用 os.path.func(),是因为 os.path是特定系统路径模块的别名,目的是使代码更具可移植性。OS 模块为系统集 sys.modules['os.path'] = <path module>导入正确的路径模块。在这种情况下,Windows 的 ntpath.func()和 Linux 的 posixpath.func()都会转换成这种模式。