没有 __init__.py,但仍被视为一个包?

Posted

技术标签:

【中文标题】没有 __init__.py,但仍被视为一个包?【英文标题】:No __init__.py, but still considered a package? 【发布时间】:2015-11-23 20:47:30 【问题描述】:

A foobar package

foobar

__init__.py foo.py

酒吧

bar.py

Inside the __init__.py

from . import foo
from . import bar

即使bar 不是包或子包,它仍然作为模块导入(lolwut)。我通过在__init__.py 中执行print(type(bar)) 检查了导入类型,它打印了<class 'module'>... 就是这样。这里发生了什么?它是一个模块对象,所以我做了print(dir(bar)),输出为['__doc__', '__loader__', '__name__', '__package__', '__path__', '__spec__']。现在,更让我困惑的是其中的__path__ 变量。那不是只有包裹吗?

这就是所谓的命名空间包吗?我认为不是,不过我在__init__.py 文件中又尝试了另一件事——添加了一行import bar.bar。它以ImportError 结尾。所以,总结一下我的问题,这个模块有什么用?为什么 Python 首先要导入这个?

There's an amazing tutorial on this entire topic by David Beazley。前段时间我已经看完了整件事,但我想我应该再看一遍以回忆一切。

【问题讨论】:

【参考方案1】:

来自the docs

模块是包含 Python 定义和语句的文件。文件名是后缀.py的模块名。在模块中,模块的名称(作为字符串)可用作全局变量 __name__ 的值。

...

包是一种通过使用“带点的模块名称”来构建 Python 模块命名空间的方法。例如,模块名 A.B 指定了一个名为 A 的包中名为 B 的子模块。

...

包支持另一种特殊属性__path__。在执行该文件中的代码之前,这被初始化为一个列表,其中包含包含包的 __init__.py 的目录名称。这个变量可以修改;这样做会影响将来对包中包含的模块和子包的搜索。

虽然并不经常需要此功能,但可用于扩展包中的模块集

所以是的,__path__ 变量也适用于包内的模块,这些模块被视为“包的子模块”

编辑 在 Python 2.x 中,带有 from . import bar 的包将在该行返回 ImportError。在 Python 3.x 上,modulefoobar.foo 的类型为 <module 'foobar.foo' from '../py/foobar/foo.py'><module 'foobar.bar' (namespace)>foobar.bar

显然,它出现在here

常规包将继续具有 init.py 并将驻留在单个目录中。命名空间包不能包含 init.py

【讨论】:

感谢您的回答。 “这被初始化为一个列表,其中包含包含包的 __init__.py 的目录名称” 在我上面的示例中,bar 文件夹中没有 __init__,但它被视为包和一些东西被导入了。我必须承认,这让我越来越困惑。 在 Python 2.x 中,带有from . import bar 的包将在该行返回ImportError。在 Python 3.x 上,模块foobar.foo 的类型为 <module 'foobar.foo' from '../py/foobar/foo.py'><module 'foobar.bar' (namespace)>foobar.bar。显然,here >常规包将继续具有 init.py 并将驻留在单个目录中。命名空间包不能包含 init.py 请用最后一条评论更新您的答案,因为它实际上回答了 OP 的问题。

以上是关于没有 __init__.py,但仍被视为一个包?的主要内容,如果未能解决你的问题,请参考以下文章

python包中__init__.py的作用

Python模块包中__init__.py文件的作用

8.1包,__init__.py,

包 __init__.py 的相对导入

python基础:__init__.py和__init__函数的作用

ImportError:没有名为包的模块