【问题标题】:python imports - public or private conventionpython导入-公共或私人约定
【发布时间】:2016-06-13 18:59:18
【问题描述】:

在 Python 约定中,模块的导入是否应该被视为其公共接口的一部分?

我有一些代码可以做到这一点:

foo.py

from a import b

bar.py

from foo import b

我正在尝试决定是否重构 bar.py 以直接从 a 导入 b。我想在某些情况下,您可能希望 foo.py 控制 bar.py 使用的 b 的实现。但如果不是这样,让两个模块以相同的方式导入它不是更好的做法吗?

【问题讨论】:

  • 如果您想将它们设为私有,您可以随时使用import b as _b。此外,这个问题似乎有点基于意见,如果你能想出一种更客观的方式来改写它,以防止这个问题被关闭为题外话。

标签: python import conventions


【解决方案1】:

在 Python 约定中,模块的导入是否应该被视为其公共接口的一部分?

模块的公共 API 是模块记录其公共 API 的任何内容。如果模块foo 记录了它提供的b,那么b 是它的公共API 的一部分,无论b 实际上是在foo 中定义还是从其他地方导入。

许多模块将其代码拆分为多个文件,并将所有部分一起导入到一个模块中。例如,collections 模块将其部分代码放在 C 的 _collections 模块中,然后

from _collections import deque, defaultdict

dequedefaultdict 无疑是 collections 的公共 API 的一部分。

如果一个模块导入了不应该属于其公共 API 的内容,通常最好使用import thing as _thing,并在其上加上下划线以表示导入的内容是一个实现细节。

【讨论】:

    【解决方案2】:

    文档的观点。惯例是所有不以下划线开头的都是公开的。如果要将导入符号标记为私有,请使用下划线将其命名为 from a import b as _b。有一个替代方案。您可以改用__all__ 来声明您认为是公开的符号。尽管从技术上讲它只影响from module import *,但它也是一个很好的意向声明。

    依赖的观点。我不建议在没有充分理由的情况下使依赖关系图复杂化,因为否则在开发过程的后期有更高的机会在循环导入问题上绊倒。

    根据Zen of Python显式优于隐式简单优于复杂。所以如果模块a提供符号b,那么所有使用b的模块都从a导入它是合理的。

    【讨论】:

      【解决方案3】:

      PEP 8 在这里给出了一些指导。

      应始终将导入的名称视为实现细节。其他模块不得依赖对此类导入名称的间接访问,除非它们是包含模块 API 的明确记录的部分,例如 os.path 或从子模块公开功能的包的 __init__ 模块。

      【讨论】:

        【解决方案4】:

        忍者模式模块定义

        def defmod():
            global foo
            import sys
            def foo(): return sys.path
        defmod()
        del defmod
        

        【讨论】:

          猜你喜欢
          • 2015-12-11
          • 2014-07-14
          • 2019-02-14
          • 1970-01-01
          • 2017-02-17
          • 2012-08-03
          • 2011-01-09
          • 2013-01-31
          • 1970-01-01
          相关资源
          最近更新 更多