使用装饰器在__all__中添加名称是个好习惯吗?

22 投票
4 回答
3728 浏览
提问于 2025-04-16 18:47

在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__ 中。

4 个回答

1

我觉得这个问题有点主观,但我喜欢这个想法。我通常在我的模块中使用 __all__,不过有时候我会忘记把一个新函数加进去,而这个函数本来是我想让它成为模块公共接口的一部分。因为我通常是按名称导入模块,而不是使用通配符,所以我不会注意到这个错误,直到我团队里的其他人(他们用通配符语法来导入整个模块的公共接口)开始抱怨。

注意:问题的标题有点误导,正如其他人已经在回答中提到的那样。

17

在Python中,更常见的做法是通过在函数名前加一个下划线来标记这些私有函数,也就是说,这些函数是私有的,不应该被外部直接使用:

def public(x):
      ...


def _private_helper(y):
    ...

这样做会让更多人觉得熟悉(而且这种写法也是Python语言支持的:即使你不使用 __all___private_helper 这个函数也不会被导出),比起你用的 public 装饰器来说,更容易被大家接受。

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 * 这种方式被导入。

撰写回答