Как бы вы поймали Python Exception внутри исключения, кроме - PullRequest
1 голос
/ 21 октября 2019

Как бы вы поймали исключение в исключении в Python?

Рассмотрим следующий случай

bak_filename = filename + ".bak"
#This try is needed because if bak_filename existed, rename will fail
try:
   os.rename(filename, bak_filename)
except WindowsError:
   #However, os.remove may still fail e.g. file in use. How would you handle this exception within except clause ?
   #try and except around this os.remove?  
   os.remove(bak_filename)

   os.rename(filename, bak_filename)

Любая мысль:

  1. Переписать наизбегать двойных try ?

  2. Не обязательно этот пример, но в некоторых случаях мы не можем переписать, как бы вы справились с double try ?

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Решением, позволяющим избежать всех этих исключений, является использование shutil.move

shutil.move(filename, bak_filename)

Если место назначения уже существует, но не является каталогом, оно может бытьперезаписывается в зависимости от семантики os.rename ().

Если место назначения находится в текущей файловой системе, тогда используется os.rename (). В противном случае src копируется в dst с помощью copy_function, а затем удаляется. В случае символических ссылок, новая символическая ссылка, указывающая на цель src, будет создана в или как dst, и src будет удален.

Так что это в основном делает то, что вы пытаетесь сделать, но вбиблиотека, доступная на всех дистрибутивах Python.

Обратите внимание, что производительность может быть плохой, если файл большой и целевой файл существует , а os.rename отказывается перезаписывать его (полностью зависитв операционной системе, но, например, Windows будет отказываться переименовывать поверх существующего файла), потому что откат, когда os.rename выбрасывает OSError, копирует источник , а затем удаляет. Реализация не пытается удалить файл , а затем переименовать снова, потому что если rename не удается, Python предполагает, что мы пытаемся переименовать через файловые системы, и в этом случае порядок копирования + удаления в порядке(именно так работает Unix mv).

try:
    os.rename(src, real_dst)
except OSError:
    if os.path.islink(src):
        ...
    else:
        copy_function(src, real_dst)
        os.unlink(src)

Чтобы обойти это возможное существование файла, можно выполнить предыдущий вызов os.remove, заключенный в оператор try/except OSError.

try:
   os.remove(bak_filename)
except OSError:
   pass
shutil.move(filename, bak_filename)  # or os.rename(filename, bak_filename)

Конечно, если bak_filename заблокирован / не удаляется, исключение все равно может быть вызвано на shutil.mode. Также обратите внимание, что если мы попытались удалить целевой файл, os.rename будет так же хорошо, как shutil.move. Если целевой файл не может быть удален, операция все равно не может быть успешной.

0 голосов
/ 21 октября 2019

Подробнее о Цепочка исключений . Но это для Python 3

В Python 2 вы можете сохранить свое исключение в переменной, а затем вызвать его снова в явном виде, например:

try:
    do something
except Exception as e:
    try:
        do something again
    except:
        pass
    raise e
...