用Python导入包

Importing packages in Python

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

当您在python中导入像os这样的包时,可以立即使用任何子模块/子包。例如,这项工作:

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

但是,我有自己的包,其结构如下:

1
2
3
FooPackage/
  __init__.py
  foo.py

在这里,同样的逻辑不起作用:

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

我做错什么了?


当导入FooPackage时,python会搜索pythonpath上的目录,直到找到名为FooPackage.py的文件或名为FooPackage的目录,其中包含名为__init__.py的文件。但是,找到包目录后,它不会扫描该目录并自动导入所有.py文件。

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

第二个更微妙,同时也是一个展示的拦路虎。如果没有明确的导入语句(在FooPackage/__init__.py或客户机程序中),python不一定知道应该将foo.py作为什么名称导入。在不区分大小写的文件系统(如在Windows中使用)上,它可以表示名为foofoofoofoofoofoofoofoofoo的模块。所有这些都是有效的、不同的python标识符,所以python仅仅从文件中没有足够的信息来了解您的意思。因此,为了在所有系统上保持一致的行为,它需要在某个地方有一个明确的导入语句来澄清名称,即使在有完整案例信息的文件系统上也是如此。


您需要导入子模块:

1
import FooPackage.foo

你要做的是在FooPackage/__init__.py中寻找foo。你可以通过把import FooPackage.foo as foofrom . import foo放在FooPackage/__init__.py中来解决这个问题,然后python就可以在那里找到foo。但我建议使用我的第一个建议。


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


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

您可以检查os是否为模块。要确认这一点,您可以执行以下操作:

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

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

import语句之外,不能使用'.'符号来处理模块内部的模块。唯一的例外情况是,如果一个module导入了预期的父公司的包__init__.py文件中。为了说明这一点,让我们在这里做一些例子:

考虑您的原始结构:

1
2
3
FooPackage/
  __init__.py
  foo.py

案例1:uuu init_uuuuy是一个空文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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:uuinit_uuu.py中有行import foo

1
2
3
4
5
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不是模块。


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

syntax : import module_name

1
     ex: import math

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

syntax : from module_name import function_name

1
     ex: from math import radians