Python: оператор try в одной строке


есть ли способ в python превратить try / except в одну строку?

что-то вроде...

b = 'some variable'
a = c | b #try statement goes here

здесь b является объявленной переменной и c нет... так что c выдаст ошибку и a станет b...

9 51

9 ответов:

нет никакого способа, чтобы сжать try/except блок на одной строке в Python.

кроме того, плохо не знать, существует ли переменная в Python, как и в некоторых других динамических языках. Более безопасный способ (и преобладающий стиль) - установить все переменные на что-то. Если они не могут быть установлены, установите их в None первый (или 0 или '' или что-то, если это более применимо.)


если вы do присвоить все имена, которые вас интересуют в первую очередь, у вас есть варианты.

  • лучшим вариантом является оператор 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:.)

это ужасно hackish, но я использовал его в приглашении, когда я хотел написать последовательность действий для отладки:

exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]

для реальной цели вы пытаетесь выполнить, вы можете попробовать locals().get('c', b); в идеале было бы лучше использовать реальный словарь вместо локального контекста или просто назначить c None перед запуском того, что может или не может его установить.

вы можете сделать это, обратившись к пространству имен dict с помощью vars(),locals() или globals() в зависимости от того является наиболее подходящим для вашей ситуации.

>>> b = 'some variable'
>>> a = vars().get('c', b)

другой способ-определить контекстный менеджер:

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:.

Вы упомянули, что используете django. Если это имеет смысл для того, что вы делаете, вы можете использовать:

my_instance, created = MyModel.objects.get_or_create()

created будет True или False. Может быть, это вам поможет.

parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)

всегда есть решение.

проблема в том, что его на самом деле модель django.объекты.получить запрос, который я пытаюсь проверить. этот.get возвращает ошибку, если данные не найдены... он не возвращает ни одного (что меня раздражает)

использовать что-то вроде этого:

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 и т. д.

если вам нужно, чтобы на самом деле управлять исключениями:
(изменено из ответа 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 вы можете использовать contextlib.подавить:

from contextlib import suppress

d = {}
with suppress(KeyError): d['foo']