我该如何将try/except语句放在一行中?

140

在Python中,有没有一种方法可以将try/except转换为单行代码?

类似于...

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

b 是一个声明的变量而 c 不是时...所以 c 会抛出一个错误,a 将变成 b...

18个回答

120

在Python 3中,您可以使用contextlib.suppress

from contextlib import suppress

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

18
这应该是标准答案。 - Sphynx-HenryAY
6
这个答案并没有解决这个问题。suppress 只是在 except: 上执行了 pass,无法处理异常。 - rzlvmp
1
我们能否在使用 suppress 的时候不指定任何异常类型,而是将其应用于所有异常? - alper
2
@alper 是的,如果你想捕获像 KeyErrorIndexError 这样的通用异常,只需使用 Exception。但是如果你还想捕获 SystemExitKeyboardInterruptGeneratorExit 这些异常(这些异常大多数情况下并不重要),则需要使用 BaseException - LMCuber
3
@alper 因为 BaseException 也处理 KeyboardInterruptSystemExit(在使用 sys.exit() 时调用的异常)等。 处理这些异常将使您无法退出程序,除非您使用任务管理器或类似工具强制终止它。 这是一个非常好的解释视频:https://www.youtube.com/watch?v=zrVfY9SuO64 - Lysander12 PT
显示剩余5条评论

95

这个方法非常hackish,但是我在提示符时使用它来编写调试的一系列操作:

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

大多数情况下,我并不受到 no-single-line-try-except 限制的影响,但当我仅仅是在尝试实验性代码时,我想要readline一次性回忆起整个代码块,以便我可以进行一些调整,这个小技巧就派上用场了。

对于你想要实现的实际目的,你可以尝试 locals().get('c', b);理想情况下最好使用真正的字典而不是本地上下文,或者在运行可能设置它的任何内容之前将c赋值为None。


34
嘿,这回答了问题! :) - Steve Bennett
5
喜欢这个回答,虽然有些混乱,但只有一行,这正是我喜欢的方式。 - Patrick Cook
这就是答案!!problem[0]会返回该函数的返回值吗? - SIslam
5
Exec 是代码异味,除非没有其他方法,否则应该避免使用。如果一行代码非常重要,那么使用它是可行的,但是你需要问自己为什么这一行如此重要。 - Gewthen
6
显然不适用于生产环境,但却是解决棘手调试问题所需的工具。 - ThorSummoner

78

在Python中,无法将try/except块压缩到一行中。

此外,在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。由于有很多值可以表示 false,所以我不使用 or 技巧。(当人们说 if foo: 时实际上是想表达 if foo is not None:,这也是他们经常遇到的同样问题。)

    谢谢。问题在于我正在尝试测试一个Django model.objects.get查询。如果没有找到数据,.get会返回一个错误...它不会返回None(这让我很烦恼)。 - Brant
    @Brant,好的,这种情况与检查变量是否设置(在Python中没有声明变量)有些不同。Python中的典型风格是优先使用引发异常而不是返回错误值,这是我们许多人喜欢的。每次都必须检查操作的返回代码并且如果不这样做很难跟踪错误,这是我在写Python时绝对不会想念C语言的一件事情。无论如何,虽然已经讨论过,但目前没有 try/except 代码块的单行语法。幸运的是,代码行数不大,所以4行解决方案应该适合你。;-) - Mike Graham
    它是字典中一个大元组集合的一部分... 我只是想把事情简化一点。 - Brant
    2
    如果你不想要异常,就不要使用 get 方法,而应该使用 filter 方法。 - jcdyer
    @MikeGraham 很好的回答 - 提供一些提示(链接?)为什么短路计算容易出错会更好。 - kratenko
    显示剩余2条评论

    26

    有限预期异常情况下的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
    

    "expected_exc=(Exception,)" 中的逗号是用来干什么的?你能解释一下吗?" - ibilgen
    2
    逗号将表达式转换为tuple。写成(Exception)等同于省略括号。(Exception, )告诉解释器这是一个带有一个条目的元组(类似于列表)。在这个例子中,这是用来使expected_exc可以是多个异常。 - miile7
    1
    我最喜欢的解决方案!有时候我需要记录日志,以便了解当前作用域中的多个变量,但我没有堆栈跟踪,并且无法运行步骤调试器(例如在远程服务器上)。这使我可以在一行中查看感兴趣的变量,因此我不必做很多if语句,我只需使用这一行代码:needed_variable = try_or(lambda : var_maybe_not_in_scope, default="none_present")。 - Jonathan Ma

    22

    另一种方法是定义一个上下文管理器:

    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
    

    在运行时错误发生时不会引发任何异常。这就像一个没有except:try:


    3
    太好了!既然没有显式的try/except,你能简要解释一下上下文管理器如何处理错误吗? - Patrick
    1
    @Patrick 请查看 https://dev59.com/slsW5IYBdhLWcg3wCTaB#35483461,了解如何从 __exit__ 中返回 True 来抑制错误。 - jnnnnn

    14
    问题在于实际上我正在尝试测试一个Django model.objects.get查询。如果找不到数据,.get会返回一个错误...它不会返回None(这让我很烦恼) 使用类似以下的内容:
    print("result:", try_or(lambda: model.objects.get(), '<n/a>'))
    

    where try_or 是由您定义的实用程序函数:

    def try_or(fn, default):
        try:
            return fn()
        except:
            return default
    

    你可以选择限制接受的异常类型,例如 NameErrorAttributeError等。


    2
    有趣而且不错的方法!建议:lambda 是无意义的,只需传递 model.objects.get(不带执行调用的 ())即可按预期工作。 - MestreLion

    13

    使用两行行不行?

    >>> try: a = 3; b= 0; c = a / b
    ... except : print('not possible'); print('zero division error')
    ...
    not possible
    zero division error
    

    9

    基于Python3实现,灵感来自Walter Mundt的作品。

    exec("try:some_problematic_thing()\nexcept:pass")
    

    将多行合并为一行

    exec("try:\n\tprint('FirstLineOk')\n\tsome_problematic_thing()\n\tprint('ThirdLineNotTriggerd')\nexcept:pass")
    

    提示: 在您无法控制的数据上使用 Exec 是不安全的。


    1
    不错。我用这个来检查 Python 模块:python -c 'exec("try:import build\nexcept: exit(1)")' - Jonathan Komar

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

    总有解决办法。


    使用exec - undefined

    4

    您可以通过访问命名空间字典,使用vars()locals()globals()来实现。根据您的情况选择最合适的方法。

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

    4
    这个与检查一个变量是否设置的方法不完全相同(尽管如果你只关心特定范围,它也是有效的)。此外,啊啊啊啊啊...... - Mike Graham

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接