将__all__导出为不属于自己的东西

时间:2014-09-05 14:09:03

标签: python python-3.x python-import

我希望my_module__all__导出为空列表,即

from my_module import *
assert '__all__' in dir() and __all__ == []

我可以像这样导出__all__(在'my_module.py'中):

__all__ = ['__all__']

然而,它可预测地将__all__绑定到自身,所以

from my_module import *
assert '__all__' in dir() and __all__ == ['__all__']

如何将__all__导出为空列表?如果做不到这一点,我如何挂钩导入过程,将__all__放入每个顶级__dict__语句的导入模块import my_module中,绕过模块缓存。

2 个答案:

答案 0 :(得分:2)

我首先要说的是,在我看来,这是一个可怕的想法。你真的不应该隐含地改变从模块导出的内容,这与Zen of Python相反:显式优于隐式。

我同意关于你引用的问题的highest-voted answer; Python已经有一种机制来标记函数' private'按照惯例,我们使用前导下划线来表示函数不应被视为模块API的一部分。这种方法适用于现有工具,而装饰器动态设置__all__,这肯定会破坏静态代码分析器。

那就是,这是一只霰弹枪指着你的脚。小心使用。


您想要的是在导入名称时检测的方法。你通常不能这样做; import语句没有挂钩。从源导入模块后,module对象将添加到sys.modules并重新用于后续导入,但该对象不会通知导入。

可以做的事情是挂钩属性访问。不使用默认模块对象,但您可以将任何对象填充到sys.modules中,并将其视为模块。您甚至可以将模块类型子类化,然后为其添加__getattribute__方法。在使用from module import name导入任何名称时,系统会调用它,对于使用__all__的{​​{1}}中列出的所有名称,以及在Python 3中,{{即使只执行from module import *所有导入表单也会访问1}}。

然后你可以通过sys._getframe()使用它来破解调用框架全局变量:

__spec__

答案 1 :(得分:1)

  

那个人在第一个装饰器应用程序上设置__all__,因此不显式导出任何内容会导致它隐式导出所有内容。我正在努力改进这个设计:如果导入了装饰器,那么无论它的用法如何,都不会导出我的默认值。

只需将__all__设置为模块开头的空列表,例如:

# this is my_module.py
from utilitymodule import public

__all__ = []

# and now you could use your @public decorator to optionally add module to it