python的init函数异常,关于python:处理__init__中的异常

可以在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之后添加了对函数的调用

添加了检查以查看目录是否存在

不仅对象没有被正确初始化,没有异常处理程序,VersionManager(path)的调用者可以希望捕获异常并且根本没有实例。

os.mkdir是一种特殊情况,因为它在许多用户不是错误的情况下抛出异常 - 当目录已经存在时。因此,您可能希望明确处理该情况,除了您的__init__函数是否应该引发异常的问题。

谢谢你提醒我。但是,我对一个OSError更好奇,这可能是由于权限被拒绝引起的。

如果VersionManager需要存在目录才能工作,并且其__init__函数无法创建目录,那么允许异常传播是完全合理的。从__init__抛出异常的意思是,"我无法使这个对象起作用,所以我不会让你拥有该对象"。或许更正式地说,"我不能为这个对象建立不变量"。虽然再次创建文件或目录是类不变的特例。通常没有什么可以阻止其他进程删除它,所以"dir存在"不是一个适当的不变量。

Python的可能重复:在__init__中引发异常是不好的形式?

在__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

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"", line 1, in

ZeroDivisionError: integer division or modulo by zero

>>> x

Traceback (most recent call last):

File"", line 1, in

NameError: name 'x' is not defined

潜在的偷偷摸摸:

>>> x='Old X'

>>> x=1/0

Traceback (most recent call last):

File"", line 1, in

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的用户定义的异常想法),你可以包装对象的创建并捕获异常。只需弄清楚如何对您正在查看的操作系统错误作出适当的反应。

所以:

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

请注意,如果您想在处理错误时避免"可能",则可以删除所有疑问:class ForbiddenTwoException(ValueError): pass。

如果你认为__del__与__new__配对(并且__init__只是一个可能由__new__调用的函数),那么它需要被调用就不足为奇了。

@SteveJessop:谢谢!好主意...编辑...

@chepner:嗯,C ++方式是只有构造函数成功完成才会执行析构函数。因此,如果你按照你说的术语来考虑它,那么根据你认为"配对"应该意味着它是否令人惊讶:-)对于Python中的另一个例子,你可能会说__enter__与__exit__配对,但是如果__enter__抛出,则不会调用__exit__。我认为最好认为__del__与__new__配对,而__init__是在__new__之后调用的东西,而不是它。

我的观点是,仅仅因为__init__引发了异常,并不意味着__init__尚未完成需要清理的事情。 __new__是Python中的构造函数,而不是__init__(从语义上讲;我知道Python文档将__init__称为构造函数,但__new__实际上构造了对象; __init__之后只是设置了一些字段。

你可以打电话,正如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语句中捕获错误。

def __enter__(self, path):肯定不会奏效。

并且__exit__不会在__enter__中引发任何异常。

是的,我认为那是对的-_-。这就是为什么我也在__enter__函数中使用tryexcept块。

什么是except子句除了重新引发异常之外什么也没做什么?

嗯,你是对的,修好了。

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

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)

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

听起来不错。但是如果另一个函数需要创建目录,它将在except情况下失败。

对不起,这不适用于我。我的所有对象都有某种形式的状态标志。因此,如果目录没有创建,如果您稍后尝试调用函数,则会自动生成错误。我想我们有不同的编程风格。我认为主要问题是如何处理__init__()中的异常。

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

try:

ver = VersionManager(my_path)

except Exception as e:

# raise e or handle error

print e

并且您需要告诉OP ver会发生什么(例如它甚至不存在)

@MartijnPieters你可以回答......

你已经做了:),但感谢弃用的except上的指针。

@SteveP:正确跟进的时间很短

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值