简体   繁体   English

在导入时引发自定义异常

[英]Raise a custom exception on import

Short question: I have a module with objects.简短的问题:我有一个带有对象的模块。 How can I do that if someone imports an object from my module, my specified exception is raised?如果有人从我的模块导入一个对象,我的指定异常被引发,我该怎么做?

What I want to do: I write an architectural framework.我想做什么:我写一个架构框架。 A class for output depends on jinja2 external library.输出类依赖于jinja2外部库。 I want the framework to be usable without this dependency as well.我希望框架也可以在没有这种依赖性的情况下使用。 In the package's __init__.py I write conditional import of my class RenderLaTeX (if jinja2 is available, the class is imported, otherwise not).在包的__init__.py我编写了我的类RenderLaTeX条件导入(如果 jinja2 可用,则导入该类,否则不导入)。

The problem with this approach is that I have some code which uses this class RenderLaTeX , but when I run it on a fresh setup, I receive an error like Import error: no class RenderLaTeX could be imported from output .这种方法的问题是我有一些代码使用了这个类RenderLaTeX ,但是当我在新的设置上运行它时,我收到一个错误,比如Import error: no class RenderLaTeX could be imported from output This error is pretty unexpected and ununderstandable before I recall that jinja2 must be installed beforehand.在我记得必须事先安装jinja2之前,这个错误是非常意外和无法理解的。

I thought about this solution: if the class is not available, __init__.py can create a string with this name.我想到了这个解决方案:如果类不可用, __init__.py可以创建一个具有此名称的字符串。 If a user tries to instantiate this object with the usual class constructor, they'll get a more meaningful error.如果用户尝试使用通常的类构造函数实例化这个对象,他们会得到一个更有意义的错误。 Unfortunately, simple import不幸的是,简单的导入

from output import RenderLaTeX

won't raise an error in this case.在这种情况下不会引发错误。

What would you suggest, hopefully with the description of benefits and drawbacks?您有什么建议,希望能结合优点和缺点的描述?

Important UPD: I package my classes in modules and import them to the module via __init__.py , so that I import 'from lena.flow import ReadROOTFile', rather than 'from lena.flow.read_root_file import ReadROOTFile.'重要 UPD:我将我的类打包在模块中,并通过__init__.py将它们导入模块,以便我导入“from lena.flow import ReadROOTFile”,而不是“from lena.flow.read_root_file import ReadROOTFile”。

When Python imports a module all of the code inside the file from which you are importing is executed.当 Python 导入一个模块时,您要从中导入的文件中的所有代码都会被执行。

If your RenderLaTeX class is therefore placed into a seperate file you can freely add logic which would prevent it from being imported (or run) if required dependencies are missing.如果您的RenderLaTeX类因此被放置到一个单独的文件中,您可以自由添加逻辑,如果缺少所需的依赖项,将阻止它被导入(或运行)。

For example:例如:

try:
    import somethingidonthave
except ImportError:
    raise Exception('You need this module!')

class RenderLaTeX(object):
    pass

You can also add any custom message you want to the exception to better describe the error.您还可以将您想要的任何自定义消息添加到异常中以更好地描述错误。 This should work in both Python2 and Python3.这应该适用于 Python2 和 Python3。

After a year of thinking, the solution appeared.经过一年的思考,解决方案出现了。

First of all, I think that this is pretty meaningless to overwrite an exception's type.首先,我认为覆盖异常类型是毫无意义的。 The only good way would be to add a useful message for a missing import.唯一的好方法是为丢失的导入添加有用的消息。

Second, I think that the syntax其次,我认为语法

from framework.renderers import MyRenderer

is really better than真的比

from framework.renderers.my_renderer import MyRenderer

because it hides implementation details and requires less code from user (I updated my question to reflect that).因为它隐藏了实现细节并且需要更少的用户代码(我更新了我的问题以反映这一点)。 For the former syntax to work, I have to import MyRenderer in __init__.py in the module.为了使前一种语法起作用,我必须在模块的__init__.py中导入MyRenderer

Now, in my_renderer.py I would usually import third-party packages with现在,在my_renderer.py我通常会导入第三方包

import huge_specific_library

in the header.在标题中。 This syntax is required by PEP 8 . PEP 8需要此语法。 However, this would make the whole framework.renderers module depend on huge_specific_library .然而,这会使整个framework.renderers模块依赖于huge_specific_library

The solution for that is to violate PEP 8 and import the library inside the class itself:解决方案是违反 PEP 8 并在类本身中导入库:

class MyRenderer():

    def __init__(self):
        import huge_specific_library
        # ... use that...

Here you can catch the exception if that is important, change its message, etc. There is another benefit for that: there exist guides how to reduce import time, and they propose this solution (I read them a long time ago and forgot).如果这很重要,您可以在这里捕获异常,更改其消息等。还有另一个好处:存在如何减少导入时间的指南,他们提出了这个解决方案(我很久以前读过它们但忘记了)。 Large modules require some time to be loaded.大型模块需要一些时间来加载。 If you follow PEP 8 Style Guide (I still think that you usually should), this may lead to large delays just to make all imports to your program, not having done anything useful yet.如果您遵循 PEP 8 样式指南(我仍然认为您通常应该这样做),这可能会导致大量延迟,只是为了将所有导入到您的程序中,而还没有做任何有用的事情。

The only caveat is this: if you import the library in __init__ , you should also import that to other class methods that use it, otherwise it won't be visible there.唯一的警告是:如果您在__init__ 中导入库,您还应该将其导入到使用它的其他类方法中,否则它将在那里不可见。

For those who still doubt, I must add that since Python imports are cached, this doesn't affect performance if your method that uses import is not called too often.对于那些仍然怀疑的人,我必须补充一点,由于 Python 导入已被缓存,因此如果您使用 import 的方法调用频率不高,这不会影响性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM