очистка при использовании исключений и файлов в python - PullRequest
3 голосов
/ 19 июля 2009

Я изучаю питон уже пару дней и борюсь с его «духом». Я прихожу из школы C / C ++ / Java / Perl и понимаю, что python - это не C (вообще), поэтому я пытаюсь понять дух, чтобы извлечь из него максимум пользы (и пока это сложно) ...

Мой вопрос особенно сосредоточен на обработке и очистке исключений: Код в конце этого поста предназначен для имитации довольно распространенного случая открытия / разбора файла, когда вам необходимо закрыть файл в случае ошибки ...

Большинство примеров, которые я видел, используют предложение else оператора try, чтобы закрыть файл ... что имело смысл для меня, пока я не понял, что ошибка может быть связана с

  • само отверстие (в этом случае нет необходимости закрывать открытый файл)
  • разбор (в котором если файл необходимо закрыть)

Ловушка здесь заключается в том, что если вы используете предложение 'else' блока try, тогда файл никогда не закроется, если во время синтаксического анализа произойдет ошибка! С другой стороны, использование предложения 'finally' приводит к дополнительной необходимой проверке, поскольку переменная file_desc может не существовать, если ошибка произошла во время открытия (см. Комментарии в коде ниже) ...

Эта дополнительная проверка неэффективна и полна дерьма, потому что любая разумная программа может содержать сотни символов, а синтаксический анализ результатов dir () - боль в заднице ... Не говоря уже об отсутствии читабельности такого утверждения. ..

Большинство других языков допускают определения переменных, которые могут сэкономить здесь время ... но в python все кажется неявным ...

Обычно, можно просто объявить переменную file_desc, а затем использовать много блоков try / catch для каждой задачи ... один для открытия, один для анализа и последний для закрытия () ... нет необходимости их вкладывать ... здесь я не знаю, как объявить переменную ... так что я застрял в самом начале проблемы!

так в чем тут дух питона ???

  • разделить открытие / анализ двумя разными способами? Как?
  • использовать какие-то вложенные предложения try / кроме ??? Как?
  • может быть, есть способ объявить переменную file_desc, и тогда нет необходимости в дополнительной проверке ... это вообще возможно ??? желательно ???
  • как насчет оператора close () ??? что если возникнет ошибка?

спасибо за подсказки ... вот пример кода:

class FormatError(Exception):
    def __init__(self, message):
        self.strerror = message
    def __str__(self):
        return repr(message)


file_name = raw_input("Input a filename please: ")
try:
    file_desc = open(file_name, 'r')
    # read the file...
    while True:
        current_line = file_desc.readline()
        if not current_line: break
        print current_line.rstrip("\n")
    # lets simulate some parsing error...
    raise FormatError("oops... the file format is wrong...")
except FormatError as format_error:
    print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
except IOError as io_error:
    print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)
else:
    file_desc.close()
# finally:
#     if 'file_desc' in dir() and not file_desc.closed:
#        file_desc.close()

if 'file_desc' in dir():
    print "The file exists and closed={0}".format(file_desc.closed)
else:
    print "The file has never been defined..."

Ответы [ 5 ]

6 голосов
/ 19 июля 2009

Самый простой способ справиться с этим - использовать тот факт, что файловые объекты в Python 2.5+ являются контекстными менеджерами . Вы можете использовать оператор with для ввода контекста; метод __exit__ менеджера контекста автоматически вызывается при выходе из этой области действия with. Затем контекстное управление файлового объекта автоматически закрывает файл.

try:
    with file("hello.txt") as input_file:
        for line in input_file:
            if "hello" not in line:
                 raise ValueError("Every line must contain 'hello'!")
except IOError:
    print "Damnit, couldn't open the file."
except:
    raise
else:
    print "Everything went fine!"

Открытый дескриптор hello.txt будет автоматически закрыт, а исключения из области действия with распространяются за пределы.

2 голосов
/ 19 июля 2009

Просто примечание: вы всегда можете объявить переменную, и тогда она станет примерно такой:

file_desc = None
try:
    file_desc = open(file_name, 'r')
except IOError, err:
    pass
finally:
    if file_desc:
        close(file_desc)

Конечно, если вы используете более новую версию Python, конструкция, использующая менеджер контекста, будет намного лучше; тем не менее, я хотел бы указать, как вы можете в общем случае работать с исключениями и областью видимости переменных в Python.

1 голос
/ 19 июля 2009

Начиная с Python 2.5, есть команда with, которая упрощает некоторые из ваших задач. Подробнее об этом здесь . Вот преобразованная версия вашего кода:

class FormatError(Exception):
    def __init__(self, message):
        self.strerror = message
    def __str__(self):
        return repr(message)


file_name = raw_input("Input a filename please: ")
with open(file_name, 'r') as file_desc:
    try:
        # read the file...
        while True:
            current_line = file_desc.readline()
            if not current_line: break
            print current_line.rstrip("\n")
        # lets simulate some parsing error...
        raise FormatError("oops... the file format is wrong...")
    except FormatError as format_error:
        print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
    except IOError as io_error:
        print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)

if 'file_desc' in dir():
    print "The file exists and closed={0}".format(file_desc.closed)
else:
    print "The file has never been defined..."
0 голосов
/ 19 июля 2009

Близко, насколько мне известно, никогда не вернет ошибку.

Фактически, дескриптор файла будет закрыт при сборке мусора, поэтому вам не нужно делать это явно в Python. Хотя это все равно хорошее программирование, очевидно.

0 голосов
/ 19 июля 2009

ОК, я задница. edit: и кстати, большое спасибо за тех, кто уже ответил, когда я публиковал это

Код ниже делает свое дело. Вы должны создать вложенный блок с помощью оператора with, чтобы убедиться, что файл очищен:

class FormatError(Exception):
    def __init__(self, message):
        self.strerror = message
    def __str__(self):
        return repr(message)


file_name = raw_input("Input a filename please: ")
try:
    #
    # THIS IS PYTHON'S SPIRIT... no else/finally
    #
    with open(file_name, 'r') as file_desc:
        # read the file...
        while True:
            current_line = file_desc.readline()
            if not current_line: break
            print current_line.rstrip("\n")
        raise FormatError("oops... the file format is wrong...")
    print "will never get here"
except FormatError as format_error:
    print "The file {0} is invalid: {1}".format(file_name, format_error.strerror)
except IOError as io_error:
    print "The file {0} could not be read: {1}".format(file_name, io_error.strerror)

if 'file_desc' in dir():
    print "The file exists and closed={0}".format(file_desc.closed)
else:
    print "The file has never been defined..."
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...