Python 复杂包结构中的导入语句?
Python import statements in complex package structures?
考虑以下三个常规包的层次结构及其
内容:
quick
├── brown
│ ├── fox.py
│ └── __init__.py
├── lazy
│ ├── dog.py
│ └── __init__.py
└── __init__.py
现在假设模块 dog
中有一个函数 jump
,并且模块 fox
中需要它。我该如何进行?
最近看了 Raymond Hettinger 在 Pycon 的 演讲
2015我愿意
可直接从包 lazy
的根导入的函数,
像这样:
from lazy import jump
另外,我觉得写relative import更简洁明了
使包内连接很容易看到。因此,我会写
这变成 lazy/__init__.py
:
from .dog import jump
然后变成 fox.py
:
from ..lazy import jump
但我想知道,这是正确的方法吗?
首先,在 lazy/__init__.py
中导入名称 jump
对
防止它直接从 dog
导入。如果一个函数可能从许多地方导入,它会导致问题吗?例如,在单元测试中,我们是否可以从错误的位置修补名称?
此外,具有自动导入例程的 IDE 似乎更喜欢从定义函数的模块中导入。我也许可以通过将字符 _
放在所有模块名称的前面来覆盖它,但这似乎有点不切实际。
把所有需要的名字都带在外面是不是很危险?
打包到 __init__.py
?可能这至少增加了
循环进口的可能性。但我想如果一个通告
import 遇到了一些根本性的错误
无论如何包结构。
相对进口呢?
PEP 8 说
建议绝对进口:绝对进口是什么意思
进口产品表现优于相关产品?你能给我一个
例如?
显式接口声明:如果你想公开属于lazy
包的jump
函数,那么包含它是有意义的lazy.__init__
,正如你所建议的。这样你就清楚地表明它是 lazy
的“public 接口 ” 的一部分。您还建议其他模块不是 public 接口的一部分。
关于阻止people/tools直接从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
考虑以下三个常规包的层次结构及其 内容:
quick
├── brown
│ ├── fox.py
│ └── __init__.py
├── lazy
│ ├── dog.py
│ └── __init__.py
└── __init__.py
现在假设模块 dog
中有一个函数 jump
,并且模块 fox
中需要它。我该如何进行?
最近看了 Raymond Hettinger 在 Pycon 的 演讲
2015我愿意
可直接从包 lazy
的根导入的函数,
像这样:
from lazy import jump
另外,我觉得写relative import更简洁明了
使包内连接很容易看到。因此,我会写
这变成 lazy/__init__.py
:
from .dog import jump
然后变成 fox.py
:
from ..lazy import jump
但我想知道,这是正确的方法吗?
首先,在 lazy/__init__.py
中导入名称 jump
对
防止它直接从 dog
导入。如果一个函数可能从许多地方导入,它会导致问题吗?例如,在单元测试中,我们是否可以从错误的位置修补名称?
此外,具有自动导入例程的 IDE 似乎更喜欢从定义函数的模块中导入。我也许可以通过将字符 _
放在所有模块名称的前面来覆盖它,但这似乎有点不切实际。
把所有需要的名字都带在外面是不是很危险?
打包到 __init__.py
?可能这至少增加了
循环进口的可能性。但我想如果一个通告
import 遇到了一些根本性的错误
无论如何包结构。
相对进口呢? PEP 8 说 建议绝对进口:绝对进口是什么意思 进口产品表现优于相关产品?你能给我一个 例如?
显式接口声明:如果你想公开属于lazy
包的jump
函数,那么包含它是有意义的lazy.__init__
,正如你所建议的。这样你就清楚地表明它是 lazy
的“public 接口 ” 的一部分。您还建议其他模块不是 public 接口的一部分。
关于阻止people/tools直接从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