我正在开发一个处理一些科学数据的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
这设法解决了这两个问题,模块命名空间污染和易于使用的功能。。。但它似乎一点也不Python。
那么,什么样的解决方案是最Python?有没有另一个我忽略的好办法?
我见过使用的一种技术,包括在标准库中,是使用
import module as _module
或from module import var as _var
,即将导入的模块/变量分配给以下划线开头的名称。其结果是,其他代码遵循通常的Python约定,将这些成员视为私有成员。这甚至适用于不查看
__all__
的代码,例如IPython的autocomplete函数。来自Python 3.3的
random
模块的示例:另一种技术是在函数范围内执行导入,以便它们成为局部变量:
这样做的主要原因是它实际上是懒惰的,延迟了模块依赖项的导入,直到它们被实际使用。假设模块中的一个函数依赖于一个特定的大型库。导入文件顶部的库意味着导入模块将加载整个库。这样,导入模块就可以很快,而且只有真正调用该函数的客户机代码才会产生加载库的成本。此外,如果依赖关系库不可用,则不需要依赖特性的客户端代码仍然可以导入模块并调用其他函数。缺点是使用函数级导入会模糊代码的依赖关系。
来自Python 3.3的示例
os.py
:继续执行通常的
from W import X, Y, Z
,然后使用__all__
特殊符号来定义您希望用户从模块中导入的实际符号:这定义了如果符号从您的模块
import *
导入到用户模块中的符号。一般来说,Python程序员应该而不是使用
dir()
来找出如何使用您的模块,如果他们这样做,则可能表示其他地方有问题。他们应该阅读您的文档或键入help(yourmodule)
来了解如何使用您的库。或者他们可以自己浏览源代码,在这种情况下(a)您导入的东西和您定义的东西之间的区别非常明显,(b)他们将看到__all__
声明并知道他们应该玩哪些玩具。如果你试图在这样的情况下支持一个不是为其设计的任务,
dir()
,你将不得不对自己的代码设置恼人的限制,我希望这里的其他答案是清楚的。我的建议是:不要这样做!请看一下标准库以获得指导:只要代码清晰和简洁性需要,它就会from … import …
,并提供(1)信息性文档字符串,(2)完整文档和(3)可读代码,这样就不必在模块上运行dir()
,并尝试将导入与模块中实际定义的内容区分开来。将模块作为一个整体导入:
import foreignmodule
。你所说的缺点实际上是一种好处。也就是说,预先设置模块名可以使代码更易于维护,并使其更具自文档性。六个月后,当你看到像
foo = Bar(baz)
这样的一行代码时,你可能会问自己Bar
来自哪个模块,但对于foo = cleverlib.Bar
来说,这就不那么神秘了。当然,进口越少,问题就越小。对于依赖关系很少的小程序来说,这并不重要。
当你发现自己问这样的问题时,问问自己是什么使代码更容易理解,而不是什么使代码更容易编写。你写过一次,但你读了很多。
相关问题 更多 >
编程相关推荐