【问题标题】:Is there a neater alternative to `except: pass`?有没有比“除了:通过”更简洁的替代方法?
【发布时间】:2010-09-16 02:28:45
【问题描述】:

我有一个函数,它按优先顺序返回几个组的随机成员。它是这样的:

def get_random_foo_or_bar():
    "I'd rather have a foo than a bar."

    if there_are_foos():
        return get_random_foo()

    if there_are_bars():
        return get_random_bar()

    raise IndexError, "No foos, no bars"

但是,get_random_foo 所做的第一件事是验证是否存在 foo,如果没有,则提出 IndexError,因此 there_are_foos 是多余的。此外,涉及数据库并且使用单独的函数会产生并发问题。因此,我将其重写为:

def get_random_foo_or_bar():
    "Still prefer foos."

    try:
        return get_random_foo()
    except IndexError:
        pass

    try:
        return get_random_bar()
    except IndexError:
        pass

    raise IndexError, "No foos, no bars"

但我发现它的可读性要差得多,而且我从来没有理由使用 pass,然后才会觉得它本能地错了。

有没有更简洁有效的模式,还是我应该学会接受pass

注意:我想避免任何嵌套,因为以后可能会添加其他类型。


编辑

感谢所有说pass 很好的人——这让人放心!

还要感谢那些建议将异常替换为返回值None 的人。我可以看到这是一个有用的模式,但我认为在这种情况下它在语义上是错误的:函数被要求执行不可能的任务,因此它们应该引发异常。我更喜欢遵循random 模块的行为(例如random.choice([]))。

【问题讨论】:

  • except 语句中的使用可能是 Python 中pass 最常见的使用。所以我会习惯的。
  • “但我发现这不太可读……感觉本能地错误”——把它当作一个文化问题。现在看起来很奇怪,但这是使用该语言的最简洁的方式。

标签: python exception-handling coding-style


【解决方案1】:

我就是这样写的。这很简单,也很有意义。我认为pass 语句没有问题。

如果您想减少重复并希望添加未来的类型,您可以将其汇总到一个循环中。然后,您可以将 pass 更改为功能等效的 continue 语句,如果这更令人赏心悦目:

for getter in (get_random_foo, get_random_bar):
    try:
        return getter()
    except IndexError:
        continue  # Ignore the exception and try the next type.

raise IndexError, "No foos, no bars"

【讨论】:

    【解决方案2】:

    使用 try, except, pass 是可以接受的,但是有一种更简洁的方法可以使用 contextlib.suppress() 编写此代码,可用于 python 3.4+。

    from contextlib import suppress
    
    def get_random_foo_or_bar():
        "Still prefer foos."
    
        with suppress(IndexError):
            return get_random_foo()
    
        with suppress(IndexError):
            return get_random_bar()
    
        raise IndexError("No foos, no bars")
    

    【讨论】:

      【解决方案3】:

      pass 很好(有一个原因它在语言中!-),但无传递替代方案只需要更多的嵌套:

      try: return get_random_foo()
      except IndexError:
          try: return get_random_bar()
          except IndexError:
              raise IndexError "no foos, no bars"
      

      Python 的 Zen(来自交互式解释器提示符的import this)说“扁平比嵌套更好”,但嵌套在语言中也是,供您在决定时使用(大概是被启发了) ) 你可以比那个聪明的公案做得更好!-) (如,“如果你在路上遇到佛陀”......)。

      【讨论】:

        【解决方案4】:

        get_random_foo() 在不将索引作为参数时引发 IndexError 对我来说有点奇怪(但在上下文中可能更有意义)。为什么不使用 get_random_foo() 或包装器来捕获错误并返回 None 呢?

        def get_random_foo_wrapper():
            try:
                return get_random_foo()
            except IndexError:
                return None
        
        def get_random_foo_or_bar():
            "I'd rather have a foo than a bar."
        
            return get_random_foo_wrapper() or get_random_bar_wrapper() or None
        

        编辑:我应该提到,如果 foo & bar 是可能评估为 False(0 或 '' 说)的对象,那么 or 比较将跳过它们,这是不好的

        【讨论】:

        • 我从随机模块中得到了启发 - 尝试运行 random.choice([])。有趣的解决方案,谢谢!
        【解决方案5】:

        如果只是那两个,总是可以...

        try:
            return get_random_foo()
        except IndexError:
            try:
                return get_random_bar()
            except IndexError:
                raise IndexError, "No foos, no bars"
        

        如果超过两个,你写的似乎完全可以接受。

        【讨论】:

          【解决方案6】:

          根据 Peter Gibson 的建议,您可以创建一个通用包装函数来吞下给定的异常。然后,您可以编写一个函数,返回这样的通用包装器,用于提供的异常。或者见鬼,对于提供的 list 异常。

          def maketrap(*exceptions):
              def trap(func, *args, **kwargs):
                  try:
                      return func(*args, **kwargs)
                  except exceptions:
                      return None
              return trap
          
          def get_random_foo_or_bar():
              mytrap = maketrap(IndexError)
              return mytrap(get_random_foo) or mytrap(get_random_bar) or None
          

          【讨论】:

            【解决方案7】:

            如果您真的不需要异常消息(只需要类型):

            def get_random_foo_or_bar():
                try:
                    return get_random_foo()
                except IndexError:
                    return get_random_bar()    # if failing at this point,
                                               # the whole function will raise IndexError
            

            【讨论】:

            • 我想我更愿意从get_random_foo_or_bar 明确提出错误,而不是依赖于错误发生相同并需要评论。这也让我可以从get_random_foo_or_bar 返回适当的异常消息。
            【解决方案8】:

            如果 get_random_foo/bar() 无法成功,是否有必要引发 IndexError?

            如果他们返回 None,你可以这样做:

            def get_random_foo_or_bar():
                return get_random_foo() or get_random_bar()
            

            【讨论】:

              猜你喜欢
              • 2012-06-30
              • 1970-01-01
              • 1970-01-01
              • 2012-04-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-04-09
              • 1970-01-01
              相关资源
              最近更新 更多