在Python中导入包
我可能遗漏了一些明显的东西,但无论如何:
当你在Python中导入像os
这样的包时,你可以立即使用任何子模块/子包。例如,这有效:
>>> import os
>>> os.path.abspath(...)
但是,我有自己的包,其结构如下:
FooPackage/
__init__.py
foo.py
这里相同的逻辑不起作用:
>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'
我做错了什么?
I am probably missing something obvious but anyway:
When you import a package like os
in Python, you can use any submodules/subpackages off the bat. For example this works:
>>> import os
>>> os.path.abspath(...)
However, I have my own package which is structured as follows:
FooPackage/
__init__.py
foo.py
and here the same logic does not work:
>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'
What am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
当您导入
FooPackage
时,Python 会搜索 PYTHONPATH 上的目录,直到找到名为FooPackage.py
的文件或包含名为FooPackage
的文件的目录。__init__.py
。但是,找到包目录后,它不会扫描该目录并自动导入所有 .py 文件。这种行为有两个原因。首先,导入模块会执行 Python 代码,这可能需要时间、内存或产生副作用。因此,您可能希望导入
abcd
,而不必导入整个大包a
。由包设计者决定 a 的 __init__.py 是否显式导入其模块和子包以使它们始终可用,或者是否让客户端程序能够选择加载的内容。第二个有点微妙,也是一个令人震惊的事情。如果没有显式的 import 语句(无论是在 FooPackage/__init__.py 中还是在客户端程序中),Python 不一定知道应该将 foo.py 导入为什么名称。在不区分大小写的文件系统(例如在 Windows 中使用)上,这可能表示名为
foo
、Foo
、FOO
、的模块fOo
、foO
、FoO
、FOo
或fOO
。所有这些都是有效的、不同的 Python 标识符,因此 Python 仅从文件中没有足够的信息来了解您的意思。因此,为了在所有系统上表现一致,需要在某处显式导入语句来澄清名称,即使在完整案例信息可用的文件系统上也是如此。When you import
FooPackage
, Python searches the directories on PYTHONPATH until it finds a file calledFooPackage.py
or a directory calledFooPackage
containing a file called__init__.py
. However, having found the package directory, it does not then scan that directory and automatically import all .py files.There are two reasons for this behaviour. The first is that importing a module executes Python code which may take time, memory, or have side effects. So you might want to import
a.b.c.d
without necessarily importing all of a huge packagea
. It's up to the package designer to decide whether a's__init__.py
explicitly imports its modules and subpackages so that they are always available, or whether or leaves the client program the ability to pick and choose what is loaded.The second is a bit more subtle, and also a showstopper. Without an explicit import statement (either in
FooPackage/__init__.py
or in the client program), Python doesn't necessarily know what name it should importfoo.py
as. On a case insensitive file system (such as used in Windows), this could represent a module namedfoo
,Foo
,FOO
,fOo
,foO
,FoO
,FOo
, orfOO
. All of these are valid, distinct Python identifiers, so Python just doesn't have enough information from the file alone to know what you mean. Therefore, in order to behave consistently on all systems, it requires an explicit import statement somewhere to clarify the name, even on file systems where full case information is available.您需要导入子模块:
您要做的就是在
FooPackage/__init__.py
中查找foo
。你可以通过将import FooPackage.foo as foo
(或from . import foo
)放入FooPackage/__init__.py
来解决这个问题,然后 Python 将能够在那里找到foo
。但我建议使用我的第一个建议。You need to import the submodule:
What you're doing is looking for
foo
inFooPackage/__init__.py
. You could solve it by puttingimport FooPackage.foo as foo
(orfrom . import foo
) inFooPackage/__init__.py
, then Python will be able to findfoo
there. But I recommend using my first suggestion.您需要添加
from 。将 foo
导入到包中的__init__.py
文件中。You need to add
from . import foo
to the__init__.py
file in your package.有一些重要的误解需要解决,特别是术语方面的误解。首先,通常,当您认为在 python 中导入
包
时,您实际上导入的是一个模块
。当您考虑帮助您组织代码的文件系统子结构时,您应该使用术语package
。但从代码角度来看,每当您导入包
时,Python 都会将其视为模块。所有包都是模块。并非所有模块都是包。具有 __path__ 属性的模块被视为包。您可以检查 os 是否是一个模块。要确认这一点,您可以执行以下操作:
在您的示例中,当您执行
import FooPackage
时,FooPackage
也被视为并被视为一个模块,其属性(函数、类、等)据说是在 __init__.py 中定义的。由于您的__init__.py
为空,因此它找不到foo
。在
import
语句之外,您不能使用'.'
表示法来寻址模块内部的模块。如果将module
导入到目标父包的__init__.py
文件中,则会发生唯一的异常。为了清楚起见,让我们在这里举一些例子:考虑您的原始结构:
情况 1:__init__.py 是一个空文件
情况 2:__init__.py 有行
import foo< /code> 其中:
现在,假设 foo 不再是一个
模块
,而是一个您在__init__.py函数
代码>.如果你import FooPackage.foo
,它会抛出一个错误,指出foo
不是一个模块。There are some important misconceptions that need to be addressed, specifically with terminology. First, usually, when you think that you are importing a
package
in python, what you are actually importing is amodule
. You should use the termpackage
when you are thinking in terms of file system substructure that helps you organize your code. But from the code perspective, whenever you import apackage
, Python treats it as a module. All packages are modules. Not all modules are packages. A module with the__path__
attribute is considered a package.You can check that
os
is a module. To confirm this you can do:In your example, when you do
import FooPackage
,FooPackage
is treated and considered to be a module too, and its attributes (functions, classes, etc.) are supposedly defined in__init__.py
. Since your__init__.py
is empty, it cannot findfoo
.Outside of
import
statements you cannot use'.'
notation to address modules inside of modules. The only exception happens if amodule
is imported in the intended parent's package__init__.py
file. To make it clear, let's do some examples here:Consider your original structure:
Case 1: __init__.py is an empty file
Case 2: __init__.py has line
import foo
in it:Now, suppose that foo is no longer a
module
, but afunction
that you define in__init__.py
. if you doimport FooPackage.foo
, it will throw an error saying thatfoo
is not a module.您可以使用 os.path.func() 的原因是因为 os.path 是特定系统路径模块的别名,以便使代码更具可移植性。 os 模块会为您的系统集
sys.modules['os.path'] =
导入正确的路径模块。对于 Windows,这本质上会转换为ntpath.func()
,对于 Linux,则转换为posixpath.func()
。The reason you can use
os.path.func()
is becauseos.path
is an alias for your particular system's path module in order to make code more portable. The os modules imports the correct path module for your system setssys.modules['os.path'] = <path module>
. Where this would essentially translate tontpath.func()
for Windows orposixpath.func()
for linux.您可以使用 import 语句从库中导入包。
您可以使用blow语法仅导入包中的特定方法
You can import a package from library using import statement.
You can import only a specific method form a package by using blow syntax