Есть ли способ в python включить try/except в одну строку?
что-то вроде...
b = 'some variable'
a = c | b #try statement goes here
Где b
- объявленная переменная, а c
- не... поэтому c
выдаст ошибку, а a
станет b
...
Есть ли способ в python включить try/except в одну строку?
что-то вроде...
b = 'some variable'
a = c | b #try statement goes here
Где b
- объявленная переменная, а c
- не... поэтому c
выдаст ошибку, а a
станет b
...
Невозможно сжать блок try
/except
на одну строку в Python.
Кроме того, плохо знать, существует ли переменная в Python, как на других динамических языках. Более безопасный способ (и преобладающий стиль) заключается в том, чтобы все переменные были чем-то. Если они не могут быть установлены, сначала установите их None
(или 0
или ''
), если это более применимо.)
Если вы сделаете, сначала назначьте все имена, которые вас интересуют, у вас есть варианты.
Лучший вариант - это оператор if.
c = None
b = [1, 2]
if c is None:
a = b
else:
a = c
Вариант с одним слоем - условное выражение.
c = None
b = [1, 2]
a = c if c is not None else b
Некоторые люди злоупотребляют короткозамкнутым поведением or
, чтобы сделать это. Это склонно к ошибкам,, поэтому я никогда не использую его.
c = None
b = [1, 2]
a = c or b
Рассмотрим следующий случай:
c = []
b = [1, 2]
a = c or b
В этом случае a
, вероятно, должен быть []
, но это [1, 2]
, потому что []
является ложным в булевом контексте. Поскольку существует множество значений, которые могут быть ложными, я не использую трюк or
. (Это та самая проблема, с которой сталкиваются люди, когда они говорят if foo:
, когда они означают if foo is not None:
.)
Это ужасно хакерский, но я использовал его в приглашении, когда хотел написать последовательность действий для отладки:
exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]
По большей части меня совсем не беспокоит ограничение не-одиночной строки-try-except, но когда я просто экспериментирую, и я хочу, чтобы readline сразу вызывал целый фрагмент кода в интерактивный интерпретатор, чтобы как можно скорее его настроить, этот небольшой трюк пригодится.
Для фактической цели, которую вы пытаетесь выполнить, вы можете попробовать locals().get('c', b)
; в идеале было бы лучше использовать настоящий словарь вместо локального контекста или просто назначить c None, прежде чем запускать все, что может или не может его установить.
Другим способом является определение менеджера контекста:
class trialContextManager:
def __enter__(self): pass
def __exit__(self, *args): return True
trial = trialContextManager()
Затем используйте оператор with
для игнорирования ошибок в одной строке:
>>> with trial: a = 5 # will be executed normally
>>> with trial: a = 1 / 0 # will be not executed and no exception is raised
>>> print a
5
Никакое исключение не будет возникать в случае ошибки времени выполнения. Это как try:
без except:
.
parse_float = lambda x, y=exec("def f(s):\n try:\n return float(s)\n except: return None"): f(x)
Всегда есть решение.
Вы можете сделать это, обратившись к пространству имен dict, используя vars()
, locals()
или globals()
, в зависимости от того, что наиболее подходит для вашей ситуации.
>>> b = 'some variable'
>>> a = vars().get('c', b)
Вы упомянули, что используете джанго. Если это имеет смысл для того, что вы делаете, вы можете использовать:
my_instance, created = MyModel.objects.get_or_create()
created
будет True или False. Возможно, это поможет вам.
Проблема в том, что на самом деле это запрос django model.objects.get, который я пытаюсь проверить..get возвращает ошибку, если данные не найдены... он не возвращает None (что меня раздражает)
Используйте что-то вроде этого:
print("result:", try_or(lambda: model.objects.get(), '<n/a>'))
Где try_or - это функция полезности, определенная вами:
def try_or(fn, default):
try:
return fn()
except:
return default
При желании вы можете ограничить допустимые типы исключений до NameError
, AttributeError
и т.д.
В python3 вы можете использовать contextlib.suppress:
from contextlib import suppress
d = {}
with suppress(KeyError): d['foo']
если вам нужно управлять исключениями:
(модифицировано из ответа poke53280)
>>> def try_or(fn, exceptions: dict = {}):
try:
return fn()
except Exception as ei:
for e in ei.__class__.__mro__[:-1]:
if e in exceptions: return exceptions[e]()
else:
raise
>>> def context():
return 1 + None
>>> try_or( context, {TypeError: lambda: print('TypeError exception')} )
TypeError exception
>>>
обратите внимание, что если исключение не поддерживается, оно будет повышаться, как и ожидалось:
>>> try_or( context, {ValueError: lambda: print('ValueError exception')} )
Traceback (most recent call last):
File "<pyshell#57>", line 1, in <module>
try_or( context, {ValueError: lambda: print('ValueError exception')} )
File "<pyshell#38>", line 3, in try_or
return fn()
File "<pyshell#56>", line 2, in context
return 1 + None
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>>
также, если дано Exception
, оно будет соответствовать чему-либо ниже.
(BaseException
выше, поэтому он не будет совпадать)
>>> try_or( context, {Exception: lambda: print('exception')} )
exception
Версия ответа poke53280 с ограниченными ожидаемыми исключениями.
def try_or(func, default=None, expected_exc=(Exception,)):
try:
return func()
except expected_exc:
return default
и это может быть использовано как
In [2]: try_or(lambda: 1/2, default=float('nan'))
Out[2]: 0.5
In [3]: try_or(lambda: 1/0, default=float('nan'), expected_exc=(ArithmeticError,))
Out[3]: nan
In [4]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError,))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
[your traceback here]
TypeError: unsupported operand type(s) for /: 'str' and 'int'
In [5]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError, TypeError))
Out[5]: nan