保持继续代码不会在尝试中失败...除外?

时间:2011-07-09 08:53:27

标签: python

Dive into Python -

这是本书中使用的fileinfo.py小片段。这是打开一个MP3文件并读取最后128个字节以获取并稍后解析元数据。

try:                                
  fsock = open(filename, "rb", 0) 
  try:                           
    fsock.seek(-128, 2)         
    tagdata = fsock.read(128)   
  finally:                        
    fsock.close()              
  .
  .                       # process tagdata: will NEVER raise IOError though
  .
except IOError:                     
  pass

这可以重构为:

try:                                
  fsock = open(filename, "rb", 0) 
  try:                           
    fsock.seek(-128, 2)         
    tagdata = fsock.read(128)         
except IOError:                     
  pass
finally:
  fsock.close()              

.
.                       # process tagdata
.

在我学习Java时,我甚至习惯了这个问题。我们是否应该保留可以在try..except块内实际引发异常的逻辑,或者为了保持在一个地方执行某项特定工作的代码;保留其他代码,不会在try...except

内引发异常

4 个答案:

答案 0 :(得分:6)

最常被接受的标准是尽可能少地将代码放在try..except中。推理是,如果尝试了大量代码,你就不知道其他代码将会引发什么然后它变得非常混乱。

您可以在PEP 8中看到许多优秀的样式信息,其中包括:

- Additionally, for all try/except clauses, limit the 'try' clause
  to the absolute minimum amount of code necessary.  Again, this
  avoids masking bugs.

  Yes:

      try:
          value = collection[key]
      except KeyError:
          return key_not_found(key)
      else:
          return handle_value(value)

  No:

      try:
          # Too broad!
          return handle_value(collection[key])
      except KeyError:
          # Will also catch KeyError raised by handle_value()
          return key_not_found(key)

答案 1 :(得分:6)

try / finally子句的主要目的是关闭文件而不管发生了什么,将其移到外部try / except是没有意义的我假设你正在努力做到:

try:
    fsock = open(filename, "rb", 0)
    try:
        fsock.seek(-128, 2)
        tagdata = fsock.read(128)
    except:
        pass
except IOError:
    pass
finally:
    fsock.close()

原因是,如果实际提出IOError,则调用fsock.close()会引发另一个异常,因为不会分配fsock。而不是其中之一,最好使用with语句,它将自动为您关闭文件:

try:
    with open(filename, 'rb') as fsock:
        fsock.seek(-128, 2)
        tagdata = fsock.read(128)
except IOError:
    pass

答案 2 :(得分:1)

第二段代码在语法上是无效的,所以你应该更喜欢第一种形式。

如果你通过添加exceptfinally子句使它在语法上有效,那么它在语义上是无效的:如果open失败,你仍然会尝试关闭fsock,不会被分配。

答案 3 :(得分:0)

如果open失败,则您无法分配到tagdata,因此您不应允许代码到达处理tagdata的位置。通常,处理此问题的最佳方法是在更高级别处理IOError(即将其包装在函数中并在调用上下文中处理它)。

顺便说一句,在现代Python中,我们不需要使用finally来做这类事情 - 我们有一个更强大的习惯用法。我们还有一个else子句,可以附加到try / except块,只有在异常处理程序被调用时才会执行。

所以我们得到类似的东西:

def get_data():
    with open(filename, "rb", 0) as fsock:
        fsock.seek(-128, 2)
        return fsock.read(128)

def do_processing():
    try: tagdata = get_data()
    except IOError: handle_error()
    else: process(tagdata)