MvG*_*MvG 5 python visibility module python-module package
一个合适的Python模块将列出名为的列表中的所有公共符号.管理该列表可能很繁琐,因为您必须两次列出每个符号.当然有更好的方法,可能使用装饰器,因此只需将导出的符号注释为.__all__@export
你会怎么写这样的装饰师?我确定有不同的方法,所以我希望看到几个答案,其中包含足够的信息,用户可以将这些方法相互比较.
在使用装饰器向 __all__ 添加名称是一个好习惯吗?,Ed L建议将以下内容包含在某些实用程序库中:
import sys
def export(fn):
"""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
"""
mod = sys.modules[fn.__module__]
if hasattr(mod, '__all__'):
name = fn.__name__
all_ = mod.__all__
if name not in all_:
all_.append(name)
else:
mod.__all__ = [fn.__name__]
return fn
Run Code Online (Sandbox Code Playgroud)
我们已调整名称以匹配其他示例。在本地实用程序库中使用它,您只需编写
from .utility import export
Run Code Online (Sandbox Code Playgroud)
然后开始使用@export。只需一行惯用的 Python,就没有比这更简单的了。不利的一面是,该模块确实需要使用__module__属性和sys.modules缓存来访问该模块,这两种设置在一些深奥的设置中都可能会出现问题(例如自定义导入机制,或者包装来自另一个模块的函数以在此模块中创建函数)。模块)。
Barry Warsaw的atpublic 包的python 部分做了类似的事情。它也提供了一些基于关键字的语法,但装饰器变体依赖于上面使用的相同模式。
Aaron Hall的这个很好的答案提出了非常相似的东西,多了两行代码,因为它不使用__dict__.setdefault. __dict__如果由于某种原因操作模块出现问题,这可能会更好。
您可以简单地在模块级别声明装饰器,如下所示:
__all__ = []
def export(obj):
__all__.append(obj.__name__)
return obj
Run Code Online (Sandbox Code Playgroud)
如果您只在单个模块中使用它,那么这是完美的。在 4 行代码中(可能还加上一些用于典型格式化实践的空行),在不同的模块中重复此操作并不会太昂贵,但在这些情况下确实感觉像是代码重复。