Python:Duck类型与异常处理

Python:Duck类型与异常处理,python,types,exception-handling,duck-typing,Python,Types,Exception Handling,Duck Typing,关于idomatic Python的问题。假设我有一个函数: def a_function(list_of_things): for item in list_of_things: process_item(item) 现在假设我很难确定输入参数是一个列表。即使是现在,我也能听到甜美的蟒蛇合唱团哀求我:“使用鸭子打字和例外!” 这很好,除非我传入一个映射,或者字符串,或者其他任何我认为对于这个特定应用程序是“错误的”可移植的东西 我不太会写Python,但我经常遇到这种

关于idomatic Python的问题。假设我有一个函数:

def a_function(list_of_things):
    for item in list_of_things:
        process_item(item)
现在假设我很难确定输入参数是一个列表。即使是现在,我也能听到甜美的蟒蛇合唱团哀求我:“使用鸭子打字和例外!”

这很好,除非我传入一个映射,或者字符串,或者其他任何我认为对于这个特定应用程序是“错误的”可移植的东西

我不太会写Python,但我经常遇到这种情况和相关的情况,经常让我感到烦恼。更一般地说,我想使用duck类型和异常,这似乎是Python中的惯例,但是在很多情况下,获得通过我的异常的错误输入类型是可能的;如此之多的例外看起来像是错误的答案(或者至少经常是错误的)

即使异常看起来确实是正确的答案,但当我使用它们时,我仍然感到害怕,因为如果我没有想到坏类型将通过的极端情况,因为缺少更好的术语而留下我的代码,“躲闪”会怎样

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

我想到了四个可能的答案,在我看来,所有这些答案都是同样可能的:

  • 你应该使用异常,但你做得不对。像这样做
  • 您应该使用异常。如果坏类型通过了检查,则表明设计中存在一些问题(什么问题?)
  • 你做得对。在这些情况下,显式类型检查更可取
  • 你不知道
    ?做些调查 这是其中一个,还是别的什么


    注意-我发现了很多问题,因此在这个问题上绕圈子,但我正在寻找人们,如果可能的话,他们可以针对这个问题的特定“类型”发表意见。

    最好的做法是,不分类型。
    -for的
    循环会引发任何不可iterable类型的异常。文档应明确说明,需要iterable类型。使用函数的函数应该进行单元或集成测试,以便发现意外行为

    类型检查- 您正确地提到类型检查在Python中被认为是有害的。 我们应该关心一个物体做什么,而不是它是什么。 e、 如果我对输入进行迭代,那么我的代码应该适用于所有iterable,并且我不应该检查它的类型

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

    让我们验证python内置的行为,我们可以遵循相同的原则-

  • 散列(输入) 如果输入不可哈希,它将抛出异常-

    散列([1,2])

    TypeError:不可损坏的类型:“列表”

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

    {[1,2]:"sample"}
    TypeError: unhashable type: 'list'
    
    现在试试set

    set(([1,2], 5,6))
    TypeError: unhashable type: 'list'
    
  • 过滤器(函数\对象,任意\可选项)`

    过滤器(布尔,1245)

    它会扔 TypeError:“int”对象不可编辑

    现在在int对象上应用iter

    国际热核实验堆(1245)

    TypeError:“int”对象不可编辑

  • 所以过滤器内部使用iter()并抛出它从iter()得到的相同异常


    `

    为什么地图、字符串或其他可编辑项会“错误地”可编辑?您的示例函数只依赖于可移植性。无论如何,如果你需要一个序列,你可以在Python3中尝试
    isinstance(collections.sequence)
    ,或者
    isinstance(collections.abc.sequence)
    ,但是通常的方法是假设调用者做了正确的事情,并依靠单元测试来确保你的代码工作。只需检查,如果一个错误的类型导致一个错误但有效的答案(如果您想要一个单字符序列,字符串是有效的参数)。其他事情由打电话的人决定。“bug”并不是无声的,因为您需要进行测试,以检查结果是否正确。这只是一个示例,还有其他情况,例如
    add
    -多么模糊的函数名,看起来您可以对集合进行数学运算…当使用duck键入时。。。不要使用异常来尝试保存调用方。您编写了一个处理序列的函数,并使用列表对其进行了大量测试。如果用户传递的其他内容没有按您认为应该的方式工作,则由调用者负责。如果你的代码因为一个时髦的数据类型而崩溃。。。这也是来电者的责任。如果它像鸭子一样呱呱叫,但结果却是大象。。。这就是大象的问题。在高风险的环境中,在知道您已经消除了代码的一些可能用途的情况下进行大量类型检查是有意义的。所以,当你遭遇恐怖袭击时,赶快离开!对我来说,我的较低数据层倾向于偏执,但举例来说,不是
    isinstance(x,int)
    I
    int(x)
    ,而是让异常飞起来。而且,调用方应该一直在测试代码(并读取所调用函数的文档)。。。你只要决定谁穿大男孩的裤子就行了。
    set(([1,2], 5,6))
    TypeError: unhashable type: 'list'