考虑以下三个常规包的层次结构及其 内容:
quick
├── brown
│ ├── fox.py
│ └── __init__.py
├── lazy
│ ├── dog.py
│ └── __init__.py
└── __init__.py
现在假设在模块dog
中有一个函数jump
,并且在模块fox
中需要它。我应该如何进行?
最近看过 Raymond Hettinger 的 talk at Pycon
2015我愿意
可直接从包 lazy
的根导入的函数,
像这样:
from lazy import jump
另外,在我看来,写相对导入更简洁
使包内连接很容易看到。因此,我会写
这进入 lazy/__init__.py
:
from .dog import jump
并将其放入 fox.py
:
from ..lazy import jump
但我想知道,这是正确的方法吗?
首先,在 lazy/__init__.py
中导入名称 jump
对
防止它直接从 dog
导入。如果一个函数可能从许多地方导入,它会导致问题吗?例如,在单元测试中,我们是否可以从错误的位置修补名称?
此外,具有自动导入例程的 IDE 似乎更喜欢从定义函数的模块中导入。我或许可以通过将字符 _
放在所有模块名称的前面来覆盖它,但这似乎有点不切实际。
将所有需要的名字带出
打包到 __init__.py
?可能这至少增加了
循环进口的可能性。但我想如果一个通告
import 遇到了一些根本性的错误
无论如何包结构。
相对进口呢? PEP 8说 建议绝对进口:绝对进口是什么意思 进口产品表现优于相关产品?你能给我一个 例子?
最佳答案
显式接口(interface)声明:如果您想将jump
函数公开为属于lazy
包,那么包含它是有意义的lazy.__init__
,正如你所建议的。这样你就清楚地表明它是 lazy
的“public interface”的一部分。您还建议其他模块不是公共(public)接口(interface)的一部分。
关于防止人/工具直接从dog
导入:在Python中,隐私取决于用户是否同意,你不能强行隐藏任何东西,但有惯例。
使用下划线和定义 dog._jump()
可以清楚地表明 dog
不想要暴露 _jump
。我们可以假设任何 IDE 工具都应该遵守这种约定。无论如何,如果 dog
定义了 _jump
,并且 lazy
公开了 jump
,那么您就不会有问题不知道导入的是哪个,因为名称不同,所以这是显式的,这在 Python 中被认为是好的。
这是关于这个主题的一个很好的指针:Defining private module functions in python
关于相对导入::PEP 8 不鼓励这些,但是它们的实现是有原因的,并且它们取代了隐式相对导入。 PEP 8 中的原因:尤其是在处理复杂的包布局时,在这种情况下使用绝对导入会不必要地冗长。
最后的想法:简而言之,如果您将 lazy
包视为一个库并且不想暴露内部模块,那么我认为这是有道理的公开 lazy.__init__
中的对象。相反,如果你想让人们知道有一个 dog
模块,那么无论如何,让其他模块做:
从 lazy.dog 导入跳转
或
从..lazy导入跳转
如果 brown
和 brown.fox
将始终被打包并与 lazy
紧密集成,那么我看不出绝对的区别和相对的,但我更喜欢相对的,以明确指示您指的是内部模块。
但如果你认为它们将来可能被拆分,那么相对导入就没有意义,你宁愿这样做,取决于以上几点:
from lazy.dog import jump
或者:
从惰性导入跳转
关于复杂包结构中的 Python 导入语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30239475/