Обработка исключений Pythonic: ловить только определенные ошибки

Я часто читал, что в питоне «легче попросить прощения, чем разрешения», поэтому иногда считается, что лучше использовать try except вместо if.

У меня часто бывают такие утверждения, как

if (not os.path.isdir(dir)):
    os.mkdir(dir).

Вероятная замена будет

try:
    os.mkdir(dir)
except OSError:
    pass.

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

try:
    os.mkdir(dir)
except OSError:
    if(OSError.errno != errno.EEXIST):
        raise
    else:
        pass.

Кажется, это помогает. Но это действительно громоздко и «загрязнит» мой код и снизит читабельность, если мне понадобится много этих кодовых блоков. Есть ли питонический способ сделать это в Python 2.X? Какова стандартная процедура для таких случаев?

правки:

  • используйте повышение вместо повышения OSerror, как указал @Francisco Cuzo
  • Я использую Python 2.7

person DerWeh    schedule 23.10.2016    source источник
comment
Просто сделайте raise, а не raise OSError, чтобы не потерять контекст исключения   -  person Francisco C    schedule 23.10.2016
comment
Вы могли бы просто поймать FileExistsError: except FileExistsError: pass   -  person vaultah    schedule 23.10.2016
comment
Дубликат: stackoverflow.com/questions/20790580 /   -  person Hai Vu    schedule 23.10.2016
comment
Нет необходимости в else: pass, это лишнее.   -  person Mark Ransom    schedule 25.10.2016


Ответы (3)


Я только что наткнулся на, пожалуй, самое элегантное решение: создание контекстного менеджера ignored:

import errno
from contextlib import contextmanager

@contextmanager
def ignorednr(exception, *errornrs):
    try:
        yield
    except exception as e:
        if e.errno not in errornrs:
            raise
        pass


with ignorednr(OSError, errno.EEXIST):
     os.mkdir(dir)

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

Решение взято с https://www.youtube.com/watch?v=OSGv2VnC0go.

person DerWeh    schedule 25.12.2016

Если вы вызываете его несколько раз с разными аргументами, поместите его в функцию:

def catch(d, err):
    try:
        os.mkdir(d)
    except OSError as e:
        if e.errno != err:
            raise

Затем вызовите функцию, передающую любые аргументы:

 catch(, "foo", errno.EEXIST)

Вы также можете разрешить передачу нескольких ошибок, если хотите больше:

def catch(d, *errs):
    try:
        os.mkdir(d)
    except OSError as e:
        if e.errno not in errs:
            raise

catch("foo", errno.EEXIST, errno.EPERM)
person Padraic Cunningham    schedule 24.10.2016

Этот пример для исключения OSError : 17, 'File exists'

import sys
try:
    value = os.mkdir("dir")
except:
    e = sys.exc_info()[:2]
    e = str(e)
    if "17" in e:
        raise OSError #Perform Action
    else:
        pass   

Просто измените номер 17 на свой номер исключения. Вы можете получить более подробное объяснение по этой ссылке.

person Anurag Sinha    schedule 23.10.2016
comment
Я думаю, что мой вопрос уже дает лучший ответ, он короче и не использует явный номер. Я читал, что цифры могут отличаться в зависимости от системы, поэтому errno.EEXIST лучше и читабельнее. - person DerWeh; 24.10.2016