可选的静态类型对Python API设计是有利还是不利?(包括类型检查装饰器示例)

可选的静态类型对Python API设计是有利还是不利?(包括类型检查装饰器示例),python,static-typing,Python,Static Typing,我是一名长期的Python开发人员,我非常喜欢这种语言的动态特性,但我想知道Python是否会从可选的静态类型中受益。 将静态类型应用于库的API是否有益,其缺点是什么? 我快速绘制了一个实现运行时静态类型检查的装饰器,其工作原理如下: # A TypeError will be thrown if the argument "string" is not a "str" and if # the returned value is not an "int" @typed(int, strin

我是一名长期的Python开发人员,我非常喜欢这种语言的动态特性,但我想知道Python是否会从可选的静态类型中受益。 将静态类型应用于库的API是否有益,其缺点是什么?

我快速绘制了一个实现运行时静态类型检查的装饰器,其工作原理如下:

# A TypeError will be thrown if the argument "string" is not a "str" and if 
# the returned value is not an "int"
@typed(int, string = str)
def getStringLength(string):
    return len(string)
在库的API函数上使用这样的装饰器是否切实可行?在我看来,类型检查在库的特定于域的模块的内部工作中是不需要的,但是在库与其客户机之间的连接点上,通过应用类型检查的简单版本的契约式设计可能是有用的。特别是作为一种强制文档,它向库的客户清楚地说明它期望和返回的内容

类似于此示例,其中
addObjectToQueue()
isObjectProcessed()
公开供客户端使用,而
processTheQueueAndDoAdvancedStuff()
是一个内部库函数。我认为类型检查在面向外部的函数上可能很有用,但如果在内部函数上使用,它只会膨胀并限制python的动态性和实用性

# some_library_module.py

@typed(int, name = string)
def addObjectToQueue(name):
    return random.randint() # Some object id

def processTheQueueAndDoAdvancedStuff(arg_of_library_specific_type)
    # Function body here

@typed(bool, object_id = int)
def isObjectProcessed(object_id):
    return True
使用此技术的缺点是什么? 我的幼稚实现的缺点是什么?


我不想要讨论Python向静态类型语言转换的答案,而是想了解API设计特有的优缺点。(请把这个移到程序员。StasExchange。com,如果你认为这不是问题)

< P>个人,我不认为这个想法对Python有吸引力。当然,这只是我的观点,但从上下文来看,我会告诉你Python和Haskell可能是我最喜欢的两种编程语言——我喜欢静态类型和动态类型的两种极端语言

我认为静态类型的主要好处如下:

  • 一旦编译器接受了您的代码,代码正确的可能性就会增加;如果我知道我已经通过调用的所有操作将我的值线程化,这样一个操作的结果类型总是与另一个操作的输入类型匹配,并且最终的结果类型是我想要的类型,那么我选择正确操作的可能性就会增加。这一点是非常值得商榷的,因为它只在您不进行太多测试的情况下才真正重要,这将是不好的。但确实,在Haskell编程时,当我坐下来说“好了,完成了!”时,我实际上已经完成了很多次,而我的Python代码几乎从来都不是这样
  • 当我(大多数时候)对数据结构或接口进行不兼容的更改时,编译器会自动指出大多数需要更改的地方。同样,仍然需要测试来确保您已经抓住了所有的含义,但根据我的经验,大多数时候编译器的唠叨实际上已经足够了,这大大简化了重构;您可以直接从实现重构的核心到测试程序是否仍然可以正常工作,因为实现所有更改流的实际工作几乎是机械的
  • 有效实施。编译器可以使用所有关于类型的知识来进行优化
  • 您建议的系统实际上没有提供任何这些好处

  • 在使用您的库编写了一个程序之后,我仍然不知道它是否包含任何类型的错误函数用法,直到我对全部代码进行了广泛的测试,以查看任何执行路径是否包含错误的调用
  • 当我重构某些东西时,我需要经历多次“运行完整的测试套件,查找异常,找到它的来源,修复代码”,以获得任何东西,比如静态类型编译器的问题检测
  • Python仍然会表现得好像这些变量在任何时候都可以是任何东西
  • 为了获得更多,您牺牲了Python duck类型的灵活性;仅仅提供一个足够“类似列表”的对象是不够的,我必须提供一个列表


    对我来说,这种静态类型是两个世界中最糟糕的。主要的动态类型参数是“您无论如何都必须测试代码,因此您也可以使用这些测试来捕获类型错误,并且在类型系统对您没有帮助时,您不必再处理它”。对于真正好的静态类型系统来说,这可能是一个好的参数,也可能不是一个好的参数,但是对于只在运行时检测类型错误的弱部分静态类型系统来说,它绝对是一个引人注目的参数。我认为,失去灵活性并不值得有更好的错误消息(这在大多数情况下都是它真正为您带来的;没有在接口上捕获的类型错误几乎肯定会在调用堆栈中引发更深层次的异常)。

    使用此技术的缺点是什么?
    失去duck类型。