没有 __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,但仍被视为一个包?的主要内容,如果未能解决你的问题,请参考以下文章