【发布时间】:2016-04-02 13:00:30
【问题描述】:
假设我从包含模块 foo.py 的包 pack 开始。
pack/
pack/__init__.py
pack/foo.py # Defines class Foo
但由于某些原因,我决定需要将 foo.py 移动到子包中。也许我的 foo 非常强大,我需要更多的功能来管理它。由于子包都是关于 foo 的,所以我也将它命名为 foo,所以现在我们有了
pack/
pack/__init__.py
pack/foo
pack/foo/__init__.py
pack/foo/foo.py # Defines class Foo
“啊”,我说,“我可以使事情向后兼容,并避免在调用代码时造成pack.foo.foo.Foo() 的过度愚蠢,并在pack/__init__.py 中进行以下导入......
$ cat pack/__init__.py
import foo.foo as foo
...这样我就可以使用pack.foo.Foo() 来初始化Foo。”
不幸的是,这意味着 foo.py 模块会遮蔽 foo 包的其余部分,因此只有 pack/foo/foo.py 的内容可见。
这都是预期的行为,我的问题是,这会上升到反模式的水平吗?似乎每一步的决定都有一定的意义,所以这是一条很容易走下去的路(我有几次),直到激发子包的所有附加功能说“嘿,我们呢?”
考虑到命名和向后兼容性,有没有一种 Python 方法可以将模块变成这样的子包? foo.foo.Foo 尤其令人讨厌(尽管有datetime.datetime),但也许答案是“处理它”并吃掉向后的不兼容性。我想把from foo import * 放在某个地方,但这似乎是错误的。还是我错过了一些简单的解决方案?
【问题讨论】:
-
我认为显而易见的答案是:首先不要使用像
foo.foo.Foo这样的愚蠢嵌套名称来命名事物。虽然命名空间是一个很棒的主意(让我们做更多这样的事情!),但超过一两个级别的嵌套命名空间很烦人。如果你真的需要嵌套包,至少在每一层都给它们有意义的(非重复的)名称。 -
我绝对同意深度命名空间,但这只是一个额外的级别,示例比比皆是(os.path、日志配置、冗余的 datetime.datetime)。它甚至不必是做它的愿望,更多的是沿途每一步的诱惑。 :)
-
是的,但是如果您有
foo.foo,则不存在此问题。为什么foo.foo的内容不在foo中?datetime.datetime不是模块。而且它的名字也很糟糕。 -
Antti,在这种情况下,以 foo.foo 结尾的内容开始于 foo,但随后 foo 变得足够大以至于它应该拥有多个文件,因此模块 foo 被扩展为一个子包富。但是子包是如此的 foo-ey 它被命名为 foo,而原始模块 foo 仍然存在。然后向后兼容性抬头。这是“仅有的两个难题”之一。 martinfowler.com/bliki/TwoHardThings.html
标签: python module package init shadowing