Pregunta

Realmente no presté tanta atención al desarrollo de Python 3 como me hubiera gustado, y apenas noté algunos cambios de sintaxis nuevos e interesantes.Específicamente de esta respuesta SO anotación de parámetro de función:

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

Sin saber nada sobre esto, pensé que tal vez podría usarse para implementar escritura estática en Python.

Después de algunas búsquedas, parecía haber mucha discusión sobre la escritura estática (completamente opcional) en Python, como la mencionada en PEP 3107, y "Agregar escritura estática opcional a Python" (y parte 2)

...pero no tengo claro hasta qué punto ha progresado esto.¿Existe alguna implementación de escritura estática, utilizando la anotación de parámetros?¿Alguna de las ideas de tipo parametrizado llegó a Python 3?

¿Fue útil?

Solución

¡Gracias por leer mi código!

De hecho, no es difícil crear un ejecutor de anotaciones genérico en Python.Aquí está mi opinión:

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

Dada esta simplicidad, a primera vista resulta extraño que esto no sea algo común.Sin embargo, creo que hay buenas razones por las que es no es tan útil como podría parecer.Generalmente, la verificación de tipos ayuda porque si agrega un número entero y un diccionario, es probable que haya cometido algún error obvio (y si quiso decir algo razonable, aún así es mejor ser explícito que implícito).

Pero en la vida real a menudo se mezclan cantidades iguales. tipo de computadora como lo ve el compilador pero claramente diferente tipo humano, por ejemplo, el siguiente fragmento contiene un error obvio:

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

Cualquier humano debería ver inmediatamente un error en la línea anterior siempre que conozca el "tipo humano" de las variables. height y length aunque a la computadora le parezca perfectamente legal multiplicación de int y float.

Se puede decir más sobre las posibles soluciones a este problema, pero hacer cumplir los 'tipos de computadoras' es aparentemente una solución a medias, por lo que, al menos en mi opinión, es peor que ninguna solución.Es la misma razón por la que Sistemas húngaro es una idea terrible mientras Aplicaciones húngaras es genial.Hay más en el muy informativo. publicación de Joel Spolsky.

Ahora bien, si alguien implementara algún tipo de biblioteca Pythonic de terceros que asignara automáticamente datos del mundo real, su tipo humano y luego se encargó de transformar ese tipo como width * height -> area y hacer cumplir esa verificación con anotaciones de funciones, ¡creo que sería una verificación de tipo que la gente realmente podría usar!

Otros consejos

Como se mencionó en el que la PPE, la comprobación de tipos estáticos es una de las posibles aplicaciones que funcionan las anotaciones se pueden utilizar para, pero están dejando a las bibliotecas de terceros para decidir cómo hacerlo. Es decir, no va a ser una aplicación oficial en Python núcleo.

En lo que se refiere a las implementaciones de terceros, hay algunos fragmentos (como http: // code.activestate.com/recipes/572161/ ), que parecen hacer el trabajo bastante bien.

EDIT:

Como nota, quiero mencionar que el control de comportamiento es preferible a chequear el tipo, luego pienso verificación de tipos estáticos no es tan grande una idea. Mi respuesta anterior está dirigido a responder a la pregunta, no porque yo lo haría verificación de tipos de mí de tal manera.

Esta no es una respuesta a la pregunta directamente, pero he encontrado un tenedor Python que añade tipos estáticos: mypy- lang.org , por supuesto, uno no puede confiar en él, ya que es todavía pequeño esfuerzo, pero interesante.

"tipos estáticos" en Python sólo puede ser implementado de modo que la comprobación de tipos se realiza en tiempo de ejecución, lo que significa que ralentiza la aplicación. Por lo tanto usted no quiere que, como generalidad. Por el contrario desea algunos de sus métodos para comprobar que es insumos. Esto puede hacerse fácilmente con llana afirma, o con decoradores si (erróneamente) cree que se necesita una gran cantidad.

También hay una alternativa a la comprobación de tipo estático, y que es utilizar una arquitectura de componentes orientada a aspectos como The Zope arquitectura de componentes. En lugar de comprobar el tipo, que adaptarlo. Así que en lugar de:

assert isinstance(theobject, myclass)

hacer esto:

theobject = IMyClass(theobject)

Si theObject ya implementa IMyClass no pasa nada. Si no es así, un adaptador que envuelve todo lo theObject es IMyClass se levantó, y se utiliza en lugar de theObject. Si no se encuentra ningún adaptador, se produce un error.

Esta combinó el dynamicism de Python con el deseo de tener un tipo específico de una manera específica.

Por supuesto, tipos estáticos parece un poco "unpythonic" y yo no lo uso todo el tiempo. Sin embargo, hay casos (por ejemplo, las clases anidadas, como en el dominio de análisis sintáctico del lenguaje específico) en el que realmente puede acelerar su desarrollo.

A continuación, Yo prefiero usar beartype se explica en este post *. Viene con un repositorio git, pruebas y una explicación de lo que puede y lo que no puede hacer ... y me gusta el nombre;)

* Por favor, no prestar atención a la queja de Cecil acerca de por qué Python no viene con baterías incluidas en este caso.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top