Python: попробовать, кроме как выражение? - PullRequest
23 голосов
/ 17 августа 2011

У меня снова и снова возникает такая картина:

variable = ""
try:
    variable = ... do some file loading stuff ...
except:
    variable = ""

Есть ли способ сжать это в одно выражение? Как и в случае с инструкциями if-else, вы можете включить:

variable = ""
if something:
    variable = somethingelse
else:
    variable = ""

в

variable = somethingelse if something else ""

Есть ли что-то подобное для try-catch?

Ответы [ 6 ]

19 голосов
/ 17 августа 2011

Поскольку agf уже предоставил подход, который я бы порекомендовал, вот версия его процедуры с парой незначительных улучшений:

def try_except(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure() if callable(failure) else failure

Эта версия:

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

  2. Поддерживает использование простого значения, а также функцию для значения ошибки. Это избавляет вас от необходимости использовать лямбду во многих случаях. (Конечно, вместо lambda: '' вы можете просто использовать str.)

15 голосов
/ 17 августа 2011
def try_except(success, failure):
    try:
        return success()
    except:
        return failure()

variable = try_except(do_some_file_loading_stuff, lambda: '')

Я думаю, что код не требует пояснений.Он возвращает значение, возвращаемое success, если нет ошибки, затем возвращает значение, возвращаемое failure.Если do_some_file_loading_stuff является выражением, а не просто вызовом функции, оберните его также в lambda.

Edit: @kindall, и я немного улучшил его версию, так что это простотак же быстро, как у меня, может вызываться точно так же, если хотите, имеет больше возможностей и такое же количество строк.Используйте это!

def try_except(success, failure, *exceptions):
    try:
        return success()
    except exceptions or Exception:
        return failure() if callable(failure) else failure
12 голосов
/ 19 августа 2011

Вот менеджер контекста, который предоставляет немного ярлыка:

from contextlib import contextmanager

@contextmanager
def catch(*exceptions, **kwargs):
    try:
        yield kwargs.get("default", None)
    except exceptions or Exception:
        pass

Использование:

with catch(ZeroDivisionError, default=0) as x:
    x = 3 / 0              # error

print x                    # prints 0, the default

Основная идея здесь заключается в том, что менеджер контекста возвращает любое значение по умолчанию, которое вы ему передаете, которое затем присваивается переменной, указанной в предложении with оператора as. Затем внутри контекста вы выполняете оператор, который пытается присвоить эту же переменную. Если это вызывает исключение, менеджер контекста ловит и молча игнорирует его, но так как назначение не произошло, значение по умолчанию остается.

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

3 голосов
/ 17 августа 2011

К сожалению, нет, для него нет языковой конструкции, и я не знаю какой-либо действительно разборчивой и краткой идиомы. Я всегда хотел что-то подобное. Некоторое время назад кто-то объяснил мне, что в Python нет ничего похожего на variable = function_cal() except "", но они не очень убедительны, и я все еще скучаю по этой языковой конструкции:)

1 голос
/ 17 августа 2011

Очевидно, что последний способ сделать это более лаконичен и предпочтителен многими программистами, такими как вы.

Хотя сам по себе язык не обеспечивает «однострочную попытку-за исключением-поймать» по каким бы то ни было причинам, все хорошо и необходимо, я полагаю, вы, как правило, можете добиться этого, немного изменив программу; как например:

try:
    a_var = a_dict.get('abcd')
except a_dict.KeyError:
    a_var = ''

в

a_var = a_dict.get('abcd',default='')

и аналогично для запросов к БД;

try:
    a_qs = Model.objects.get(id=42)
except Model.DoesNotExist:
    a_qs = Model.objects.create(id=42)

с

a_qs = Model.objects.get_or_create(id=42,**kwargs)

и добавляйте подобные API в свои собственные программы, где это возможно. try-exception довольно «дешевый» в Python, и программирование на основе исключений предпочтительнее, чем «проверка в первую очередь», обычно предлагаемая в Java-подобных языках, из-за дорогостоящего характера обработки исключений. Таким образом, вам лучше обернуть эту «цепляющую вещь» в метод / функцию и вызывать ее везде, как, например, dict и другие конструкции.

0 голосов
/ 17 августа 2011

Нет простого способа упростить оператор try / catch, как в примере if / else, но я хочу отметить, что оператор python «with», представленный в python2.5, сделал множество интерфейсов для file / db io tryловить операторы проще и исключение безопасно.Операции ввода-вывода, как правило, используются там, где используется множество операторов try / catch.

with open("myfile.txt", "r") as f:
   # Do stuff with f

вместо

try:
   f = open("myfile.txt", "r")
   # Do stuff with f
except:
   pass
finally:
   if f: f.close
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...