Python 3和静态类型

时间:2009-08-14 01:47:27

标签: python python-3.x static-typing

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

def digits(x:'nonnegative number') -> "yields number's digits":
    # ...

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

经过一些搜索后,似乎有很多关于(完全可选的)静态类型的讨论,例如PEP 3107中提到的和"Adding Optional Static Typing to Python"(以及part 2)< / p>

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

5 个答案:

答案 0 :(得分: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)

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

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

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???

任何人都应该立即看到上述行中的错误,前提是它知道变量heightlength的“人类类型”,即使它将计算机视为完全合法 intfloat的乘法。

关于这个问题的可能解决方案可以说更多,但强制执行'计算机类型'显然是一个半解决方案,所以,至少在我看来,它比没有解决方案更糟糕。这就是为什么系统匈牙利是一个可怕的想法,而 Apps匈牙利是一个伟大的想法。在信息量很大的 post of Joel Spolsky 中还有更多信息。

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

答案 1 :(得分:14)

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

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

编辑:

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

答案 2 :(得分:13)

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

答案 3 :(得分:12)

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

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

assert isinstance(theobject, myclass)

你这样做:

theobject = IMyClass(theobject)

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

这结合了Python的动态主义和以特定方式拥有特定类型的愿望。

答案 4 :(得分:0)

当然,静态打字似乎有点“unpythonic”,我不会一直使用它。但是有些情况(例如嵌套类,如在域特定语言中解析),它可以真正加速您的开发。

然后我更喜欢使用beartype *中解释的post。它附带一个git repo,测试和解释它能做什么以及它不能做什么......我喜欢这个名字;)

*请不要注意Cecil对于为什么Python没有附带电池的咆哮。