【问题标题】:Raise exception in python dict.get()在 python dict.get() 中引发异常
【发布时间】:2019-07-15 09:30:05
【问题描述】:

实际上,我已经知道我想做的事情有点奇怪,但我认为它很适合我的代码,所以我问:

有没有办法做这样的事情:

foo = { 'a':1, 'b':2, 'c':3 }
bar = { 'd':4, 'f':5, 'g':6 }

foo.get('h', bar.get('h'))

引发异常而不是None,以防 dict.get() '失败'?

foo.get('h', bar.get('h', raise)) 将提高 SyntaxError

foo.get('h', bar.get('h', Exception)) 只会返回 Exception

目前我只是在使用if not foo.get('h', bar.get('h')): raise Exception,但如果有办法直接在dict.get() 中加注,我会非常高兴。

谢谢

【问题讨论】:

  • 你可以继承 dict 并让 get 做你想做的事
  • 不要使用get(),因为它会为您捕获 IndexError。如果你真的想要 IndexError,只需使用 foo['h']
  • “只使用括号”的答案是正确的,但这里有一个解释为什么:stackoverflow.com/a/11041421/769971 另外,我保证在以后的路上.get() 函数将对您有用。你也应该学习如何使用它。
  • 没错,我知道为什么使用.get(),我只是想在找不到密钥而不是None时引发异常,而不必使用条件

标签: python dictionary exception-handling


【解决方案1】:

你可以做一些断言魔法:

foo = { 'a':1, 'b':2, 'c':3 }
bar = { 'd':4, 'f':5, 'g':6 }

assert foo.get('h', bar.get('h')), 'value "h" did not exist in dicts!'

Foo 尝试选择键“h”的值,如果这些值都没有返回任何有意义的值,则回退到选择键“h”的值,则返回最里面的 get 调用的默认值,在这种情况下为 None。 None 会触发断言。

之所以有效,是因为可以测试任何对象的真值,例如 None 等常量。 https://docs.python.org/3/library/stdtypes.html#truth-value-testing

您还可以获得自定义错误消息的额外好处。

对于 Python 3.8 +,您可以将其与一些海象魔法结合使用:

assert (myVariable := foo.get('h', bar.get('h'))), 'value "h" did not exist in dicts!'
# if value of key "h" was found from any of the dicts, it is now assigned to the variable myVariable.

【讨论】:

    【解决方案2】:

    如果你想在 get 中引发错误,你可以这样欺骗:

    {"a":4}.get("b", exec("raise Exception('some error msg') "))
    

    此外,如果您想避免拼写错误,请使用 f-strings。

    【讨论】:

      【解决方案3】:

      可以使用容器ChainMap,将两个字典封装成一个:

      from collections import ChainMap
      
      foo = { 'a':1, 'b':2, 'c':3 }
      bar = { 'd':4, 'f':5, 'g':6 }
      
      ChainMap(foo, bar)['h']
      

      【讨论】:

      • 抱歉,这可能是一个愚蠢的问题 - 这如何引发所需的异常,而不是仅仅从其他地方检索值?
      • @VincentBuscarello 如果值 h 不在链式字典中,则会出现 KeyError 异常。
      【解决方案4】:

      既然你已经有了一些好的答案,我会给你 boondoggle 答案作为学习...的东西。

      class MyDict(dict):
          def get(self, key, default=None, error=None):
              res = super().get(key,default)
              if res is None:
                  if error == 'raise':
                      raise SyntaxError()
                  elif error == 'Exception':
                      return SyntaxError()
              return res
      

      现在你可以这样做了:

      foo = MyDict({ 'a':1, 'b':2, 'c':3 })
      bar = MyDict({ 'd':4, 'f':5, 'g':6 })
      foo.get('h', bar.get('h', error="Exception")) #  returns a syntaxerror object
      foo.get('h', bar.get('h', error="raise"))  # raises a syntax error
      

      super() 允许您访问超类的成员,这样您就可以拥有自己的get,同时仍然在内部使用父级get

      【讨论】:

      • "我会给你一个愚蠢的答案" 看来你有一些竞争。 ?
      • @TrebuchetMS 当我开始写这篇文章时,没有那么多疯狂的答案
      【解决方案5】:

      您可以使用魔术功能为您的 dict 自定义类:

      class GetAndRaise:
          def __init__(self):
              self.dict = dict()
          def __getitem__(self, key):
              try:
                  return self.dict[key]
              except ValueError:
                  raise MyException
          def __setitem__(self, key, value):
              self.dict[key] = value
          def get(self, key):
              return self[key]
      

      【讨论】:

      • 我不能容忍这个......请不要这样做,因为他正在寻找的功能已经在 dict 类中。
      【解决方案6】:

      使用下标,这是默认行为:

      d={}
      d['unknown key'] --> Raises a KeyError
      

      如果你想抛出一个自定义异常,你可以这样做:

      try:
          d['unknown key']
      except KeyError:
          raise CustomException('Custom message')
      

      并包含来自 KeyError 的堆栈跟踪:

      try:
          d['unknown key']
      except KeyError as e:
          raise CustomException('Custom message') from e
      

      【讨论】:

      • 谢谢。我已经知道这一点,我想使用 .get() 这样我就不必使用条件,但最后看来我还是不得不使用
      【解决方案7】:

      你可以这样做:

      class MyException(Exception):
          pass
      
      
      try:
          value = dict['h']
      except KeyError:
          raise MyException('my message')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-04
        • 2021-10-28
        • 1970-01-01
        • 2019-03-02
        • 1970-01-01
        • 1970-01-01
        • 2016-12-15
        • 1970-01-01
        相关资源
        最近更新 更多