我应该如何在不污染其命名空间的情况下在Python模块中执行导入?

2022-03-31 00:00:00 python module python-import

问题描述

我正在开发一个用于处理一些科学数据的Python包。我在包的任何模块中定义的几乎每个函数中都需要来自其他模块和包(包括NumPy)的多个常用类和函数。

如何用毕德学派的方法来处理这些问题?我考虑过多种变种,但每一种都有自己的缺点。

  • 使用from foreignmodule import Class1, Class2, function1, function2导入模块级别的类
    然后,可以从每个函数轻松访问导入的函数和类。另一方面,它们污染了模块命名空间,使dir(package.module)help(package.module)与导入的函数杂乱无章

  • 使用from foreignmodule import Class1, Class2, function1, function2导入函数级类
    函数和类易于访问,不会污染模块,但从每个函数中的多达十几个模块导入看起来像是大量重复代码。

  • 使用import foreignmodule在模块级别导入模块
    由于需要在每个函数或类调用前添加模块名称,因此不会造成太多污染。

  • 使用一些人为的变通办法,如对所有这些操作使用函数体,并仅返回要导出的对象...像这样

    def _export():
        from foreignmodule import Class1, Class2, function1, function2
        def myfunc(x):
            return function1(x, function2(x))
        return myfunc
    myfunc = _export()
    del _export
    

    这设法解决了模块命名空间污染和函数的易用性这两个问题...但它似乎一点也不像派德哲学。

那么,什么样的解决方案才是最具毕达式的呢?有没有我忽略的另一个好的解决方案?


解决方案

继续执行通常的from W import X, Y, Z,然后使用__all__特殊符号定义您希望用户从您的模块导入的实际符号:

__all__ = ('MyClass1', 'MyClass2', 'myvar1', …)

这定义了import *从您的模块导入到用户模块中的符号。

一般来说,Python程序员应该而不是使用dir()来确定如何使用您的模块,如果他们这样做了,则可能表明其他地方有问题。他们应该正在阅读您的文档或输入help(yourmodule)以确定如何使用您的库。或者他们可以自己浏览源代码,在这种情况下,(A)您导入的东西和您定义的东西之间的区别非常明显,以及(B)他们将看到__all__声明,并知道他们应该玩哪些玩具。

如果您试图在这种情况下支持dir()而不是为它设计的任务,您将不得不对您自己的代码设置恼人的限制,我希望从这里的其他答案中可以清楚地看到这一点。我的建议是:别这么做!看看标准库的指导:只要代码清晰和简洁需要,它就会from … import …,并提供(1)信息性文档字符串、(2)完整文档和(3)可读代码,因此任何人都不必在模块上运行dir()并试图将导入与模块中实际定义的内容区分开来。

相关文章