【问题标题】:Is this a python antipattern? 'import foo.foo as foo' shadows the rest of the foo package这是python反模式吗? 'import foo.foo as foo' 会影响 foo 包的其余部分
【发布时间】: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


【解决方案1】:

尽管我评论说 真正的 解决方案是避免这种深度嵌套的命名空间,但我认为解决问题的最佳方法可能是将pack/foo/foo.py 的内容移动到pack/foo/__init__.py 文件。这样,您仍然可以在 pack.foo 包中拥有其他模块,而且还可以从与以前相同的位置 (pack.foo) 访问 Foo 类和 foo.py 中的任何其他模块。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 2016-05-16
    • 1970-01-01
    • 2012-08-21
    • 2012-02-25
    相关资源
    最近更新 更多