我正在使用以下代码填充模块__all__
中的__init__.py
,如果有更有效的方法,我就会徘徊。有什么想法吗?
import fnmatch
import os
__all__ = []
for root, dirnames, filenames in os.walk(os.path.dirname(__file__)):
root = root[os.path.dirname(__file__).__len__():]
for filename in fnmatch.filter(filenames, "*.py"):
__all__.append(os.path.join(root, filename[:-3]))
答案 0 :(得分:2)
您可能不应该这样做:import
的默认行为非常灵活。如果您不想自动导出模块(或任何其他变量),请为其命名,以_
开头,python不会导出它。这是标准的python方式,重新发明轮子被认为是unpythonic。另外,不要忘记模块之外的其他东西可能需要导出;设置__all__
后,您还需要查找并导出它们。
仍然,您要问如何最好地生成可导出模块的列表。由于您无法导出不存在的内容,我只需检查您的主模块中已知的模块:
basedir = os.path.dirname(__file__)
for m in sys.modules:
if m in locals() and not m.startswith('_'): # Only export regular names
mod = locals()[m]
if '__file__' in mod.__dict__ and mod.__file__.startswith(basedir):
print m
sys.modules
包含python已加载的每个模块的名称,包括许多尚未导出到主模块的模块 - 因此我们检查它们是否在locals()
。
这比扫描文件系统更快,并且比假设目录树中的每个.py
文件以某种方式最终作为顶级子模块更强大。当然,您应该在__init__.py
的末尾附近运行此代码,此时所有内容都已加载。
答案 1 :(得分:0)
我处理一些带有子软件包和子模块的复杂软件包。我喜欢逐个模块地控制它。我使用了一个名为auto-all
的简单程序包,该程序包很容易(完全公开-我是作者)。
https://pypi.org/project/auto-all/
这是一个例子:
from auto_all import start_all, end_all
# Define some internal stuff
start_all(globals())
# Define some external stuff
end_all(globals())
我使用此方法的原因主要是由于导入。如alexis所述,您可以通过在对象名称前添加下划线来隐式地使事物私有,但是对于导入的对象而言,这可能会变得凌乱或不切实际。考虑以下代码:
from pyspark.sql.session import SparkSession
如果这出现在您的模块中,则将隐式使SparkSession
可从模块外部访问。另一种方法是在所有导入的项目前加上下划线,例如:
from pyspark.sql.session import SparkSession as _SparkSession
这也不理想,因此(我知道)手动管理__all__
是管理外部可用内容的唯一方法。
您可以通过显式设置__all__
变量的内容(是的pythonic方式)轻松地做到这一点,但是在管理大量对象时这可能变得很乏味,并且如果开发人员添加了新对象并且没有通过添加到__all__
变量来公开对象,也会导致问题。这种类型的事情可能会通过代码审查。使用简单的辅助函数来管理变量内容将使此操作变得更加容易。