Python 例外准则解释
Python Exception guidelines explanation
在 Google 的 python 样式指南文档中,他们提到了以下内容:
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.
为什么不合适?这是否意味着首先不应像这样使用 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
ConnectionError
可能是根据记录的用法使用该函数的结果。
然而,ValueError
只是公然违反函数前提条件的结果。您已被警告 minimum >= 1024
必须为真。您不需要记录违反该警告的后果。
例如,您不需要 try
语句来处理 ValueError
;您可以在调用函数之前检查参数的值以避免它。 (在这种情况下,请求宽恕比获得许可不容易。)
您确实需要 try
语句来处理 ConnectionError
,因为无法预测它可能会发生。为了知道可能会引发 ConnectionError
,需要对其进行记录。
从具有静态类型检查的整体语言的角度来看,区别在于您可以通过使用适当的 argument 类型来避免的错误,以及您可以通过使用来避免的错误适当的 return 类型。考虑 Haskell 类伪代码中的部分函数。
type ValidPort = Int
connect_to_next_port :: ValidPort -> ValidPort
connect_to_next_port = ...
但并非所有 Int
都是有效端口;只有 1024 和 65535 之间的整数(TCP/IP 中的端口是 16 位值)。所以想象我们有一种方法来定义受限类型,我们可以用
消除 ValueError
type ValidPort = { x :: Int | 1024 <= x <= 65535 }
connect_to_next_port :: ValidPort -> ValidPort
connect_to_next_port = ...
但我们可能找不到 return 的端口。我们没有引发异常,而是 return 类型 Maybe ValidPort
的东西,您可以将其视为包含类型 ValidPort
和值 None
的包装器(大致对应于Haskell中的Nothing
).
type ValidPort = { x :: Int | 1024 <= x <= 65535 }
connect_to_next_port :: ValidPort -> Maybe ValidPort
connect_to_next_port = ...
总而言之,我们记录了可以编码为 return 类型的异常,而不是可以用适当的参数类型消除的异常。
在 Google 的 python 样式指南文档中,他们提到了以下内容:
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.
为什么不合适?这是否意味着首先不应像这样使用 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
ConnectionError
可能是根据记录的用法使用该函数的结果。
然而,ValueError
只是公然违反函数前提条件的结果。您已被警告 minimum >= 1024
必须为真。您不需要记录违反该警告的后果。
例如,您不需要 try
语句来处理 ValueError
;您可以在调用函数之前检查参数的值以避免它。 (在这种情况下,请求宽恕比获得许可不容易。)
您确实需要 try
语句来处理 ConnectionError
,因为无法预测它可能会发生。为了知道可能会引发 ConnectionError
,需要对其进行记录。
从具有静态类型检查的整体语言的角度来看,区别在于您可以通过使用适当的 argument 类型来避免的错误,以及您可以通过使用来避免的错误适当的 return 类型。考虑 Haskell 类伪代码中的部分函数。
type ValidPort = Int
connect_to_next_port :: ValidPort -> ValidPort
connect_to_next_port = ...
但并非所有 Int
都是有效端口;只有 1024 和 65535 之间的整数(TCP/IP 中的端口是 16 位值)。所以想象我们有一种方法来定义受限类型,我们可以用
ValueError
type ValidPort = { x :: Int | 1024 <= x <= 65535 }
connect_to_next_port :: ValidPort -> ValidPort
connect_to_next_port = ...
但我们可能找不到 return 的端口。我们没有引发异常,而是 return 类型 Maybe ValidPort
的东西,您可以将其视为包含类型 ValidPort
和值 None
的包装器(大致对应于Haskell中的Nothing
).
type ValidPort = { x :: Int | 1024 <= x <= 65535 }
connect_to_next_port :: ValidPort -> Maybe ValidPort
connect_to_next_port = ...
总而言之,我们记录了可以编码为 return 类型的异常,而不是可以用适当的参数类型消除的异常。