【问题标题】:How should I put try/except in a single line?Python:在一行中尝试语句
【发布时间】:2011-02-01 06:19:18
【问题描述】:

在 python 中有没有办法将 try/except 变成单行?

类似...

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

其中b 是已声明的变量,而c 不是...所以c 会抛出错误,a 会变成b...

【问题讨论】:

    标签: python exception lines-of-code


    【解决方案1】:

    两行版本对我不起作用。我在 ubuntu 20.04 x64 上使用 VSCode。它只有在我将异常语句移到新行时才有效。尝试可以保持单行。所以至少我需要3行。不知道这是bug还是功能。

    【讨论】:

    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    【解决方案2】:

    在一行中使用with 语法:

    class OK(): __init__ = lambda self, *isok: setattr(self, 'isok', isok); __enter__ = lambda self: None; __exit__ = lambda self, exc_type, exc_value, traceback: (True if not self.isok or issubclass(exc_type, self.isok) else None) if exc_type else None
    

    忽略任何错误:

    with OK(): 1/0
    

    忽略指定的错误:

    with OK(ZeroDivisionError, NameError): 1/0
    

    【讨论】:

      【解决方案3】:

      这是@surendra_ben 提供的答案的更简单版本

      a = "apple"
      ​
      try: a.something_that_definitely_doesnt_exist
      except: print("nope")
      
      ...
      
      nope
      

      【讨论】:

        【解决方案4】:

        使用两条线怎么样。可以吗?

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

        【讨论】:

          【解决方案5】:

          在 Python3 上工作,灵感来自 Walter Mundt

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

          多行合为一行

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

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

          【讨论】:

            【解决方案6】:

            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 逗号将表达式转换为tuple。写(Exception) 等于省略括号。 (Exception, ) 告诉解释器这是一个包含一个条目的元组(类似于列表)。在本例中使用了这个,所以expected_exc 可以是多个例外。
            • 我最喜欢的解决方案!有时我需要在必须知道当前范围内的许多变量的情况下进行日志记录,并且我没有得到堆栈跟踪,并且无法运行步进调试器(例如在远程服务器上)。这使我可以在一行中查看感兴趣的变量,因此我不必执行一堆 if 语句,我可以将这一行与 required_variable = try_or(lambda : var_maybe_not_in_scope, default="none_present")
            【解决方案7】:

            在python3中你可以使用contextlib.suppress:

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

            【讨论】:

            • 这应该是标准答案
            • 这个答案不能解决问题。 suppress 只需在 except: 上执行 pass,这里没有办法处理异常
            • 我们可以在不提供任何异常类型(如KeyError)的情况下使用抑制并将其应用于所有异常吗?
            • @alper 是的,如果你想捕捉像KeyErrorIndexError这样的通用异常,只需使用Exception,但如果你想捕捉SystemExitKeyboardInterruptBaseException GeneratorExit 也一样(你大多不关心)
            • @alper 因为BaseException 还处理KeyboardInterruptSystemExit(使用sys.exit() 时调用的异常)等。处理这些异常将使您无法退出程序除非您使用任务管理器或类似工具强制杀死它。这是一个很好地解释它的视频:youtube.com/watch?v=zrVfY9SuO64
            【解决方案8】:

            如果您需要实际管理异常:
            (修改自 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
            

            【讨论】:

              【解决方案9】:
              parse_float = lambda x, y=exec("def f(s):\n try:\n  return float(s)\n except:  return None"): f(x)
              

              总会有解决办法的。

              【讨论】:

                【解决方案10】:

                问题在于它实际上是我正在尝试测试的 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
                

                您可以选择将接受的异常类型限制为NameErrorAttributeError 等。

                【讨论】:

                • 有趣又不错的方法!建议:lambda 没有意义,只需传递model.objects.get(没有执行呼叫的()),它就会按预期工作
                【解决方案11】:

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

                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:

                【讨论】:

                • 这太棒了!由于没有明确的 try/except,您能否简要解释一下上下文管理器如何处理错误?
                【解决方案12】:

                在 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],因为[] 在布尔上下文中为假。因为有很多值可能是假的,所以我不使用or 技巧。 (这与人们在说if foo: 时遇到的问题相同,而他们的意思是if foo is not None:。)

                【讨论】:

                • 谢谢。问题是它实际上是我正在尝试测试的 django model.objects.get 查询。如果没有找到数据,.get 会返回一个错误......它不会返回 None(这让我很烦恼)
                • @Brant,好的,这种情况与检查是否设置了变量(没有在 Python 中声明变量)有点不同。 Python 的典型风格是更喜欢引发异常而不是将错误作为值返回,我们中的许多人实际上都喜欢这种风格。每次都必须检查操作的返回码,如果我不检查则很难追踪错误,这是我在编写 Python 时绝对不会错过的 C 语言。无论如何,尽管已经讨论过,但try/except 块没有单行语法。幸运的是线路很便宜,所以 4 线路解决方案应该适合您。 ;-)
                • 它是字典中大量元组的一部分...我只是想缩短一点
                • 如果您不想出现异常,请不要使用get。请改用filter
                • @MikeGraham 好的答案 - 提示(链接?)为什么短路容易出错会很好。
                【解决方案13】:

                这非常骇人听闻,但是当我想编写一系列用于调试的操作时,我已经在提示符下使用了它:

                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。

                【讨论】:

                • 嘿,这回答了问题! :)
                • 喜欢这个答案,超级乱,但是一行,就是我喜欢的方式。
                • 这就是答案!! problem[0] 会返回该函数返回的内容吗?
                • Exec 是一种代码异味,应避免使用,除非没有其他方法。如果一行代码如此重要,那么这将起作用,但您需要问自己为什么一行代码如此重要。
                • 显然不是用于生产用途,但正是尴尬的调试会话所需要的。
                【解决方案14】:

                您可以通过使用vars()locals()globals() 访问命名空间字典来做到这一点,以最适合您的情况为准。

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

                【讨论】:

                • 这与检查是否设置了变量并不完全相同(尽管如果您对特定范围感兴趣,它会这样做。)另外,ewwwwwwww.....
                【解决方案15】:

                您提到您正在使用 django。如果它对你正在做的事情有意义,你可能想要使用:

                my_instance, created = MyModel.objects.get_or_create()
                

                created 将是 True 或 False。也许这会对你有所帮助。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2022-01-12
                  • 1970-01-01
                  • 2016-10-02
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-07-30
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多