考虑以下三个常规包及其类别的层次结构 内容:
quick
├── brown
│ ├── fox.py
│ └── __init__.py
├── lazy
│ ├── dog.py
│ └── __init__.py
└── __init__.py
现在假设模块jump
中有一个函数dog
,模块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
但我想知道,这是正确的方法吗?
首先,在jump
中导入名称lazy/__init__.py
无效
防止它直接从dog
导入。如果某个功能可能从很多地方导入,会导致问题吗?例如,在单元测试中,我们是否可能从错误的位置修改名称?
此外,具有自动导入例程的IDE似乎更喜欢从定义函数的模块导入。我可以通过将字符_
放在所有模块名称前面来覆盖它,但这似乎有点不切实际。
将所有需要的名字带到外面是否危险
打包到__init__.py
?可能这至少会增加
循环进口的可能性。但我想如果是圆形的话
遇到导入存在根本性的错误
包装结构无论如何。
相对进口情况如何? PEP 8说 建议绝对进口:当它说绝对时意味着什么 进口表现比相对表现好吗?你能给我一个 示例
答案 0 :(得分:3)
显式接口声明:如果您希望将jump
函数公开为属于lazy
包,那么将它包含在lazy.__init__
中是有意义的,正如你的建议。这样你就可以清楚地知道它是lazy
的“公共接口”的一部分。您还建议其他模块不属于公共接口。
防止人/工具直接从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
模块,那么无论如何,让其他模块做:
from lazy.dog import jump
或
from ..lazy import jump
如果brown
和brown.fox
将始终打包并与lazy
紧密集成,那么我看不出绝对和相对之间的区别,但我会稍微偏爱相对,明确表示您指的是内部模块。
但如果你认为他们将来会被拆分,那么相对导入没有意义,而你宁可这样做,具体取决于以上几点:
from lazy.dog import jump
或:
from lazy import jump