Чи є в python спосіб перетворити спробу / за винятком на один рядок?
щось на зразок...
b = 'some variable'
a = c | b #try statement goes here
Де b
декларована змінна, а c
ні ..., c
то викине помилку і a
стане b
...
Відповіді:
У Python немає можливості стиснути a try
/ except
block в один рядок.
Крім того, погано не знати, чи існує в 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]
тому []
, що false у логічному контексті. Оскільки існує багато значень, які можуть бути хибними, я не використовую or
фокус. (Це та сама проблема, з якою стикаються люди, коли кажуть, if foo:
коли мають на увазі if foo is not None:
.)
try
/ except
block не існує однорядкового синтаксису . На щастя лінії дешеві, тому 4-лінійне рішення має працювати для вас. ;-)
get
якщо не хочете винятку. Використовуйте filter
замість цього.
Це жахливо, але я використовував це підказку, коли хотів написати послідовність дій для налагодження:
exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]
Здебільшого мене взагалі не турбує обмеження, не обмежуючи спроби вибору одного рядка, але коли я просто експериментую, і я хочу, щоб readline відкликав цілий шматок коду відразу в інтерактивному інтерпретаторі, так що я можу це якось відрегулювати, цей маленький фокус стане в нагоді.
Для фактичної мети, яку ви намагаєтесь досягти, ви можете спробувати locals().get('c', b)
; в ідеалі було б краще використовувати справжній словник замість локального контексту, або просто присвоїти c значення None перед тим, як запустити будь-що, що може або не може встановити його.
problem[0]
повернути те , що функція повертає?
У python3 ви можете використовувати contextlib.suppress :
from contextlib import suppress
d = {}
with suppress(KeyError): d['foo']
Інший спосіб - визначити менеджер контексту:
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:
.
Версія відповіді 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
parse_float = lambda x, y=exec("def f(s):\n try:\n return float(s)\n except: return None"): f(x)
Рішення завжди є.
Проблема полягає в тому, що його власне запит 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
і т.д.
Ви можете зробити це шляхом доступу до простору імен Dict з використанням vars()
, locals()
або globals()
, в залежності від того є найбільш придатною для вашої ситуації.
>>> b = 'some variable'
>>> a = vars().get('c', b)
Як щодо використання двох рядків. це нормально?
>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error
якщо вам потрібно насправді керувати винятками:
(змінено з відповіді 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
Працює над Python3, натхненний Вальтером Мундтом
exec("try:some_problematic_thing()\nexcept:pass")
Для багаторядних рядків в один рядок
exec("try:\n\tprint('FirstLineOk')\n\tsome_problematic_thing()\n\tprint('ThirdLineNotTriggerd')\nexcept:pass")
Ps: Exec небезпечно використовувати з даними, над якими ви не маєте контролю.