【问题标题】:Using exceptions from a module without importing it explicitly使用模块中的异常而不显式导入它
【发布时间】:2013-08-02 10:30:12
【问题描述】:

我有一个实用模块utils.py,它使用requests 来执行一些任务。在客户端代码(使用utils)中,我需要处理requests 引发的异常,但我想避免隐式导入requests(即在客户端中)。我怎样才能做到这一点?

utils.py 是(简体)

 import requests

 def download(url):
     # stuff
     return requests.get(url)

我希望client.py 类似于

 import utils  # <-- no "import requests"

 try:
      utils.download(whatever)
 except HTTPError:  # <-- not "requests.exceptions.HTTPError"
      do stuff

except utils.something 也可以。该名称不需要是全局的。我只想避免在客户端的任何地方提及requests

对于那些想知道的人,这只是关注点分离的问题。 client.py 不应该关心 utils.download 的具体实现方式以及它使用的底层底层库。

【问题讨论】:

  • 无论您执行多少import requests 语句,Python 只实际导入一次。您可以通过将print "request has been imported 放入模块范围的请求模块中来验证这一点。它只会打印一次。
  • 那么,您的意思是导入所有 utils.py 而不导入 utils.py 中的某些内容(请求)?
  • @Jblasco:我不希望“请求”一词出现在 client.py 中的任何地方。
  • utils.py 中添加HTTPError = requests.exceptions.HTTPError,然后在client.py 中使用except utils.HTTPError:

标签: python python-2.7 package python-import


【解决方案1】:

简短回答:您不能(或至少不应该)。

当然,没有理由避免导入您想使用的任何内容。这就是 Python 的工作方式,旨在发挥作用,而且效果最好。

如果你真的想分离关注点,让download()捕获异常,并抛出一个新的utils.DownloadError异常。

def download(...):
    try:
        ...
    except HTTPError as e:
        raise DownloadError() from e

编辑:

长答案:您实际上可以通过链式导入异常来做到这一点 - 但我强烈建议不要这样做 - 它只会使代码不那么清晰。

例如:如果你在utils.py 中使用from requests.exceptions import HTTPError,那么你可以import utils 并使用utils.HTTPError

但是,我相信这可能更脆弱 - 更不用说迂回并且更难以跟踪代码中的意图。我仍然强烈建议不要这样做。

从关注点分离的角度来看——它可能会阻止你提及requests,但它仍然依赖于异常,所以它所做的只是隐藏关注点,而不是分离它。

【讨论】:

  • @thg435 答案依旧。
  • @thg435 我撒了一点谎,有办法做到这一点,但这不是一个好办法。
  • @thg435 这只是a little feature added for 3.x,这意味着您可以保留该异常,以便在调试时查看顶级异常的根本原因——这并不重要。只是不要在旧版本中使用 from 部分。显然,您可能希望让新异常携带原始异常携带的一些信息 - 但这完全取决于您的使用情况。
【解决方案2】:

我知道这是一种破旧的做法,但我会做以下两件事之一:

  • 处理 utils.py 中的异常或...
  • 注意 utils.py 中的异常,并在 requests.exceptions.HTTPError 的情况下重新引发 HTTPError

你对这两个中的任何一个都满意吗?

【讨论】:

  • “re-raise”是问题所在——不仅仅是 HTTPError
  • 你要为他们每个人制作一个例外吗?因为如果您要逐个处理所有例外情况,那么无论如何您都会遇到同样的问题,对吗?问题在于您将在哪里处理它们以及您将独立处理其中的多少。
【解决方案3】:

你可以使用utils.requests.exceptions.HTTPError,但你不能避免“提及”requests。你所能做的就是以一种容易出错的迂回方式提及它。

【讨论】:

    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    • 2013-04-05
    • 1970-01-01
    • 2020-02-09
    相关资源
    最近更新 更多