代码之家  ›  专栏  ›  技术社区  ›  Bite code

为什么Exceptions是可迭代的?

  •  13
  • Bite code  · 技术社区  · 17 年前

    我最近被一件意想不到的事咬了。我想做这样的东西:

    try :
         thing.merge(iterable) # this is an iterable so I add it to the list
    except TypeError :
         thing.append(iterable) # this is not iterable, so I add it
    

    好吧,在我传递了一个从Exception继承的对象之前,它一直工作得很好,这个对象应该被添加。

    不幸的是,Exception是可迭代的。以下代码不会引发任何 TypeError :

    for x in Exception() :
        print 1
    

    有人知道为什么吗?

    2 回复  |  直到 3 年前
        1
  •  13
  •   P0k3mòn Brian    5 年前

    请注意,正在发生的事情与任何类型的隐式字符串转换等无关,而是因为 Exception 类实现 __getitem__ 返回args元组中的值( ex.args ).你可以通过这样一个事实来看到这一点,即你得到的是整个字符串作为迭代中的第一个也是唯一一个项目,而不是迭代字符串时得到的逐个字符的结果。

    这也让我感到惊讶,但仔细想想,我猜这是出于向后兼容性的原因。Python用于( pre-1.5 )缺少当前异常的类层次结构。相反,抛出了字符串,并(通常)为应传递给处理块的任何细节提供了一个元组参数,即:

    try:
        raise "something failed", (42, "some other details")
    except "something failed", args:
        errCode, msg = args
        print "something failed.  error code %d: %s" % (errCode, msg)
    

    这种行为似乎是为了避免破坏1.5之前的代码,期望得到一个参数元组,而不是一个不可迭代的异常对象。有几个这样的例子 IOError 在上述致命破损部分 link

    字符串异常已经被弃用了一段时间,在Python 3中已经消失了。异常对象在Python 3中不再可迭代:

    >>> list(Exception("test"))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'Exception' object is not iterable
    
        2
  •  2
  •   Bite code    17 年前

    无效。看看布莱恩·安瑟。

    好的,我刚刚得到它:

    for x in Exception("test") :
        print x
       ....:     
       ....:     
    test
    

    不用麻烦了;-)

    不管怎样,很高兴知道。

    编辑:看到这些评论,我想补充一些解释。

    异常包含您在实例化过程中传递的消息:

    raise Exception("test") 
    
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    Exception: test
    

    公平地说,消息是定义Exception的最佳方式,因此str()返回它:

    print Exception("test") 
    test
    

    现在,当在Exception上下文之外的其他上下文中使用时,Exceptions会隐式转换为字符串。

    所以当我这样做的时候:

    for x in Exception("test") :
        print x
    

    我正在迭代字符串“test”。

    当我这样做的时候:

    for x in Exception() :
        print x
    

    我确实迭代了一个空字符串。很棘手。因为当涉及到我的问题时:

    try :
        thing.merge(ExceptionLikeObject)
    except TypeError :
        ...
    

    这不会引发任何问题,因为ExceptionLikeObject被视为字符串。

    现在,我们知道如何,但我仍然不知道为什么。也许内置的Exception继承自内置的String?因为据我所知:

    • 增加 潜水艇用热中子反应堆 不会使任何对象可迭代。
    • 我通过覆盖来绕过这个问题 国际热核聚变实验堆 ,使其引发TypeError!

    这已经不是问题了,但仍然是个谜。