python - 用于导入模块时,Python 上 __init__ 中 __all__ 的行为
问题描述
我有一个形式的python包:
package
├── __init__.py
├── module_1.py
└── module_2.py
在 __init__.py 我有:
__all__ = ["module_1", "module_2"]
Module_1 是:
__all__ = ["foo"]
def foo(): pass
Module_2 是:
__all__ = ["Bar"]
class Bar: pass
从文档中我认为以下代码将导入foo
和Bar
:
import package as pk
但是,当我运行pk.foo()
它时会引发错误:(AttributeError: module 'package' has no attribute 'foo'
与 Bar 相同)。
感谢这个答案,我知道要获得所需的行为,我可以将 __init__.py 更改为:
from .module_1 import *
from .module_2 import *
以上工作。
但是,我不理解 文档。这些行:
如果一个包的 __init__.py 代码定义了一个名为 __all__ 的列表,它被认为是遇到 from package import * 时应该导入的模块名称的列表
听起来我原来的 __init__.py 应该可以工作(带有 的那个__all__ = ["module_1", "module_2"]
)。也就是说,该行import package as pk
应该已经导入了模块 module_1
和module_2
,这反过来又使foo
和Bar
可用。
我错过了什么?
编辑:
我也尝试过使用文档中提到的内容。也就是说,使用from package import *
, 然后尝试使用package.foo()
and foo()
,但都没有奏效。
第一个 ,package.foo()
抛出错误NameError: 'package' is not defined.
。第二个,foo()
,抛出错误NameError: 'foo' is not defined.
。
一个工作示例会是什么样子?.. __init__.py 的形式为 __all__ = ["module_1", "module_2"]。
解决方案
我将尝试总结从对我的问题、文档、我自己的测试和这篇文章的评论中获得的知识。
1)在和模块__all__
上表现不同__init__
1.1) 在一个模块内
当_
所有_is within a _module_, it determines what objects are made available when running
从模块导入 *`.
鉴于此包结构:
package
├── __init__.py
├── module_1.py
└── module_2.py
并给出以下代码module_1
:
__all__ = ["foo"]
def foo(): pass
def baz(): pass
运行from package.module_1 import *
将使foo
可用但不可baz
用。
此外,foo
可以使用 调用foo()
,即不需要引用模块。
1.2)内__init__
(我原来的问题)
什么时候__all__
在 内__init__
,
它被视为遇到from package import *时应导入的模块名称列表。
跑步from package import *
会有两个效果:
- 将运行模块的脚本
__all__
(它们被导入)。 - 这些模块在命名空间中可用。
这意味着 if__init__
的形式为:
__all__ = ["module_1", "module_2"]
然后, runningfrom package import *
将运行 和 的脚本并使module_1
两个模块都可用。所以,现在,里面的函数可以调用 as而不是.module_2
foo
module_1
module_1.foo()
package.module_1.foo()
但是,如果这是意图,那么使用from package.module_1 import foo
可能会更好。因为它foo
可以作为foo()
.
2)from package import *
不一样import package
运行from package import *
有1.2)中提到的效果。但是,这不适用于运行import package
:即module_1.foo()
在这种情况下不起作用。
3)替代方法__init__
(以下内容基于这篇文章)正如我在问题中提到的,还有一种替代方法__init__
,其中您希望在用户调用时可用的对象from package import *
直接导入到__init__
.
例如,__init__
可能包含以下代码:
from .module_1 import *
from .module_2 import *
然后,当用户调用from package import *
模块 1 和 2 中的对象时,命名空间上将可用。
如果module_1
是1.1),则foo
可以在不引用模块的情况下调用该函数。即foo()
。但是,这对baz
.
如2)中所述,from package import *
与 不同import package
。在这种情况下调用import package
(使用 this __init__
)使 foo 可以通过package.foo()
而不是foo()
. 同样import package as pk
使 foo 作为pk.foo()
.
这种方法可能比1.2)的方法更可取,后者foo
通过 提供module_1.foo()
。
推荐阅读
- mysql - 查询 sys.x$session 很慢
- java - TimePickerDialog 构造函数问题
- google-apps-script - 超链接单击后复制单元格的文本到另一个单元格
- python - Python 键盘输入
- ios - iOS App 使用错误的默认语言作为应用名称
- c# - SQL Server:执行存储过程问题
- c# - 如何将 .net core Web API 项目添加到现有的 .NET core (3.1) Web Application 项目中?
- azure-devops - 有没有办法制定基于 devops 特定阶段的部分成功或成功的分支策略?
- google-apps-script - 如何不让 Google 协作平台根据上方/下方文本调整图像大小?
- java - 泛型方法作为使用 java.util.Function 的函数式编程