Python中的异常安全状态如何?
我知道Python中有一个叫做with的语句,用来处理资源。那在Python中,写出安全的代码还有哪些需要注意的地方呢?
补充一下:这里主要是关于打开文件之类的事情。比如说,如果一个初始化的函数抛出了一个异常,那这个正在初始化的对象的状态会是什么样的呢?
3 个回答
0
Python和C++不太一样。在Python中,出现错误时会给出有用的错误追踪信息。如果你在程序中需要处理用户输入,记得捕捉一些合适的错误,比如EOFError
。但如果不是这种情况,你就不需要特别处理错误,Python会帮你处理得很好。如果程序出现了意外情况并抛出了错误,你可以利用错误信息来调试你的问题。如果你希望程序能一直稳定运行,可以考虑在最外层加一个try/except
,并放在一个循环里,这样可以记录日志并重启程序。
3
如果你在问关于语言结构的事情:
- 使用
try: except: else:
这种写法可以确保你不会捕捉到错误的异常。 - 在捕捉
BaseException
、Exception
或者使用裸except:
之前要三思,因为这样很容易捕捉到太多东西:- 比如你的拼写错误 - NameError、ImportError
- 用户试图终止你的程序 - KeyboardInterrupt、SystemExit
- 表示实现不完整的错误 - NotImplementedError
- 如果你决定捕捉通用异常,记得用
log.exception('你的信息', e)
来记录它们。 - 要记住,Python 中的异常也可以用来进行正常的流程控制(比如
StopIteration
异常)。 - 使用新的语法:
except MyException as myex:
,而不是except MyException, myex:
。这样对于不太熟悉 Python 的开发者来说更容易阅读。
下面是一个捕捉 NameError 的例子:
try:
this_doesn_not_exisit();
except Exception: #Don't do that!
pass
print "But this line is still printed"
对编辑后问题的回答:
- 关于文件,如果你要读取文本文件,始终使用 codecs.open 而不是 open,这样可以确保你安全地存储 Unicode 字符串。
- 关于
__init__
和对象的状态。__init__
是一个初始化器,所以在调用__init__
时对象已经存在。如果你抛出异常,流程会被中断,对象不会被存储在任何变量中,所以它会被垃圾回收。至少这是我的理解。可以想象 MyObject() 就像是一个函数,如果你抛出异常,你就什么都不返回,流程被中断,你原本要赋值的内容也不会被修改。
看看这个:
>>> def throw(): raise Exception()
...
>>> a=1
>>> a=throw()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in throw
Exception
>>> a
1
这里有一个例子可以证明即使在 __init__
中抛出异常,对象仍然会被创建。我无法在评论中发布这个片段给 @S.Lott 的回答:
>>> global_collection=[]
>>> class Partial(object):
... def __init__(self):
... self.test="test"
... global_collection.append(self)
... raise Exception()
...
>>> x=Partial()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __init__
Exception
>>> global_collection
[<__main__.Partial object at 0xb74f8f6c>]
>>> global_collection[0].test
'test'
更新: 包含了 @Paul McGuire、@martineau、@aaronasterling 的评论
4
比如说,假设一个初始化函数出现了错误。那么,这个正在初始化的对象状态是什么呢?
提示:如果不确定,可以实际做个实验。
>>> class Partial( object ):
... def __init__( self ):
... self.a= 1
... raise Exception
... self.b= 2
...
>>> p= Partial()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
Exception
>>> p
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'p' is not defined
整个语句都会失败。对象没有被创建,变量也没有被赋值。还有其他问题吗?
在C++中,事情就复杂多了。在Python中,这个对象会被简单地丢弃。