Python - 我应该用下划线别名导入吗?

时间:2014-09-28 00:29:04

标签: python

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

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

# 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并没有看到自动填充列表发生变化。

E.g。从我可以做的一些模块:

import a

自动填充框同时显示bf

2 个答案:

答案 0 :(得分:2)

没有人使用该模式,并且没有命名。

这是因为正确的方法是使用__all__变量明确标记导出的名称。 IDE会像help()等工具一样尊重这个变量。

引用import statement documentation

  

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

(强调我的)。

另见Can someone explain __all__ in Python?

答案 1 :(得分:2)

虽然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的模块系统,在{{3}的印象下设计咒语。例如,比较模块在Haskell中的行为方式。

<强> UPD:
看起来PEP-8已经在“simple is better than complex”部分回答了这个问题:

  

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