【问题标题】:Python - Should I alias imports with underscores?Python - 我应该用下划线对导入进行别名吗?
【发布时间】:2014-09-28 00:29:03
【问题描述】:

这是一个概念性问题,而不是一个实际问题,我想向广大的互联网人群寻求反馈。

我们都知道导入的模块最终会在该模块的命名空间中:

# Module a:
import b
__all__ = ['f']
f = lambda: None

这允许你这样做:

import a
a.b  # <- Valid attribute

有时这很好,但大多数导入都是模块提供的功能的副作用。在上面的示例中,我并不是要将b 公开为a 的调用者的有效接口。

为了抵消我们可以做的:

import b as _b

这会将导入标记为私有。但是我在任何地方都找不到这种做法,PEP8 也没有谈论使用别名将导入标记为私有。所以我认为这不是常见的做法。但从某个角度来看,我会说它在语义上绝对更清晰,因为它会清理模块的暴露位,只留下你真正想要暴露的相关接口。使用具有自动完成功能的 IDE 可以使建议的列表更加精简。

我的问题归结为您是否见过这种模式的使用?它有名字吗?有什么理由反对使用它?

我没有成功使用__all__ 功能隐藏b 导入。我正在使用 PyCharm,但没有看到自动完成列表发生变化。

例如从我可以做的一些模块:

import a

自动完成框同时显示bf

【问题讨论】:

    标签: python


    【解决方案1】:

    虽然 Martijn Pieters 说没有人真正使用下划线隐藏模块导入,但这并不完全正确。在 Python 的标准库本身中可以很容易地看到这种技术的痕迹(参见 related question)。让我们检查一下:

    $ git clone --depth 1 git@github.com:python/cpython.git
    $ cd cpython/Lib
    $ find -iname '*.py' | xargs grep 'as \+_' | wc -l
    183
    $ find -iname '*.py' | xargs grep '^import' | wc -l
    4578
    

    因此,大约 4% 的导入是带下划线前缀的——不是大多数,但远非“没有”。 numpymatplotlib 包中也有一些示例。

    对我来说,这种导入下划线是唯一在不公开暴露模块的情况下导入模块的正确方法。不幸的是,它完全破坏了代码的外观,因此许多开发人员避免使用它。但它比__all__ 方法有一些优势:

    • 图书馆用户只需查看名称即可决定名称是否为私有,而无需查阅文档。仅查看 __all__不够来区分私人和公共的,因为某些公共名称可能未在其中列出。
    • 无需维护对重构不友好的代码实体名称列表。

    总之,_name__all__ 都是邪恶的,但真正需要修复的是Python 的模块系统,它是在“simple is better than complex” 口头禅的印象下设计的。例如,与 Haskell 中模块的行为方式进行比较。

    UPD:
    看起来 PEP-8 已经在其“Public and internal-interfaces” 部分回答了这个问题:

    即使__all__ 设置得当,内部接口(包、模块、类、函数、属性或其他名称)仍应以单个前导下划线作为前缀。

    【讨论】:

      【解决方案2】:

      没有人使用这种模式,也没有命名。

      这是因为要使用的 正确 方法是使用 __all__ 变量显式标记您导出的名称。 IDE 将支持此变量,help() 等工具也是如此。

      引用import statement documentation

      模块定义的公共名称是通过检查模块命名空间中名为__all__的变量来确定的;如果已定义,它必须是由该模块定义或导入的名称的字符串序列。 __all__ 中给出的名称都被认为是公开的,并且必须存在。如果未定义__all__,则公共名称集包括在模块名称空间中找到的所有不以下划线字符开头的名称('_')。 __all__ 应该包含整个公共 API。其目的是避免意外导出不属于 API 的项目(例如在模块中导入和使用的库模块)。

      (强调我的)。

      另见Can someone explain __all__ in Python?

      【讨论】:

      • 我想我当时有些误解,我认为__all__ 只与from a import * 模式有关?这就是我从链接中得出的结论,我在通过 SO 进行的其他搜索中也遇到了这一点。在 PyCharm 中,当我创建 __all__ 条目时,当我执行正常的 import a 例如:模块 a: from 时,它不会更改自动完成框。 import b all = ['f'] f = lambda: None (module b is empty) 现在从另一个模块我可以做: from .导入 a 并且自动完成框同时显示 bf
      • @JonLauridsen:from modulename import * 模式是__all__一个用例。如果 PyCharm 仍然为 __all__ 中未列出的名称提供自动补全功能,这可能被视为 PyCharm 中的一个错误。
      • 啊,好吧,是的。好吧,我已经创建了一个缺陷@youtrack.jetbrains.com/issue/PY-14022,我们会看看会发生什么!谢谢。
      • @Martijn:你是说如果a.py 包含__all__=['f']import a; a.b 会引发一个AttributeError?我不认为这是真的……
      • @unutbu:不,我根本不是这么说的。我是说 PyCharm 应该只自动完成标记为公开的名称;他们已经忽略了以下划线开头的名称,这是“不公开”的隐含定义,而__all__ 给出了明确的定义。
      猜你喜欢
      • 1970-01-01
      • 2013-02-07
      • 2018-04-18
      • 1970-01-01
      • 2013-02-12
      • 2012-02-13
      • 2013-04-27
      • 2013-08-28
      • 2022-07-20
      相关资源
      最近更新 更多