попробуйте python: кроме: наконец - PullRequest
44 голосов
/ 15 октября 2011
# Open new file to write
file = None
try:
    file = open(filePath, 'w')
except IOError:
    msg = ("Unable to create file on disk.")
    file.close()
    return
finally:
    file.write("Hello World!")
    file.close()

Приведенный выше код извлечен из функции.Одна из систем пользователя сообщает об ошибке в строке:

file.write("Hello World!")

error:

AttributeError: 'NoneType' object has no attribute 'write'

Вопрос в том, если python не удалось открыть данный файл, выполняется блок «кроме» ион должен вернуться, но управление передается на строку, которая выдает данную ошибку.Значение переменной 'file' равно 'None'.

Любые указатели?

Ответы [ 8 ]

96 голосов
/ 15 октября 2011

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

Блок except выполняется, если исключение вызвано блоком try. Блок finally всегда выполняет все, что происходит.

Также не должно быть необходимости инициализировать переменную file в none.

Использование return в блоке except не пропустит блок finally. По самой своей природе он не может быть пропущен, поэтому вы хотите поместить туда свой код «очистки» (т.е. закрытие файлов).

Итак, если вы хотите использовать try: кроме: наконец, вы должны делать что-то вроде этого:

try:
    f = open("file", "w")
    try:
        f.write('Hello World!')
    finally:
        f.close()
except IOError:
    print 'oops!'

Более чистый способ сделать это - использовать выражение with:

try:
    with open("output", "w") as outfile:
        outfile.write('Hello World')
except IOError:
    print 'oops!'
27 голосов
/ 15 октября 2011

Если файл не открыт, строка file = open(filePath, 'w') завершается сбоем, поэтому ничего не присваивается file.

Затем выполняется предложение except, но в файле ничего нет, поэтому file.close() fails.

Предложение finally всегда выполняется, даже если было исключение.А поскольку file по-прежнему None, вы получаете еще одно исключение.

Вы хотите использовать else вместо finally для вещей, которые происходят, только если не было исключений.

    try:
        file = open(filePath, 'w')
    except IOError:
        msg = "Unable to create file on disk."
        return
    else:
        file.write("Hello World!")
        file.close()

Почему else? Python docs говорит:

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

Другими словами, он не будет перехватывать IOError при вызовах write или close.Это хорошо, потому что тогда причина не в том, что «Невозможно создать файл на диске» - это была бы другая ошибка, к которой ваш код не был подготовлен.Не стоит пытаться справляться с такими ошибками.

4 голосов
/ 15 октября 2011

Какова логика включения

file.write("Hello World!")

в предложение finally ??я думаю, что это должно быть включено в try само предложение.

try:
        file = open(filePath, 'w')
        file.write("Hello World!")
except IOError:
        print("Unable to create file on disk.")
finally:
        file.close()
1 голос
/ 25 августа 2016

Вот самое прямое решение вашей проблемы.Я использую идиому проверки для file_obj != None в блоке finally.

Кстати, вы должны знать, что file - это имя класса Python, поэтому вам следует выбрать другое имя переменной.

file = None
try:
    file = open(filePath, 'w')
except IOError:
    msg = ("Unable to create file on disk.")
    file.close()
    return
finally:
    if file != None:
        file.write("Hello World!")
        file.close()
1 голос
/ 20 ноября 2015

Вы можете сделать что-то вроде этого:

try:
    do_some_stuff()
finally:
    cleanup_stuff()
1 голос
/ 15 октября 2011

за исключением того, что не выполняется (потому что типом является IOError), это, наконец, часть, которая генерирует еще одну ошибку типа AttributeError, потому что file = None.

0 голосов
/ 23 мая 2015

Всегда желательно написать свою логику или код, который может вызвать исключение в блоке try, и использовать блок finally для закрытия ресурсов.

0 голосов
/ 15 октября 2011

наконец всегда вызывается в «конце», даже если происходит исключение. Вы можете использовать это, чтобы убедиться, что открытые ресурсы закрыты (например, соединение с БД, файл и т. Д.).

Я думаю, вы неправильно поняли семантику.

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

...