首页 > 解决方案 > Python 异常指南解释

问题描述

在 Google 的 python 样式指南文档中,他们提到了以下内容:

请注意,在文档字符串的“引发:”部分中没有提到 ValueError 的引发,因为不适合保证对 API 滥用的这种特定行为反应。

为什么不合适?这是否意味着首先不应该像这样使用 ValueError ?

def connect_to_next_port(self, minimum: int) -> int:
"""Connects to the next available port.

Args:
  minimum: A port value greater or equal to 1024.

Returns:
  The new minimum port.

Raises:
  ConnectionError: If no available port is found.
"""
if minimum < 1024:
  # Note that this raising of ValueError is not mentioned in the doc
  # string's "Raises:" section because it is not appropriate to
  # guarantee this specific behavioral reaction to API misuse.
  raise ValueError(f'Min. port must be at least 1024, not {minimum}.')
port = self._find_next_open_port(minimum)
if not port:
  raise ConnectionError(
      f'Could not connect to service on port {minimum} or higher.')
assert port >= minimum, (
    f'Unexpected port {port} when minimum was {minimum}.')
return port

标签: pythonexception

解决方案


ConnectionError可以是根据其记录的用法使用该函数的结果。

然而ValueError, 只是公然违反函数的先决条件的结果。你已经被警告过,这minimum >= 1024一定是真的。您不需要记录违反该警告的后果。

例如,您不需要try语句来处理ValueError; 您可以在调用函数之前检查参数的值以避免它。(在这种情况下,请求宽恕并不比允许更容易。)

您确实需要一个try语句来处理ConnectionError,因为无法预测它可能会发生。为了知道ConnectionError可能会提出 a,这需要记录在案。


从具有静态类型检查的总体语言的角度来看,区别在于您可以通过使用适当的参数类型来避免错误,而您可以通过使用适当的返回类型来避免错误。考虑类似 Haskell 的伪代码中的偏函数。

type ValidPort = Int
connect_to_next_port :: ValidPort -> ValidPort
connect_to_next_port = ...

但不仅仅是 anyInt是有效的端口。只有 1024 到 65535 之间的整数(TCP/IP 中的端口是 16 位值)。所以想象我们有一种方法来定义一个受限类型,我们可以消除ValueErrorwith

type ValidPort = { x :: Int | 1024 <= x <= 65535 }
connect_to_next_port :: ValidPort -> ValidPort
connect_to_next_port = ...

但我们可能找不到返回的港口。我们没有引发异常,而是返回 type 的东西Maybe ValidPort,您可以将其视为包含 type 值ValidPort和 value的包装器None(大致对应Nothing于 Haskell 中的值)。

type ValidPort = { x :: Int | 1024 <= x <= 65535 }
connect_to_next_port :: ValidPort -> Maybe ValidPort
connect_to_next_port = ...

也就是说,我们记录了可以编码为返回类型的异常,而不是可以通过适当的参数类型消除的异常。


推荐阅读