开发者

keeping the continued code that will NOT fail still in try...except?

Dive into Python -

This is a small snippet from fileinfo.py used in the book. This is opening an MP3 file and reading the last 128 bytes to fetch and later parse the metadata.

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

This can be refactored as:

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

.
.                       # process tagdata
.

I even used to have this question when I was learning Java. Should we just keep the logic that can actually raise an exception inside the 开发者_运维问答try..except block or for the sake of keeping a code that does one particular job in ONE place; keep the other code that will NEVER raise an exception also within a try...except?


The try/finally clause's primary purpose is to close the file regardless of what happens, it doesn't make sense to move it the outer try/except as I assume you are trying to do:

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

The reason being, if IOError is actually raised, calling fsock.close() would raise another exception, since fsock would not have been assigned. Instead of either, it'd be preferable to use the with statement which will automatically close the file for you:

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


The most accepted standard is to put as little code in the try..except as possible. Reasoning is that you don't know what the other code will raise if there's a ton of code in a try.. then it becomes really messy.

You can see lots of good styling information in PEP 8, amongst which is:

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


The second piece of code is syntactically invalid, so you should prefer the first form.

If you'd make it syntactically valid by adding an except or finally clause, it would be semantically invalid: if the open fails, you'd still be trying to close fsock, which would not be assigned.


If the open fails then you can't assign to tagdata, so you should not allow the code to reach the point where you process tagdata. Often the best way to handle this is to process the IOError at a higher level (i.e. wrap this in a function and handle it in the calling context).

BTW, in modern Python we don't need to use finally for this sort of thing - we have a more powerful idiom. We also have an else clause that can be attached to try/except blocks that is executed only if the exception handlers are not invoked.

So we get something like:

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)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜