3

我正在使用以下代码填充__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]))
4

2 回答 2

5

您可能不应该这样做: 的默认行为import非常灵活。如果您不希望自动导出模块(或任何其他变量),请给它一个以开头的名称,_python 不会导出它。这是标准的 python 方式,重新发明轮子被认为是不符合 python 的。另外,不要忘记除了模块之外的其他东西可能需要导出;设置__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在所有内容都已加载后,在接近结尾处运行此代码。

于 2013-02-17T00:18:37.953 回答
1

我使用一些具有子包和子模块的复杂包。我喜欢逐个模块地控制它。我使用了一个简单的包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__变量的内容(这Python 方式)轻松地做到这一点,但是在管理大量对象时这可能会变得乏味,并且如果开发人员添加新对象并且不这样做也会导致问题通过添加到__all__变量来公开它。这种类型的事情可能会通过代码审查。使用简单的辅助函数来管理变量内容使这更容易。

于 2019-09-07T20:20:44.150 回答