python中的异常传播

python中的异常传播,python,python-3.x,exception-handling,Python,Python 3.x,Exception Handling,我的应用程序使用第三方API,该API引发属于另一个API处理模块的异常。代码如下所示: #API Module def getdatafromapi(req): # Trying to get data ... if response_err in data: raise APIModuleException('API error') if conn_err in data: raise APIConnectionError('API e

我的应用程序使用第三方API,该API引发属于另一个API处理模块的异常。代码如下所示:

#API Module
def getdatafromapi(req):
    # Trying to get data ...
    if response_err in data:
        raise APIModuleException('API error')
    if conn_err in data:
        raise APIConnectionError('API error')

    # Do some processing
    return response
# My Module
def get_data_and_crunch(req):
    response = getdatafromapi(req)
    if not response:
        raise ValueError('Something happened')
    # Proceed to number crunch


# Main script
def main():
    # Sanitize api request...
    try:
        get_data_and_crunch(req)
    except ValueError:
       print('Something happened')

无论发生
apimuleexception
APIConnectionError
时,主模块的行为都是相同的,但我仍然想记录实际导致异常的异常类


是否有一种方法可以避免在我的主脚本中出现
apimuleexception
APIConnectionError
类,并且仍然只使用
ValueError
来传播异常,以告知哪个异常类实际导致了API模块中的异常?

我不确定是否理解正确。但这将是区分例外情况的标准方法:

class APIModuleException(Exception): pass
class APIConnectionError(Exception): pass

def get_data_and_crunch(req):
    # raise ValueError
    raise APIConnectionError
    # raise APIModuleException

def main():
    # Sanitize api request...
    try:
        req = None
        get_data_and_crunch(req)
    except APIModuleException as exc:
        # ...handle
        print('APIModuleException')
    except APIConnectionError as exc:
        # ...handle
        print('APIConnectionError')
    except ValueError as exc:
       # ...handle
       print('ValueError')

main()

确保模块的异常与API的异常类型不完全相同。它可以是一个基本类型,就像您的案例中的
ValueError
一样。在这方面,你的加薪代码很好

添加多个除外的块以捕获不同类型的异常:

try:
    get_data_and_crunch()
except (APIModuleException, APIConnectionError) as e:
    print('API error caught:', str(e))
except ValueError as e:
    print('My module!:', str(e))
除了块之外,您可以拥有任意多的
,并且每个块可以捕获任意多的异常类型

如果API异常继承自
ValueError
,则将
ValueError
捕获放在API异常捕获之后非常重要。使用
instanceof
按顺序计算块,因此如果
ValueError
块先出现,所有异常都会触发它,并且您将永远看不到特定于API的消息

如果您需要了解有关异常的任意特定信息,请使用通过
as…
语法提供的异常对象。该函数还将帮助您获取导致错误的调用顺序等信息。您可以使用该模块获取更多详细信息

更新

根据您最近的评论,您希望在不进行其他导入的情况下获取异常信息免责声明:这在技术上是可行的,我将在下面解释一种方法,但我强烈建议不要使用这种方法

诀窍是捕获所有可能出现的异常的基类,就像您尝试使用
ValueError
一样。问题是,尽管它是使用最广泛的异常类型之一,但它并不是所有异常的基础。你可以过火去抓,但是像按下Ctrl+C这样的操作会停止工作,所以不要这样做(只是为了好玩而提到它)

您可以使用我在上面向您展示的相同符号来获取类型(以及类型的名称)。回溯也将照常工作,以显示调用序列和异常发生的位置:

try:
    get_data_and_crunch()
except Exception as e:
    print('Got a', type(e).__name__)
根据,在深入研究
sys.exc_info
traceback
之前,有几种获取基本异常信息的常用方法
type(e)
将获取抛出错误的类别
str(e)
只返回99%sane异常类中的错误消息
repr(e)
通常会返回打印输出末尾看到的标准
type:message
字符串


作为我的免责声明的免责声明,我必须补充一点,虽然这样的技术不被推荐,但如果您知道自己在做什么,它们可以非常有效地使用。因此,请仔细阅读我链接的文档,确保您完全理解代码。这比注意任何类型的通用非限定警告都重要得多。

apimuleexception继承自什么<代码>值错误
?为什么不在main中
除了apimuleexception
apimuleexception
在这种情况下继承自Base
Exception
类。但我正在寻找一个通用的解决方案,以便在例外情况下传播信息。我意识到我写这个问题的方式似乎有误导性。我刚刚做了一个编辑now@Ajit. 目前还不清楚您要查找的确切信息是什么。有意思的是,以下两种说法似乎不一致:“我不知道哪个异常类实际引发了异常”和“…更好地了解异常的实际来源”。您想知道异常类的来源、引发它的行还是其他什么?请澄清你的术语。“哪个异常类引发异常”是什么意思?“实际源代码”是什么意思?为什么要添加
req=None
?@MadPhysicast我只是想让示例保持独立,而不是更改问题中给出的接口。。。我同意:这有点毫无意义……如果你要做“坏版本”,最好只记录异常的
repr
,它将(对于所有合理的异常)包括类型和消息。@madpysicator。你能详细说明为什么反对第二种方法吗?我试图将API模块的实现细节隐藏在
get\u data\u和\u crunch
后面。对我来说,主模块仅依赖于中间模块使其更加直观sense@Ajit. 这就是为什么我有两个免责声明。一般来说,当函数可能抛出特定异常时,这样做是不好的做法,因为最终可能会无意中使用。然而,在您的情况下,如果异常确实未知,那么您处于最高级别,并且您清楚地了解自己在做什么,这可能没问题。@abarnert。为此,我添加了一个注释,确保完整的异常信息(包括repr打印的类型或任何内容)进入您的(人类可读的,或者至少是ops或dev可读的)日志/寻呼机消息/任何内容,即使您的程序不关心这些信息,也不是一个不常见或太危险的请求,并且这个答案很好地涵盖了它。我认为这看起来很可怕,因为正如之前所写的那样,Ajit改进了这个问题,它听起来像li