用Python导入包

mik*_*725 63 python python-import

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

当您os在python中导入包时,您可以使用任何子模块/子包.例如,这有效:

>>> import os
>>> os.path.abspath(...)
Run Code Online (Sandbox Code Playgroud)

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

FooPackage/
  __init__.py
  foo.py
Run Code Online (Sandbox Code Playgroud)

这里相同的逻辑不起作用:

>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

Ben*_*Ben 64

导入时FooPackage,Python会搜索PYTHONPATH上的目录,直到找到调用的文件FooPackage.py或名为FooPackage包含调用文件的目录__init__.py.然而,在找到一个包目录,它并不能再扫描该目录,并自动导入所有.py文件.

这种行为有两个原因.第一个是导入模块执行Python代码,这可能需要时间,内存或副作用.所以你可能想要导入a.b.c.d而不必导入所有庞大的包a.由包装设计者决定是否__init__.py明确地导入其模块和子包以使它们始终可用,或者是否让客户端程序选择加载的内容.

第二个是更微妙,也是一个showstopper.如果没有显式的import语句(在FooPackage/__init__.py客户端程序中或在客户端程序中),Python不一定知道它应该导入的名称foo.py.在(如在Windows中使用)不区分大小写的文件系统,这可能是一个名为模块foo,Foo, FOO,fOo,foO,FoO,FOo,或fOO.所有这些都是有效的,不同的Python标识符,因此Python只是没有足够的信息来自文件来知道你的意思.因此,为了在所有系统上表现一致,它需要在某处明确导入语句以澄清名称,即使在可获得完整案例信息的文件系统上也是如此.

  • @drlolly 您不能将包作为聚合导入,除非包作者希望您这样做,并且专门在其“__init__.py”文件中编写了子导入。 (4认同)
  • 因此,您无法将包作为聚合导入。您只能导入该包的特定模块。 (2认同)

Rob*_*ers 38

您需要导入子模块:

import FooPackage.foo
Run Code Online (Sandbox Code Playgroud)

你在做什么是寻找fooFooPackage/__init__.py.你可以通过put import FooPackage.foo as foo(或from . import foo)来解决它FooPackage/__init__.py,然后Python就能在foo那里找到它.但我建议使用我的第一个建议.

  • 据我所知,问题不在于如何导入子模块 - 这就是为什么你可以在不导入子模块的情况下访问os的子模块,以及如何实现类似的东西.编辑:但是,你的答案会奏效 (6认同)
  • 为什么您更喜欢您的第一个建议? (2认同)

Ric*_*erd 13

您需要添加from . import foo__init__.py包中的文件.


Jad*_*mas 7

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

你可以检查那os是一个模块.要确认这一点,您可以:

import os
print(type(os)) # will print: <type 'module'>
Run Code Online (Sandbox Code Playgroud)

在你的例子中,当你这样做时import FooPackage,它FooPackage也被视为一个模块,并且它的属性(函数,类等)被定义为__init__.py.由于你__init__.py是空的,所以找不到foo.

import语句之外,您不能使用'.'符号来处理模块内部的模块.如果module在目标父代的包__init__.py文件中导入了a,则会发生唯一的异常.为了说清楚,让我们在这里做一些例子:

考虑你的原始结构:

FooPackage/
  __init__.py
  foo.py
Run Code Online (Sandbox Code Playgroud)

情况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
Run Code Online (Sandbox Code Playgroud)

案例2:__ init__.py中有一行import foo:

import FooPackage

#Now this is good. `foo` is sort of considered to be an attribute of 
#FooPackage
FooPackage.foo
Run Code Online (Sandbox Code Playgroud)

现在,假设foo不再是a module,而是function你定义的__init__.py.如果你这样做import FooPackage.foo,它会抛出一个错误,说这foo不是一个模块.

  • 在“情况 2”中,您可能需要使用 `from 。在 `__init__.py` 文件中使用 import foo` 而不是 `import foo`,否则可能会导致导入错误,因为 Python 将 `import foo` 视为“绝对导入”(请参阅​​ https://docs 中的 *包内引用* 部分) .python.org/3/tutorial/modules.html#intra-package-references) (2认同)