简短的问题:我有一个带有对象的模块。如果有人从我的模块中导入对象,该怎么办呢?
我想做什么:我写了一个架构框架(可以在Python 2和3中工作)。用于输出的类取决于jinja2
外部库。我希望该框架在没有这种依赖性的情况下也可以使用。在包的__init__.py
中,我对类RenderLaTeX
进行了条件导入(如果jinja2可用,则导入该类,否则不导入)。
这种方法的问题是我有一些使用此类RenderLaTeX
的代码,但是当我在全新的设置上运行它时,会收到类似Import error: no class RenderLaTeX could be imported from output
的错误。在我回想起必须事先安装jinja2
之前,此错误是非常意外且难以理解的。
我考虑过这种解决方案:如果该类不可用,__init__.py
可以使用该名称创建一个字符串。如果用户尝试使用常规的类构造函数实例化此对象,则他们将获得更有意义的错误。不幸的是,简单导入
from output import RenderLaTeX
在这种情况下不会引发错误。
您希望提出什么建议,并希望对优点和缺点进行描述?
答案 0 :(得分:1)
当Python导入模块时,将执行要从中导入文件的所有代码。
因此,如果将RenderLaTeX
类放在单独的文件中,则可以自由添加逻辑,以在缺少必需的依赖项时阻止其导入(或运行)。
例如:
try:
import somethingidonthave
except ImportError:
raise Exception('You need this module!')
class RenderLaTeX(object):
pass
您还可以将所需的任何自定义消息添加到异常中,以更好地描述错误。这应该在Python2和Python3中都可以使用。
答案 1 :(得分:0)
经过一年的思考,解决方案出现了。
首先,我认为覆盖异常类型是没有意义的。唯一的好方法是为丢失的导入添加有用的消息。
其次,我认为语法
from framework.renderers import MyRenderer
确实比
from framework.renderers.my_renderer import MyRenderer
因为它隐藏了实现细节并且需要更少的用户代码(我更新了我的问题以反映这一点)。要使前一种语法起作用,我必须在模块的 __init__.py
中导入 MyRenderer。
现在,在 my_renderer.py
中,我通常会使用
import huge_specific_library
在标题中。 PEP 8 需要此语法。但是,这会使整个 framework.renderers 模块依赖于 huge_specific_library。
解决方案是违反 PEP 8 并在类本身内部导入库:
class MyRenderer():
def __init__(self):
import huge_specific_library
# ... use that...
在这里您可以捕获重要的异常,更改其消息等。还有另一个好处:存在如何减少导入时间的指南,并且他们提出了这个解决方案(我很久以前读过它们并且忘记)。大型模块需要一些时间来加载。如果你遵循 PEP 8 风格指南(我仍然认为你通常应该这样做),这可能会导致大量的延迟,只是为了将所有导入到你的程序,还没有做任何有用的事情。
唯一的警告是:如果您在 __init__ 中导入库,您还应该将其导入到使用它的其他类方法中,否则它将在那里不可见。
对于那些仍然有疑问的人,我必须补充一点,由于 Python 导入是缓存的,如果您使用导入的方法不经常调用,这不会影响性能。