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".

所以我最终求助于 typeisinstance 之类的东西。根据我的阅读,显式类型检查似乎在 Python 中被认为是邪恶的,但还能做什么呢?请注意,我几乎从不在我的 Python 中编写 class 层次结构,所以我在子 class 和类型检查方面没有问题,但其他人可能会。

我想到了四个可能的答案,所有这些对我来说似乎都是同样可能的:

  1. 你应该使用异常,但你做错了。像这样做 。 . .
  2. 您应该使用例外。如果错误的类型通过了您的检查,则表明您的设计存在问题(什么问题?)
  3. 你做对了。在这些情况下,显式类型检查更可取。
  4. 你不知道 <python thing for this situation>?做一些研究!

是其中之一,还是其他?

注意 - 我在 SO 上发现了很多关于这个问题的问题,但我正在寻找可以解决这个特定 "genre" 问题的人.

最佳做法是与类型无关。 for 循环会为任何 non-iterable 类型引发异常。文档应该清楚地说明,需要一个可迭代的类型。使用您的函数的函数应该进行单元或集成测试,以便发现意外行为。

类型检查- 您正确地提到类型检查在 Python 中被认为是邪恶的。 我们应该关心一个对象做了什么,而不是它是什么。 例如 - 如果我迭代一个输入,那么我的代码应该适用于所有可迭代对象,我永远不应该检查它的类型。

异常处理 - 让它抛出异常,如果我们尝试处理它,我们要么捕获所有类型的异常,要么错过任何异常。

让我们验证 python built-in 的行为,我们可以遵循相同的 -

  1. 散列(输入) 如果输入不支持哈希,它将抛出异常-

    散列([1,2])

    类型错误:无法散列的类型:'list'

Dictionary 和 Set 都使用 hash() 函数。如果您尝试使用可变键创建字典,它也会抛出相同的异常

{[1,2]:"sample"}
TypeError: unhashable type: 'list'

现在尝试设置

set(([1,2], 5,6))
TypeError: unhashable type: 'list'
  1. 过滤器(function_object, any_iterable)`

    过滤器(布尔值,1245)

    它会抛出 类型错误:'int' 对象不可迭代

    现在对 int 对象应用 iter

    iter(1245)

    TypeError: 'int' 对象不可迭代

因此过滤器在内部使用 iter() 并抛出与从 iter() 获得的异常相同的异常

`