Поиск эквивалента FileNotFoundError в Python 2
Я создал класс с именем "Параметры". Он отлично работает, но не с Python 2.
И я хочу, чтобы он работал как на Python 2, так и на 3.
Проблема идентифицирована: FileNotFoundError не существует в Python 2.
Но если я использую IOError, он не работает в Python 3
Изменено в версии 3.3: EnvironmentError, IOError, WindowsError, VMSError, socket.error, select.error и mmap.error объединены в OSError.
Что мне делать? (Пожалуйста, не обсуждайте мой переносимость, у меня есть причины.)
Вот код:
#!/usr/bin/python
#-*-coding:utf-8*
#option_controller.py
#Walle Cyril
#25/01/2014
import json
import os
class Options():
"""Options is a class designed to read, add and change informations in a JSON file with a dictionnary in it.
The entire object works even if the file is missing since it re-creates it.
If present it must respect the JSON format: e.g. keys must be strings and so on.
If something corrupted the file, just destroy the file or call read_file method to remake it."""
def __init__(self,directory_name="Cache",file_name="options.json",imported_default_values=None):
#json file
self.option_file_path=os.path.join(directory_name,file_name)
self.directory_name=directory_name
self.file_name=file_name
#self.parameters_json_file={'sort_keys':True, 'indent':4, 'separators':(',',':')}
#the default data
if imported_default_values is None:
DEFAULT_INDENT = 2
self.default_values={\
"translate_html_level": 1,\
"indent_size":DEFAULT_INDENT,\
"document_title":"Titre"}
else:
self.default_values=imported_default_values
def read_file(self,read_this_key_only=False):
"""returns the value for the given key or a dictionary if the key is not given.
returns None if it s impossible"""
try:
text_in_file=open(self.option_file_path,'r').read()
except FileNotFoundError:#not 2.X compatible
text_in_file=""#if the file is not there we re-make one with default values
if text_in_file=="":#same if the file is empty
self.__insert_all_default_values()
text_in_file=open(self.option_file_path,'r').read()
try:
option_dict=json.loads(text_in_file)
except ValueError:
#if the json file is broken we re-make one with default values
self.__insert_all_default_values()
text_in_file=open(self.option_file_path,'r').read()
option_dict=json.loads(text_in_file)
if read_this_key_only:
if read_this_key_only in option_dict:
return option_dict[read_this_key_only]#
else:
#if the value is not there it should be written for the next time
if read_this_key_only in self.default_values:
self.add_option_to_file(read_this_key_only,self.default_values[read_this_key_only])
return self.default_values[read_this_key_only]
else:
#impossible because there is not default value so the value isn t meant to be here
return None
else:
return option_dict
def add_option_to_file(self,key,value):#or update
"""Adds or updates an option(key and value) to the json file if the option exists in the default_values of the object."""
option_dict=self.read_file()
if key in self.default_values:
option_dict[key]=value
open(self.option_file_path,'w').write(\
json.dumps(option_dict,sort_keys=True, indent=4, separators=(',',':')))
def __insert_all_default_values(self):
"""Recreate json file with default values.
called if the document is empty or non-existing or corrupted."""
try:
open(self.option_file_path,'w').write(\
json.dumps(self.default_values,sort_keys=True, indent=4, separators=(',',':')))
except FileNotFoundError:
os.mkdir(self.directory_name)#Create the directory
if os.path.isdir(self.directory_name):#succes
self.__insert_all_default_values()
else:
print("Impossible to write in %s and file %s not found" % (os.getcwd(),self.option_file_path))
#demo
if __name__ == '__main__':
option_file_object=Options()
print(option_file_object.__doc__)
print(option_file_object.read_file())
option_file_object.add_option_to_file("","test")#this should have no effect
option_file_object.add_option_to_file("translate_html_level","0")#this should have an effect
print("value of translate_html_level:",option_file_object.read_file("translate_html_level"))
print(option_file_object.read_file())
Ответы
Ответ 1
Вы можете использовать исключение базового класса EnvironmentError и использовать атрибут 'errno', чтобы выяснить, какое исключение было создано:
from __future__ import print_function
import os
import errno
try:
open('no file of this name') # generate 'file not found error'
except EnvironmentError as e: # OSError or IOError...
print(os.strerror(e.errno))
Или просто используйте IOError так же:
try:
open('/Users/test/Documents/test') # will be a permission error
except IOError as e:
print(os.strerror(e.errno))
Это работает на Python 2 или Python 3.
Будьте осторожны, чтобы не сравнивать непосредственно с числовыми значениями, потому что они могут быть разными на разных платформах. Вместо этого используйте именованные константы в стандартной библиотеке errno
библиотеки Python, которая будет использовать правильные значения для платформы времени выполнения.
Ответ 2
Если FileNotFoundError
не существует, определите его:
try:
FileNotFoundError
except NameError:
FileNotFoundError = IOError
Теперь вы можете поймать FileNotFoundError
в Python 2, так как это действительно IOError
.
Будьте осторожны, хотя IOError
имеет другие значения. В частности, любое сообщение должно, вероятно, сказать, что "файл не может быть прочитан", а не "файл не найден".
Ответ 3
Для чего это стоит, хотя IOError
едва упоминается в официальном документе Python 3 и даже не отображается в его официальной иерархии исключений, он все еще там, и это родительский класс FileNotFoundError
в Python 3. См. python3 -c "print(isinstance(FileNotFoundError(), IOError))"
дает вам значение True
. Следовательно, вы можете технически написать свой код таким образом, который работает как для Python 2, так и для Python 3.
try:
content = open("somefile.txt").read()
except IOError: # Works in both Python 2 & 3
print("Oops, we can not read this file")
Это может быть "достаточно хорошо" во многих случаях. Хотя в целом не рекомендуется полагаться на недокументированное поведение. Так что я на самом деле не предлагаю такой подход. Я лично использую ответ Kindall.
Ответ 4
Python 2/3-совместимый способ за исключением FileNotFoundError
заключается в следующем:
import errno
try:
with open('some_file_that_does_not_exist', 'r'):
pass
except EnvironmentError as e:
if e.errno != errno.ENOENT:
raise
Другие ответы близки, но не повышайте, если номер ошибки не совпадает.
Использование IOError
подходит для большинства случаев, но по какой-то причине os.listdir()
и его друзья вместо этого поднимают OSError
на Python 2. Поскольку IOError
наследует от OSError
хорошо просто всегда перехватывать OSError
и проверять номер ошибки.
Редактировать: предыдущее предложение верно только для Python 3. Чтобы обеспечить перекрестную совместимость, вместо этого перехватите EnvironmentError
и проверьте номер ошибки.