用Python导入软件包


69

我可能会缺少一些明显的东西,但是无论如何:

当您像os在python中那样导入包时,您可以直接使用任何子模块/子包。例如,这有效:

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

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

FooPackage/
  __init__.py
  foo.py

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

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

我究竟做错了什么?

Answers:


40

您需要导入子模块:

import FooPackage.foo

您正在寻找的fooFooPackage/__init__.py。您可以通过将import FooPackage.foo as foo(或from . import foo)放入来解决它FooPackage/__init__.py,然后Python就能在其中找到foo。但我建议使用我的第一个建议。


8
据我了解,问题不在于如何导入子模块-这就是为什么您可以在不导入该子模块的情况下访问os的子模块,以及如何实现类似的功能。编辑:但是,您的答案会起作用
pycoder112358'1 2012年

2
为什么请您优先提出第一个建议?
Tengerye

66

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

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

第二个是更微妙的,并且是最流行的。如果没有显式的import语句(在FooPackage/__init__.py客户端程序中或在客户端程序中),Python不一定知道应将其导入为什么名称foo.py。在不区分大小写的文件系统(例如Windows中使用),这可能是一个名为模块fooFooFOOfOofoOFoOFOo,或fOO。所有这些都是有效的,不同的Python标识符,因此Python仅从文件中就没有足够的信息来了解您的意思。因此,为了在所有系统上保持一致,即使在有完整案例信息的文件系统上,也需要在某处使用显式import语句来澄清名称。


1
因此,您不能将包作为集合导入。您只能导入该软件包的特定模块。
drlolly19年

@drlolly除非软件包作者希望您这样做,否则您不能将其作为集合导入,特别是要在其__init__.py文件中写入子导入。

14

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


1
(此信息已发布在其他答案中,但是您必须仔细阅读它们。因此,我再次将其发布为该问题的简单答案。)
Richard Shepherd 2013年

最好__all__ =["foo"]改用
Guy L

9

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

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

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

在您的示例中,当您执行时import FooPackageFooPackage也会被视为模块,并且其属性(函数,类等)也应该在中定义__init__.py。由于您__init__.py为空,因此找不到foo

import语句之外,您不能使用'.'符号来寻址模块内部的模块。如果将amodule导入到预期的父级的包__init__.py文件中,则会发生唯一的异常。为了清楚起见,让我们在这里做一些例子:

考虑您的原始结构:

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不再是您在中定义的a module,而是a 。如果这样做,将抛出错误,指出不是模块。function__init__.pyimport FooPackage.foofoo


1
在“案例2”中,您可能需要使用from . import foo而不是import foo__init__.py文件中使用,否则可能由于Python将其import foo视为“绝对导入”而导致导入错误(请参阅docs.python.org/3/tutorial/…中的“包内引用”部分)
onelaview

-4

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

语法:import module_name

     ex: import math

您只能使用打击语法从包中导入特定的方法

语法:从module_name导入function_name

     ex: from math import radians
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.