Python:鸭子类型与异常处理
Python: Duck-typing vs. Exception Handling
一个关于 idomatic Python 的问题。假设我有一个函数:
def a_function(list_of_things):
for item in list_of_things:
process_item(item)
现在假设我很难确定输入参数是一个列表。即使是现在,我也能听到甜美的 pythonista 合唱团在恳求我:"Use duck-typing and exceptions!"
def a_function(list_of_things):
try:
for item in list_of_things:
process_item(item)
except:
pass # . . . or something
这很好,除非我传入一个映射、一个字符串或任何其他我认为对这个特定应用程序来说是 "wrong" 的可迭代方式。
我没有写很多 Python,但我设法 运行 进入这个和相关的情况,经常足以让我经常烦恼。更一般地说,我想使用鸭子类型和异常,这似乎是 Python 中的约定,但在很多情况下,可能会得到一个通过我的异常的不正确的输入类型;如此多的异常似乎经常(或至少经常)是错误的答案。
即使异常 do 看起来是正确的答案,我在使用它们时仍然很害怕,因为如果我只是没有想到错误的类型将通过,留下我的代码,因为没有更好的术语,"ducked".
所以我最终求助于 type
和 isinstance
之类的东西。根据我的阅读,显式类型检查似乎在 Python 中被认为是邪恶的,但还能做什么呢?请注意,我几乎从不在我的 Python 中编写 class 层次结构,所以我在子 class 和类型检查方面没有问题,但其他人可能会。
我想到了四个可能的答案,所有这些对我来说似乎都是同样可能的:
- 你应该使用异常,但你做错了。像这样做 。 . .
- 您应该使用例外。如果错误的类型通过了您的检查,则表明您的设计存在问题(什么问题?)
- 你做对了。在这些情况下,显式类型检查更可取。
- 你不知道
<python thing for this situation>
?做一些研究!
是其中之一,还是其他?
注意 - 我在 SO 上发现了很多关于这个问题的问题,但我正在寻找可以解决这个特定 "genre" 问题的人.
最佳做法是与类型无关。 for
循环会为任何 non-iterable 类型引发异常。文档应该清楚地说明,需要一个可迭代的类型。使用您的函数的函数应该进行单元或集成测试,以便发现意外行为。
类型检查-
您正确地提到类型检查在 Python 中被认为是邪恶的。
我们应该关心一个对象做了什么,而不是它是什么。
例如 - 如果我迭代一个输入,那么我的代码应该适用于所有可迭代对象,我永远不应该检查它的类型。
异常处理 -
让它抛出异常,如果我们尝试处理它,我们要么捕获所有类型的异常,要么错过任何异常。
让我们验证 python built-in 的行为,我们可以遵循相同的 -
散列(输入)
如果输入不支持哈希,它将抛出异常-
散列([1,2])
类型错误:无法散列的类型:'list'
Dictionary 和 Set 都使用 hash() 函数。如果您尝试使用可变键创建字典,它也会抛出相同的异常
{[1,2]:"sample"}
TypeError: unhashable type: 'list'
现在尝试设置
set(([1,2], 5,6))
TypeError: unhashable type: 'list'
过滤器(function_object, any_iterable)`
过滤器(布尔值,1245)
它会抛出
类型错误:'int' 对象不可迭代
现在对 int 对象应用 iter
iter(1245)
TypeError: 'int' 对象不可迭代
因此过滤器在内部使用 iter() 并抛出与从 iter() 获得的异常相同的异常
`
一个关于 idomatic Python 的问题。假设我有一个函数:
def a_function(list_of_things):
for item in list_of_things:
process_item(item)
现在假设我很难确定输入参数是一个列表。即使是现在,我也能听到甜美的 pythonista 合唱团在恳求我:"Use duck-typing and exceptions!"
def a_function(list_of_things):
try:
for item in list_of_things:
process_item(item)
except:
pass # . . . or something
这很好,除非我传入一个映射、一个字符串或任何其他我认为对这个特定应用程序来说是 "wrong" 的可迭代方式。
我没有写很多 Python,但我设法 运行 进入这个和相关的情况,经常足以让我经常烦恼。更一般地说,我想使用鸭子类型和异常,这似乎是 Python 中的约定,但在很多情况下,可能会得到一个通过我的异常的不正确的输入类型;如此多的异常似乎经常(或至少经常)是错误的答案。
即使异常 do 看起来是正确的答案,我在使用它们时仍然很害怕,因为如果我只是没有想到错误的类型将通过,留下我的代码,因为没有更好的术语,"ducked".
所以我最终求助于 type
和 isinstance
之类的东西。根据我的阅读,显式类型检查似乎在 Python 中被认为是邪恶的,但还能做什么呢?请注意,我几乎从不在我的 Python 中编写 class 层次结构,所以我在子 class 和类型检查方面没有问题,但其他人可能会。
我想到了四个可能的答案,所有这些对我来说似乎都是同样可能的:
- 你应该使用异常,但你做错了。像这样做 。 . .
- 您应该使用例外。如果错误的类型通过了您的检查,则表明您的设计存在问题(什么问题?)
- 你做对了。在这些情况下,显式类型检查更可取。
- 你不知道
<python thing for this situation>
?做一些研究!
是其中之一,还是其他?
注意 - 我在 SO 上发现了很多关于这个问题的问题,但我正在寻找可以解决这个特定 "genre" 问题的人.
最佳做法是与类型无关。 for
循环会为任何 non-iterable 类型引发异常。文档应该清楚地说明,需要一个可迭代的类型。使用您的函数的函数应该进行单元或集成测试,以便发现意外行为。
类型检查- 您正确地提到类型检查在 Python 中被认为是邪恶的。 我们应该关心一个对象做了什么,而不是它是什么。 例如 - 如果我迭代一个输入,那么我的代码应该适用于所有可迭代对象,我永远不应该检查它的类型。
异常处理 - 让它抛出异常,如果我们尝试处理它,我们要么捕获所有类型的异常,要么错过任何异常。
让我们验证 python built-in 的行为,我们可以遵循相同的 -
散列(输入) 如果输入不支持哈希,它将抛出异常-
散列([1,2])
类型错误:无法散列的类型:'list'
Dictionary 和 Set 都使用 hash() 函数。如果您尝试使用可变键创建字典,它也会抛出相同的异常
{[1,2]:"sample"}
TypeError: unhashable type: 'list'
现在尝试设置
set(([1,2], 5,6))
TypeError: unhashable type: 'list'
过滤器(function_object, any_iterable)`
过滤器(布尔值,1245)
它会抛出 类型错误:'int' 对象不可迭代
现在对 int 对象应用 iter
iter(1245)
TypeError: 'int' 对象不可迭代
因此过滤器在内部使用 iter() 并抛出与从 iter() 获得的异常相同的异常
`