在Python中导入包

在Python中导入包,python,python-import,Python,Python Import,我可能遗漏了一些显而易见的东西,但无论如何: 在python中导入像os这样的包时,可以直接使用任何子模块/子包。例如,这项工作: >>> import os >>> os.path.abspath(...) 但是,我有自己的软件包,其结构如下: FooPackage/ __init__.py foo.py 在这里,同样的逻辑不起作用: >>> import FooPackage >>> FooPackage.f

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

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

>>> import os
>>> os.path.abspath(...)
但是,我有自己的软件包,其结构如下:

FooPackage/
  __init__.py
  foo.py
在这里,同样的逻辑不起作用:

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

我做错了什么?

您需要导入子模块:

import FooPackage.foo


您所做的是在
FooPackage/\uuuuu init\uuuuuuuuuy.py
中查找
foo
。您可以通过将
import FooPackage.foo作为foo
(或
from.import foo
)放在
FooPackage/\uuuuuu init\uuuuuuuuuuuuuu.py
中来解决这个问题,然后Python将能够在那里找到
foo
。但是我建议使用我的第一个建议。

当您导入
FooPackage
时,Python会在PYTHONPATH上搜索目录,直到找到名为
FooPackage.py
的文件或名为
FooPackage
的目录,其中包含名为
\uu init\uuuuuuuuuupy
的文件。但是,找到包目录后,它不会扫描该目录并自动导入所有.py文件

这种行为有两个原因。首先,导入模块会执行Python代码,这可能需要时间、内存或产生副作用。因此,您可能希望导入
a.b.c.d
,而不必导入所有大型软件包
a
。由软件包设计者决定a的
\uuuu init\uuuu.py
是否显式导入其模块和子包以使其始终可用,或者是否让客户端程序能够选择加载的内容


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

您需要从中添加
。将foo
导入包中的
\uuuu init\uuuu.py
文件

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

语法:导入模块名称

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

语法:从模块名称导入函数名称


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

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

import os
print(type(os)) # will print: <type 'module'>
案例1:\uuuu init\uuuuuuy.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:\uuuu init\uuuuu.py中有行
import foo

import FooPackage

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

现在,假设foo不再是
模块
,而是您在
\uuu init\uuuu.py
中定义的
函数
。如果执行导入FooPackage.foo,它将抛出一个错误,指出
foo
不是模块。

之所以可以使用
os.path.func()
,是因为
os.path
是特定系统路径模块的别名,以便使代码更易于移植。操作系统模块为您的系统集导入正确的路径模块
sys.modules['os.path']=
。这将本质上转化为适用于Windows的
ntpath.func()
,或适用于linux的
posixpath.func()

据我所知,问题不是如何导入子模块,而是为什么不导入子模块就可以访问操作系统的子模块,以及如何实现类似的功能。编辑:但是,你的答案会有用的。为什么你更喜欢你的第一个建议呢?(这个信息在已经发布的其他答案中,但是你必须仔细阅读一下。因此,我再次发布了它,作为对问题的简单回答。)最好使用
\uu all\uu=[“foo”]
而不是标题“案例2”,你可能需要使用
from。导入foo
而不是
\uuuu init\uuuuu.py
文件中的
import foo
,否则可能会导致导入错误,因为Python将
import foo
视为“绝对导入”(请参见中的包内引用部分),因此无法将包作为聚合导入。您只能导入该软件包的特定模块。@dr除非软件包作者希望您这样做,并且在其
\uuuu init\uuuu.py
文件中专门编写了子导入,否则您不能将软件包作为聚合导入。
FooPackage/
  __init__.py
  foo.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
import FooPackage

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