Python Exception子句中的例外情况如何比较

Python Exception子句中的例外情况如何比较,python,exception,Python,Exception,在以下代码段中: try: raise Bob() except Fred: print "blah" Bob和Fred的比较是如何实现的 从游戏的角度看,它似乎是在呼唤“内在的存在”,这是正确的吗 我这样问是因为我试图颠覆这个过程,特别是我希望能够构造一个Bob,这样它就会被execpt Fred捕获,即使它实际上不是Fred或其任何子类的实例 有几个人问我为什么要这么做 我们有一个RMI系统,它是围绕着尽可能无缝的理念构建的,下面是一个使用中的快速示例,注意RMI系统中没有

在以下代码段中:

try:
    raise Bob()
except Fred:
    print "blah"
Bob和Fred的比较是如何实现的

从游戏的角度看,它似乎是在呼唤“内在的存在”,这是正确的吗

我这样问是因为我试图颠覆这个过程,特别是我希望能够构造一个Bob,这样它就会被execpt Fred捕获,即使它实际上不是Fred或其任何子类的实例

有几个人问我为什么要这么做

我们有一个RMI系统,它是围绕着尽可能无缝的理念构建的,下面是一个使用中的快速示例,注意RMI系统中没有特定于套接字的代码,套接字只是提供了一个方便的示例

import remobj
socket = remobj.RemObj("remote_server_name").getImport("socket")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("", 0))
print "listening on port:", s.getsockname()[1]
s.settimeout(10)
try:
    print "received:", s.recv(2048)
except socket.timeout:
    print "timeout"
现在,在这个特定的示例中,except没有按预期工作,因为引发的对象不是socket.timeout的实例,而是我们的一个代理助手类的实例

我希望能够构造一个Bob 这样它就会被执行者抓住 弗雷德,尽管它实际上不是一个 Fred或其任何 子类

好吧,你可以捕捉“异常”——但这不是很像蟒蛇。您应该尝试捕获正确的异常,然后作为最后手段求助于常规异常(所有异常都是从该异常子类化的)。如果这对您不起作用,那么在您的设计阶段出现了严重错误

注意:请始终指定例外情况 接住。永远不要使用裸句,除非是从句。 除了条款外,其他条款都适用 意外的异常,使您的 代码极难调试

然而,Python禅宗中的一个习语是

特殊情况不足以违反规则。 虽然实用胜过纯洁


我相信您的猜测是正确的,比较是如何进行的,唯一的拦截方法是将Fred添加为Bob的基类。例如:

# Assume both Bob and Fred are derived from Exception
>>> class Bob(Bob, Fred):
...     pass
... 
>>> try:
...     raise Bob()
... except Fred:
...     print 'blah'
blah
据我所知,这是让它像你写的那样工作的唯一方法。但是,如果您只是将except:行重写为

... except (Bob, Fred):
它将捕获Bob和Fred,而不需要修改Bob的定义

>>> class Fred(Exception):
    pass
>>> class Bob(Fred):
    pass
>>> issubclass(Bob, Fred)
True
>>> issubclass(Fred, Bob)
False
>>> try:
    raise Bob()
except Fred:
    print("blah")


blah
因此,基本上捕获了异常,因为Bob是Fred的子类,我假设,要么它们实现了类似于
issubclass(Bob,Fred)

看,这就是你想要实现的方式,无论你想要什么。当然不是在init中,而是在其他方法中

>>> class Bob(Exception):
    def __init__(self):
        raise Fred

>>> try:
    b = Bob()
except Fred:
    print('blah')


blah

至少在CPython中,似乎有一个类型为10(异常匹配)的COMPARE_OP操作。你不可能做任何事情来绕过这个计算

>>> import dis >>> def foo(): ... try: ... raise OSError() ... except Exception, e: ... pass ... >>> dis.dis(foo) 2 0 SETUP_EXCEPT 13 (to 16) 3 3 LOAD_GLOBAL 0 (OSError) 6 CALL_FUNCTION 0 9 RAISE_VARARGS 1 12 POP_BLOCK 13 JUMP_FORWARD 21 (to 37) 4 >> 16 DUP_TOP 17 LOAD_GLOBAL 1 (Exception) 20 COMPARE_OP 10 (exception match) 23 JUMP_IF_FALSE 9 (to 35) 26 POP_TOP 27 POP_TOP 28 STORE_FAST 0 (e) 31 POP_TOP 5 32 JUMP_FORWARD 2 (to 37) >> 35 POP_TOP 36 END_FINALLY >> 37 LOAD_CONST 0 (None) 40 RETURN_VALUE >>>进口dis >>>def foo(): ... 尝试: ... 提高OSError() ... 除例外情况外,e: ... 通过 ... >>>dis.dis(foo) 2 0除13(至16)外的其他设置 3 3加载\u全局0(操作错误) 6调用函数0 9升高值1 12波普卢街区 13向前跳21(到37) 4>>16双陀螺 17加载_全局1(例外) 20比较操作10(例外匹配) 23如果错误则跳转9(到35) 26件流行上衣 27件流行上衣 28商店快速0(e) 31件流行上衣 5 32向前跳2(到37) >>35件流行上衣 36最后结束 >>37负载常数0(无)
40 RETURN_VALUE我不清楚在socket.timeout中隐藏异常是如何符合“无缝”原则的?捕获所定义的预期异常有什么错

try:
    print "received:", s.recv(2048)
except socket.timeout:
    print "timeout"
except our_proxy_helper_class:
    print 'crap!'
或者,如果您真的想将其捕获为socket.timeout,为什么不在我们的\u proxy\u helper\u类中提升socket.timeout呢

raise socket.timeout('Method x timeout')

因此,当您在我们的\u proxy\u helper\u类中引发socket.timeout时,它应该被“except socket.timeout”捕获。

您到底为什么要这么做?-1:颠覆Python的显而易见,明确的功能故意混淆未来的维护者。无缝的意思是本地和远程代码之间唯一明显的区别应该是导入。如果您使用“import socket”在本地导入了套接字,那么您将在socket.timeout上执行此操作,因此理想情况下,您应该在远程导入套接字时执行相同的操作。在示例中,socket.timeout不是一个类。只要你不做任何内省,它看起来和行为都像一门课。但它实际上是另一个代理助手实例。我现在相信这是核心问题,我正在研究元类,作为将其转化为实际类的一种方法。然后,我将能够将异常作为该类的一个实例提出,并且一切都应该按照预期工作。