处理__init__中的异常

时间:2013-11-18 22:57:43

标签: python exception

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

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

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

修改os.mkdir之后添加了对函数的调用 添加了检查以查看目录是否存在

4 个答案:

答案 0 :(得分:21)

__init__中引发异常完全没问题。然后,您将使用try/except包装对象启动/创建调用,并对异常做出反应。

但有一个奇怪的结果是__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 

现在尝试使用我们正在测试的值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.

创建值为2的对象会引发ValueError异常,并显示仍然运行__del__来清理对象。

请注意,如果您在__init__期间提出异常,您的对象将无法获得名称。 (但是,它会被创建和销毁。由于__del____new__配对,它仍会被调用)

即,就像这样不会创建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

潜在的偷偷摸摸:

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

如果你发现__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!

所以不要试图引用不完整的对象o - 当你到达except时它已超出范围。名称o要么没有(例如,NameError,如果您尝试使用它)或其旧值。

结束(感谢Steve Jessop的User Defined Exception想法),你可以包装对象的创建并捕获异常。只需弄清楚如何对您正在查看的操作系统错误作出适当的反应。

所以:

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... 

打印:

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

答案 1 :(得分:3)

你可以打电话,正如jramirez建议的那样:

try:
    ver = VersionManager(path)
except:
    raise

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

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)

并运行它:

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

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

答案 2 :(得分:0)

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

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)

这样,异常会打印出更像是警告而不是真正的异常。

答案 3 :(得分:-1)

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

try:

    ver = VersionManager(my_path)

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