使用装饰器在__all__中添加名称是一种好的实践吗?(涉及IT技术)

22

这个Python实践方法好吗(来自Active State Recipes -- Public Decorator)?

import sys

def public(f):
  """Use a decorator to avoid retyping function/class names.

  * Based on an idea by Duncan Booth:
  http://groups.google.com/group/comp.lang.python/msg/11cbb03e09611b8a
  * Improved via a suggestion by Dave Angel:
  http://groups.google.com/group/comp.lang.python/msg/3d400fb22d8a42e1
  """
  all = sys.modules[f.__module__].__dict__.setdefault('__all__', [])
  if f.__name__ not in all:  # Prevent duplicates if run from an IDE.
      all.append(f.__name__)
  return f

public(public)  # Emulate decorating ourself

一般的想法是定义一个装饰器,该装饰器接受一个函数或类,并将其名称添加到当前模块的__all__中。


2
修复了标题,因为有些人指出了这个问题 - Ed L
虽然这似乎是个好主意,但我发现它会让我的IDE(PyCharm 2016.1.4)感到困惑,这基本上就失去了它的目的。如果有足够的IDE支持,我会使用它的。 - Christopher Barber
让这个装饰器百分之百无懈可击似乎更加困难:请参阅Python bug#26632和其中提到的atpublic模块 - kostix
交叉引用:我在一个CW答案中引用了你的装饰器(只改了一个名字),回答了如何编写这样的装饰器的问题。 - MvG
4个回答

17

在Python中更为惯用的做法是通过在函数名前加下划线来标记私有函数:

def public(x):
      ...


def _private_helper(y):
    ...

更多的人将熟悉这种风格(它也被语言支持:_private_helper即使你不使用__all__也不会被导出),而不是您的public修饰符。


2
这似乎没有解决装饰器解决的问题:保持__all__中的名称最新。 - Ed L
4
那是因为如果你一贯地使用下划线表示“私有”内容,而不使用下划线表示公共内容,你就完全不需要__all__ - Tobias Kienzler
1
@TobiasKienzler:好主意,但那绝对不是常规做法。 - Neil G
2
@NeilG,@public 装饰器并不被提倡,常见 做法是按照预期使用 __all__ - Tobias Kienzler
3
标准库的一些部分(参见链接 https://hg.python.org/cpython/file/3.5/Lib/collections/__init__.py)使用了“import module as _module”的模式,因此我认为这是一个相当成熟的做法。 - flornquake
显示剩余6条评论

8

是的,这是一个好习惯。此装饰器允许您在函数或类定义时就表达您的意图,而不是直接之后。这使得您的代码更易读。

@public 
def foo():
    pass 

@public 
class bar():
    pass

class helper(): # not part of the modules public interface! 
    pass

注意: helper 仍然可以通过 modulename.helper 被模块的用户访问。只是不再使用 from modulename import * 导入。


8
我不会毫不保留地说这是一个好实践。在模块开头明确定义__all__的优点是,任何人(可能包括你)都可以非常容易地确定通过import *导出了哪些内容以及模块的公共API是什么。使用公共装饰器会使此过程更加困难。但是,如果使用装饰器,您可以在查看模块成员时确定它是否在__all__中。因此,两者都有各自的优缺点。 - darkfeline
除了darkfeline所说的,它还会破坏具有天真代码标记器的IDE的智能感知/代码完成功能。 - synthesizerpatel

1

这并不会自动将名称添加到__all__中,它只是允许您通过使用@public修饰符将函数添加到所有函数中。对我来说,这似乎是个好主意。


自动化地,我基本上是指不需要显式地在列表中输入名称。 - Ed L
1
是的。 - LaC

1

我认为这个问题有点主观,但我喜欢这个想法。我通常在我的模块中使用__all__,但有时我会忘记添加一个新函数,我本意是将其作为模块的公共接口的一部分。由于我通常按名称而不是通配符导入模块,所以我直到我的团队中的其他人(他们使用通配符语法导入整个模块的公共接口)开始抱怨时才注意到错误。

注意:问题的标题是误导性的,正如其他答案中已经注意到的那样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接