Python 在 __init__ 中处理异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20059766/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 19:24:10  来源:igfitidea点击:

Handle exception in __init__

pythonexception

提问by Abhishek Chanda

Is it fine to raise an exception in __init__in python? I have this piece of code:

__init__在python中引发异常可以吗?我有这段代码:

class VersionManager(object):
    def __init__(self, path):
        self._path = path
        if not os.path.exists(path): os.mkdir(path)
        myfunction(path)

The second line can potentially result in an exception. In that case the object will not be init'ed properly. Is there a better way to handle situations where code in __init__might throw an exception?

第二行可能会导致异常。在这种情况下,对象将不会被正确初始化。有没有更好的方法来处理代码__init__可能抛出异常的情况?

EDITAdded a call to a function after os.mkdir
Added a check to see if directory exists

编辑os.mkdir
添加了检查目录是否存在之后添加了对函数的调用

采纳答案by dawg

It is perfectly fine to raise an exception in __init__. You would then wrap the object initiation/creation call with try/exceptand react to the exception.

__init__. 然后,您将使用该对象启动/创建调用包装try/except并对异常做出反应。

One potential odd result though is that __del__is run anyway:

一个潜在的奇怪结果__del__是无论如何都会运行:

class Demo(object):
    def __init__(self, value):
        self.value=value
        if value==2:
            raise ValueError
    def __del__(self):
        print '__del__', self.value


d=Demo(1)     # successfully create an object here
d=22          # new int object labeled 'd'; old 'd' goes out of scope
              # '__del__ 1' is printed once a new name is put on old 'd'
              # since the object is deleted with no references 

Now try with the value 2that we are testing for:

现在尝试使用2我们正在测试的值:

Demo(2)
Traceback (most recent call last):
  File "Untitled 3.py", line 11, in <module>
    Demo(2)           
  File "Untitled 3.py", line 5, in __init__
    raise ValueError
  ValueError
 __del__ 2 # But note that `__del__` is still run.

The creation of the object with value 2raises a ValueErrorexception and show that __del__is still run to clean up the object.

创建具有值的对象2会引发ValueError异常并显示__del__仍在运行以清理对象。

Keep in mind that if you raise an exception during __init__your object will not get a name. (It will, however, be created and destroyed. Since __del__is paired with __new__it still gets called)

请记住,如果您在__init__对象期间引发异常将不会获得名称。(然而,它将被创建和销毁。因为__del____new__它配对仍然被调用)

ie, just like this does not create x:

即,就像这样不会创建x

>>> x=1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

Potential sneakier:

潜行者:

>>> x='Old X'
>>> x=1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> x
'Old X'

Same thing if you catch an exception of __init__:

如果您捕获以下异常,则同样的事情__init__

try:
    o=Demo(2)
except ValueError:
    print o          # name error -- 'o' never gets bound to the object...
                     # Worst still -- 'o' is its OLD value!

So don't try to refer to the incomplete object o-- it's gone out of scope by the time you get to except. And the name ois either nothing (i.e., NameErrorif you try to use it) or its old value.

所以不要试图引用不完整的对象o——当你到达except. 并且名称o要么是空的(即,NameError如果您尝试使用它)或它的旧值。

So wrapping up (thanks to Steve Jessop for the User Defined Exceptionidea), you can wrap the creation of the object and catch the exception. Just figure out how to react appropriately to the OS error you are looking at.

所以总结一下(感谢 Steve Jessop 提出用户定义异常的想法),您可以包装对象的创建并捕获异常。只需弄清楚如何对您正在查看的操作系统错误做出适当的反应。

So:

所以:

class ForbiddenTwoException(Exception): 
    pass

class Demo(object):
    def __init__(self, value):
        self.value=value
        print 'trying to create with val:', value
        if value==2:
            raise ForbiddenTwoException
    def __del__(self):
        print '__del__', self.value

try:
    o=Demo(2)
except ForbiddenTwoException:
    print 'Doh! Cant create Demo with a "2"! Forbidden!!!'
    # with your example - react to being unusable to create a directory... 

Prints:

印刷:

trying to create with val: 2
Doh! Cant create Demo with a "2"! Forbidden!!!
__del__ 2

回答by jramirez

You can use try/except when initializing the object.

您可以在初始化对象时使用 try/except。

try:

    ver = VersionManager(my_path)

except Exception as e:
    # raise e or handle error
    print e

回答by mAsT3RpEE

My favourite is to simply output errors to console and march on:

我最喜欢的是简单地将错误输出到控制台并继续:

import sys, os, traceback

class Myclass
    def __init__(self, path):
        self._path = path

        """Risky Code"""
        try:
            os.mkdir(path) 
        except:
            traceback.print_exc(file = sys.stdout)

This way an exception will print out more like a warning rather than a real exception.

这样,异常将更像是一个警告而不是真正的异常。

回答by aIKid

You can wrap the call, as jramirez suggested:

您可以按照 jramirez 的建议结束通话:

try:
    ver = VersionManager(path)
except:
    raise

Or you can use a context manager:

或者您可以使用上下文管理器:

class VersionManager(object):
    def __init__(self):
        #not-so-harmful code
        self.path = path

    def __enter__(self):
        try:
            self.path = path
            os.mkdir(path)
            self.myfunction(path)
        except Exception as e:
            print e
            print "The directory making has failed, the function hasn't been executed."
        return self
    def __exit__(self, exc_type, exc_value, traceback):
        print(exc_type, exc_value, traceback)

And to run it:

并运行它:

with VersionManager(my_path) as myVersionManager:
     #do things you want with myVersionManager

This way, you'll catch errors inside the withstatement as well.

这样,您也将在with语句中捕获错误。