Python's “open()” throws different errors for

2019-01-13 17:57发布

问题:

I have a script where a user is prompted to type a filename (of a file that is to be opened), and if the file doesn't exist in the current directory, the user is prompted again. Here is the short version:

file = input("Type filename: ")

...
try:
    fileContent = open(filename, "r")
    ...
except FileNotFoundError:
    ...

When I tested my script on my MacOS X in Python 3.3x it worked perfectly fine when I type the wrong filename on purpose (it executes the suite under "expect").

However, when I wanted to run my code on a Windows computer in Python 3.2x, I get an error that says that "FileNotFoundError" is not defined. So, Python 3.2 on Windows thinks "FileNotFoundError" is a variable and the programs quits with an error.

I figured out that Python 3.2 on Windows throws an "IOError" if the input filename is not valid. I tested it on my Linux machine in Python 2.7, and it's also an IOError.

My problem is now, that the code with

except "FileNotFoundError":

won't run on Windows's Python 3.2, but if I change it to

except "IOError":

it won't work on my Mac anymore.

How could I work around it? The only way I can think of is to use just except, which I usually don't want.

回答1:

In 3.3, IOError became an alias for OSError, and FileNotFoundError is a subclass of OSError. So you might try

except (OSError, IOError) as e:
   ...

This will cast a pretty wide net, and you can't assume that the exception is "file not found" without inspecting e.errno, but it may cover your use case.

PEP 3151 discusses the rationale for the change in detail.



回答2:

This strikes me as better than a simple except:, but I'm not sure if it is the best solution:

error_to_catch = getattr(__builtins__,'FileNotFoundError', IOError)

try:
    f = open('.....')
except error_to_catch:
    print('!')


回答3:

So to exactly catch only when a file is not found, I do:

import errno
try:
   open(filename, 'r')
except (OSError, IOError) as e: # FileNotFoundError does not exist on Python < 3.3
   if getattr(e, 'errno', 0) == errno.ENOENT:
      ... # file not found
   raise


回答4:

you can catch 2 errors at the same time

except (FileNotFoundError, IOError):

I didn't realize that is what you were asking. I hope there is a more eloquent solution then to manually inspect

try:
   error_to_catch = FileNotFoundError
except NameError:
   error_to_catch = IOError

except error_to_catch

cwallenpoole does this conditional more eloquently in his answer (error_to_catch = getattr(__builtins__,'FileNotFoundError', IOError))