Python 3和静态类型

dbr*_*dbr 57 python static-typing python-3.x

我并没有像我希望的那样关注Python 3的开发,只是注意到一些有趣的新语法更改.具体来自这个SO答案函数参数注释:

def digits(x:'nonnegative number') -> "yields number's digits":
    # ...
Run Code Online (Sandbox Code Playgroud)

对此一无所知,我认为它可以用于在Python中实现静态类型!

经过一些搜索,似乎有很多关于Python中的(完全可选的)静态类型的讨论,例如PEP 3107中提到的和"向Python添加可选的静态类型"(以及第2部分)

但是,我不清楚这有多大进展.是否有使用参数注释的静态类型的实现?是否有任何参数化类型的想法进入Python 3?

ily*_* n. 33

感谢您阅读我的代码!

实际上,在Python中创建通用注释实施器并不难.这是我的看法:

'''Very simple enforcer of type annotations.

This toy super-decorator can decorate all functions in a given module that have 
annotations so that the type of input and output is enforced; an AssertionError is
raised on mismatch.

This module also has a test function func() which should fail and logging facility 
log which defaults to print. 

Since this is a test module, I cut corners by only checking *keyword* arguments.

'''

import sys

log = print


def func(x:'int' = 0) -> 'str':
    '''An example function that fails type checking.'''
    return x


# For simplicity, I only do keyword args.
def check_type(*args):
    param, value, assert_type = args
    log('Checking {0} = {1} of {2}.'.format(*args))
    if not isinstance(value, assert_type):
        raise AssertionError(
            'Check failed - parameter {0} = {1} not {2}.'
            .format(*args))
    return value

def decorate_func(func):    
    def newf(*args, **kwargs):
        for k, v in kwargs.items():
            check_type(k, v, ann[k])
        return check_type('<return_value>', func(*args, **kwargs), ann['return'])

    ann = {k: eval(v) for k, v in func.__annotations__.items()}
    newf.__doc__ = func.__doc__
    newf.__type_checked = True
    return newf

def decorate_module(module = '__main__'):
    '''Enforces type from annotation for all functions in module.'''
    d = sys.modules[module].__dict__
    for k, f in d.items():
        if getattr(f, '__annotations__', {}) and not getattr(f, '__type_checked', False):
            log('Decorated {0!r}.'.format(f.__name__))
            d[k] = decorate_func(f)


if __name__ == '__main__':
    decorate_module()

    # This will raise AssertionError.
    func(x = 5)
Run Code Online (Sandbox Code Playgroud)

鉴于这种简单性,乍一看这件事并不是主流,这很奇怪.但是,我认为有充分的理由说明它没有看起来那么有用.通常,类型检查有帮助,因为如果你添加整数和字典,你可能会犯一些明显的错误(如果你的意思是合理的话,那么显性比隐式更好).

但在现实生活中,您经常混合使用编译器看到的相同计算机类型的数量,但明显不同的人类类型,例如以下代码段包含一个明显的错误:

height = 1.75 # Bob's height in meters.
length = len(sys.modules) # Number of modules imported by program.
area = height * length # What's that supposed to mean???
Run Code Online (Sandbox Code Playgroud)

任何人应立即看到上面的行了一个错误,只要它知道变量的"人型" heightlength即使它看起来计算机完全合法的乘法intfloat.

关于这个问题的可能解决方案可以说更多,但强制执行"计算机类型"显然是一个半解决方案,所以,至少在我看来,它比没有解决方案更糟糕.这就是为什么匈牙利系统是一个糟糕的想法,而匈牙利应用程序是一个伟大的想法.在Joel Spolsky的信息丰富的帖子中还有更多内容.

现在,如果有人要实现某种Pythonic第三方库,它会自动分配给它的人类类型的真实数据,然后注意转换类型width * height -> area并强制执行带有函数注释的检查,我认为这将是一种类型检查人们真的可以使用!

  • 如果鲍勃不得不为他进口的每个模块用一块红色油漆涂抹一平方米的卧室怎么办? (32认同)
  • 我不明白你怎么能从"这个解决方案没有解决*每个*问题"跳到"这个解决方案比什么都不差".如果你真的以为你甚至不会使用python,因为python不是一个完美的语言,因此比什么都没有.即使是适当的静态类型语言也不会强制执行"语义类型",因为这是一个不可能的问题.他们通常甚至不执行物理SI类型,但我认为这是因为它通常不值得努力(但有些系统可以做到这一点). (25认同)
  • 有没有人想过Python中的IDE中的代码完成是如何必须的,因为我们不知道名为`a`的变量是什么类型,当用户键入`a`并点击时我们无法弄清楚要做什么CTRL空间... (4认同)
  • 他说"这是一个半解决方案*所以*它比没有解决方案更糟糕".也许他的意思是"和"不是"如此",但正如所写,他说所有半解决方案都比没有明显错误的解决方案更糟糕.但无论如何,类型错误在大型动态类型项目中并不是一个罕见的错误.防止错误只是静态类型的一个好处.还有其他重要的好处,即代码完成,重构和静态分析.我同意它增加了复杂性,所以我开始做事Dart的可选输入可能不像它第一次听起来那样疯狂. (4认同)
  • 静态类型检查的一点,例如在[Boo](http://boo.codehaus.org/)中具有Python语法,是运行时检查转换为编译类型的检查.不错的代码. (3认同)
  • 然后你应该使用显式类型转换来惩罚鲍勃.每个强类型系统,无论是静态还是动态,都有类型转换的规定:例如`'string'+ 5`被禁止但''string'+ str(5)`很好. (2认同)

syk*_*ora 14

正如PEP中所提到的,静态类型检查是可以使用函数注释的可能应用程序之一,但是它们将它留给第三方库来决定如何执行它.也就是说,核心python中不会有官方实现.

就第三方实现而言,有一些片段(例如http://code.activestate.com/recipes/572161/),它们似乎很好地完成了这项工作.

编辑:

作为一个注释,我想提一下检查行为比检查类型更可取,因此我认为静态类型检查并不是一个好主意.我上面的回答是为了回答这个问题,而不是因为我会以这种方式做自己的攻击.

  • 请注意,提到的代码段强制执行动态类型检查而不是**静态**类型检查. (2认同)

Cia*_*tic 13

这不是直接回答问题的答案,但我发现了一个增加静态类型的Python分支:mypy-lang.org,当然不能依赖它,因为它仍然很小,但很有趣.


Len*_*bro 12

Python中的"静态类型"只能实现,以便在运行时完成类型检查,这意味着它会降低应用程序的速度.因此,你不希望这是一般性的.相反,您需要一些方法来检查它的输入.如果您(错误地)认为您需要它很多,可以使用普通断言或装饰器轻松完成.

还有静态类型检查的替代方法,即使用面向方面的组件体系结构,如Zope组件体系结构.您可以调整它,而不是检查类型.所以代替:

assert isinstance(theobject, myclass)
Run Code Online (Sandbox Code Playgroud)

你做这个:

theobject = IMyClass(theobject)
Run Code Online (Sandbox Code Playgroud)

如果对象已经实现了IMyClass,则没有任何反应.如果没有,将查找包装任何对象到IMyClass的适配器,并使用而不是对象.如果找不到适配器,则会出现错误.

这结合了Python的动态主义和以特定方式获得特定类型的愿望.

  • 静态分析工具(如pylint)可以使用注释来执行一些完整性检查,非常类似于代码区域内的静态类型,其中变量或参数的类型是可知的,并且在被调用的API上存在注释. (5认同)