64 votes

Python 3 et typage statique

Je n'ai pas vraiment d'accorder autant d'attention à Python 3 de développement que je l'aurais voulu, et viens de remarquer que certains intéressant de nouveaux changements de syntaxe. Plus précisément à partir de cette SORTE de réponse paramètre de la fonction d'annotation:

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

Ne rien savoir à ce sujet, j'ai pensé qu'il pourrait peut-être être utilisé pour la mise en œuvre de typage statique en Python!

Après quelques recherches, il semble y avoir beaucoup de discussion au sujet (entièrement facultatif) le typage statique en Python, tels que celui mentionné au PEP 3107, et "Ajouter en Option le Typage Statique pour Python" (et partie 2)

..mais, je ne suis pas clair dans quelle mesure cela a progressé. Existe-il des implémentations de typage statique, en utilisant le paramètre-annotation? Les paramétrés de type les idées de le faire en Python 3?

35voto

ilya n. Points 6610

Merci pour la lecture de mon code!

En effet, il n'est pas difficile de créer un générique d'annotation de l'outil en Python. Voici mon point de vue:

'''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)

Compte tenu de cette simplicité, c'est étrange à première vue, que cette chose n'est pas ordinaire. Cependant, je crois qu'il y a de bonnes raisons pourquoi c'est pas aussi utile que cela puisse paraître. En général, la vérification du type aide parce que si vous ajoutez entier et dictionnaire, les chances sont que vous avez fait quelques erreur évidente (et si vous vouliez dire quelque chose de raisonnable, c'est toujours mieux d'être explicite qu'implicite).

Mais dans la vraie vie, vous avez souvent mélanger des quantités du même type d'ordinateur tel que vu par le compilateur, mais clairement les différents type d'homme, par exemple le fragment de code suivant contient une erreur évidente:

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

Tout homme doit voir immédiatement une erreur dans la ligne ci-dessus pour autant qu'elle sache le "type d'homme" de variables height et length , même si elle ressemble à l'ordinateur comme parfaitement légal multiplication des int et float.

Il n'y a plus à dire sur les solutions possibles à ce problème, mais l'application de l'ordinateur de types " est apparemment une demi-solution, de sorte que, au moins à mon avis, c'est pire que pas de solution du tout. C'est la même raison pourquoi les Systèmes hongrois est une idée terrible, tandis que les Applications hongrois est un grand. Il n'y a plus à le très instructif post de Joel Spolsky.

Maintenant, si quelqu'un était de mettre en place une sorte de Pythonic de la troisième partie de la bibliothèque qui permettrait d'attribuer automatiquement des données du monde réel de son type d'homme , puis a pris le soin de transformer ce type comme width * height -> area et faire valoir ce que de vérifier avec la fonction annotations, je pense que ce serait une vérification du type de personnes pourraient vraiment utiliser!

15voto

sykora Points 30290

Comme mentionné dans ce PEP, vérifier le type statique est l'une des applications possibles de cette fonction, les annotations peuvent être utilisés, mais ils sont le fait de laisser aux bibliothèques tierces pour décider de la façon de le faire. Qui est, il ne va pas être un fonctionnaire de la mise en œuvre dans le noyau de python.

Aussi loin que les implémentations de tiers sont concernés, il y a quelques extraits (comme http://code.activestate.com/recipes/572161/), qui semblent faire le travail assez bien.

EDIT:

Comme une note, je tiens à mentionner que le comportement du contrôle est préférable de vérification de type, donc je pense que le typage statique n'est pas si grande idée. Ma réponse ci-dessus est destiné à répondre à la question, non pas parce que je ne le typage moi-même dans une telle voie.

14voto

Lennart Regebro Points 52510

"Le typage statique" en Python ne peuvent être mis en œuvre de sorte que le type de vérification est effectué au moment de l'exécution, ce qui signifie qu'il ralentit l'application. Par conséquent, vous ne voulez pas que comme une généralité. Au lieu de cela, vous souhaitez que certains de vos méthodes afin de vérifier les entrées. Cela peut être fait facilement avec la plaine affirme, ou avec des décorateurs si vous (à tort) pense que vous en avez besoin beaucoup.

Il est également une alternative à la vérification des types statiques, et qui consiste à utiliser un aspect oriented architecture de composants comme L'Architecture de Composants de Zope. Au lieu de vérifier le type, vous adapter. Ainsi, au lieu de:

assert isinstance(theobject, myclass)

pour ce faire:

theobject = IMyClass(theobject)

Si theobject implémente déjà IMyClass rien ne se passe. Si ça ne marche pas, un adaptateur qui encapsule tout ce theobject est à IMyClass sera regardé, et utilisé à la place de theobject. Si aucun adaptateur n'est trouvé, vous obtiendrez une erreur.

Cette combinaison de la dynamicism de Python avec le désir d'avoir un type spécifique d'une manière spécifique.

13voto

Ciantic Points 1376

Ce n’est pas une réponse directe à une question, mais j’ai découvert un fork de Python qui ajoute du typage statique: mypy-lang.org , bien sûr, on ne peut pas s’y fier car c’est encore peu, mais intéressant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X