web-dev-qa-db-ja.com

Python 2でFileNotFoundErrorに相当するものを検索する

Optionsという名前のクラスを作成しました。正常に動作しますが、Python 2.では動作しません。そして、Python 2と3の両方で動作することを望みます。 in 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 __== '__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())
39
Walle Cyril

基本クラスの例外 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。

異なる場合があります 異なるプラットフォームでは、数値と直接比較しないように注意してください。代わりに、 Pythonの標準ライブラリerrnoモジュール で名前付き定数を使用します。これにより、実行時プラットフォームに正しい値が使用されます。

22
dawg

FileNotFoundErrorが存在しない場合は、定義します。

try:
    FileNotFoundError
except NameError:
    FileNotFoundError = IOError

これで、実際にFileNotFoundErrorであるため、Python 2でIOErrorをキャッチできます。

ただし、IOErrorには他の意味があることに注意してください。特に、メッセージはおそらく「ファイルが見つかりません」ではなく「ファイルを読み取れませんでした」と言う必要があります。

44
kindall

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()と友人は代わりにPython 2でOSErrorを発生させます。 IOErrorOSErrorから継承するため、常にOSErrorをキャッチしてエラー番号を確認するだけで問題ありません。

編集:前の文はPython 3.でのみ当てはまります。相互互換性を持たせるには、代わりにEnvironmentErrorをキャッチしてエラー番号を確認します。

4
leafmeal

価値があるのは、IOErrorPython 3の公式ドキュメント でほとんど言及されておらず、 その公式の例外階層 にも現れていないが、それでもそこにあり、それはPython 3.のFileNotFoundErrorの親クラスです。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の答え を使用しています。

2
RayLuo