Desde 2014, cuando Python introdujo el soporte para
anotaciones de tipo , los programadores han estado trabajando en su implementación en su código. La autora del material, cuya primera parte de la traducción publicamos hoy, dice que, según su evaluación, las anotaciones de tipo bastante audaces (ahora denominadas "sugerencias") se utilizan en aproximadamente el 20-30% del código escrito en Python 3.
Aquí están los resultados de la encuesta, que ella, en mayo de 2019, publicó en Twitter.
Al final resultó que, las anotaciones son utilizadas por el 29% de los encuestados. Según la autora del artículo, en los últimos años, se ha encontrado cada vez más con anotaciones tipográficas en varios
libros y guías de estudio.
→
La segunda parte
En la documentación de Python, los términos "sugerencia de tipo" y "anotación de tipo" se usan indistintamente. El autor del artículo utiliza principalmente el término "sugerencia de tipo", utilizamos el término "anotación de tipo".
Este artículo cubrirá una amplia gama de problemas relacionados con el uso de anotaciones de tipo en Python. Si desea discutir el artículo
original con el autor, puede usar el mecanismo de
solicitud de extracción .
Introduccion
Aquí puede encontrar un ejemplo clásico de cómo se ve el código escrito usando anotaciones de tipo.
Aquí está el código regular:
def greeting(name): return 'Hello ' + name
Aquí está el código al que se agregan las anotaciones:
def greeting(name: str) -> str: return 'Hello ' + name
La plantilla según la cual se ejecuta el código con anotaciones de tipo se ve así:
def function(variable: input_type) -> return_type: pass
A primera vista, parece que aplicar anotaciones de tipo en el código parece simple y directo. Pero todavía hay una gran cantidad de incertidumbre en la comunidad de desarrolladores para comprender qué son exactamente las anotaciones de tipo. Además, incluso hay ambigüedad en cómo llamarlos correctamente: "anotaciones" o "sugerencias", y en qué ventajas ofrece su uso en la base de código.
Cuando comencé a investigar este tema y a pensar si necesitaba usar anotaciones de tipo, me sentí completamente confundido. Como resultado, decidí hacer lo mismo que siempre, habiéndome encontrado con algo incomprensible. Decidí investigar a fondo este tema y expongo mi investigación en forma de este material, que, espero, sea útil para aquellos que, como yo, quieren lidiar con las anotaciones de tipo en Python.
¿Cómo las computadoras ejecutan nuestros programas?
Para comprender lo que los desarrolladores de Python están tratando de lograr con anotaciones de tipo, hablemos sobre los mecanismos de los sistemas informáticos que están varios niveles por debajo del código de Python. Gracias a esto, podemos entender mejor cómo, en términos generales, funcionan las computadoras y los lenguajes de programación.
Los lenguajes de programación, en esencia, son herramientas que le permiten procesar datos utilizando una unidad central de procesamiento (CPU), así como almacenar en la memoria los datos que deben procesarse y los datos resultantes del procesamiento.
Circuito informático simplificadoUn procesador es una cosa bastante estúpida en su esencia. Es capaz de realizar acciones impresionantes con datos, pero solo entiende las instrucciones de la máquina, que se reducen a conjuntos de señales eléctricas. El lenguaje de máquina se puede representar como consistente en ceros y unos.
Para preparar estos ceros y los que el procesador entiende, debe traducir el código de un lenguaje de alto nivel a un lenguaje de bajo nivel. Aquí es donde entran los compiladores e intérpretes.
Si el lenguaje es
compilado o ejecutable (el código Python se ejecuta por medio del intérprete), entonces el código en este lenguaje se convierte en código de máquina de bajo nivel que contiene instrucciones para componentes de computadora de bajo nivel, es decir, para hardware.
Hay varias formas de traducir código escrito en algún lenguaje de programación a código que las máquinas puedan entender. Puede crear un archivo con el código del programa y convertirlo a código de máquina usando el compilador (así es como funcionan C ++, Go, Rust y algunos otros lenguajes), o ejecutar el código directamente usando el intérprete, que será responsable de convertir el código en comandos de máquina. Así es como, con la ayuda de intérpretes, se lanzan programas en Python, así como en otros lenguajes de "scripting", como PHP y Ruby.
Esquema de procesamiento de código de lenguaje interpretado¿Cómo sabe el hardware cómo almacenar ceros y unos que representan los datos con los que trabaja el programa en la memoria? Nuestro programa debe informar a la computadora cómo asignar memoria para estos datos. ¿Y qué son estos datos? Depende de qué tipos de datos admita un idioma en particular.
Los tipos de datos están disponibles en todos los idiomas. Por lo general, los tipos de datos son uno de los primeros temas que los principiantes aprenden a aprender a programar en un idioma determinado.
Hay excelentes tutoriales en el mismo Python, por ejemplo,
aquí es donde puede encontrar información detallada sobre los tipos de datos. En palabras simples, los tipos de datos son diferentes formas de representar los datos almacenados en la memoria.
Entre los tipos de datos existentes, por ejemplo, se pueden observar cadenas y enteros. El conjunto de tipos de datos disponibles para el desarrollador depende del lenguaje de programación que utilizan. Aquí, por ejemplo, hay una lista de
tipos de datos básicos de Python :
int, float, complex str bytes tuple frozenset bool array bytearray list set dict
Hay tipos de datos que consisten en otros tipos de datos. Por ejemplo, una lista en Python puede almacenar enteros o cadenas, así como ambos.
Para saber cuánta memoria necesita asignar para almacenar algunos datos, la computadora necesita saber qué tipo de datos colocará el programa en la memoria. Python tiene una
función getsizeof
incorporada que nos permitirá conocer la cantidad de memoria, expresada en bytes, necesaria para almacenar los valores de varios tipos de datos.
Aquí hay una gran respuesta a StackOverflow donde puede encontrar información sobre cómo averiguar los tamaños de los valores "mínimos" que se pueden almacenar en varios tipos de variables.
import sys import decimal import operator d = {"int": 0, "float": 0.0, "dict": dict(), "set": set(), "tuple": tuple(), "list": list(), "str": "a", "unicode": u"a", "decimal": decimal.Decimal(0), "object": object(), }
Como resultado, al ordenar un diccionario que contiene muestras de valores de varios tipos, podemos descubrir que el tamaño máximo es un diccionario vacío (
dict
) y seguido de un conjunto (
set
). En comparación con ellos, se necesita muy poco espacio para almacenar un número entero (tipo
int
).
El ejemplo anterior nos da una idea de cuánta memoria se requiere para almacenar varios valores utilizados en los programas.
¿Por qué debería molestarnos esto? El hecho es que algunos tipos son mejores que otros para resolver algunos problemas, lo que le permite resolver estos problemas de manera más efectiva. En algunas situaciones, los tipos deben verificarse cuidadosamente. Por ejemplo, a veces se realizan comprobaciones de que los tipos de datos utilizados en el programa no son contrarios a algunas suposiciones hechas al diseñar el programa.
¿Pero qué son estos tipos? ¿Por qué los necesitamos? Aquí es donde entra en juego el concepto de "sistema de tipos".
Introducción a los sistemas de tipos
Hace mucho tiempo , en una galaxia distante y distante, las personas que realizaban cálculos matemáticos de forma
manual se daban cuenta de que si comparaban los "tipos" con números o elementos de ecuaciones, podían reducir la cantidad de errores lógicos que aparecen al derivar pruebas matemáticas sobre estos elementos.
Dado que al principio la informática se redujo, en esencia, a la ejecución de grandes volúmenes de cálculos manuales, algunos de esos viejos principios se transfirieron a estos cálculos. Los sistemas de tipos se han convertido en una herramienta utilizada para reducir la cantidad de errores en los programas mediante la asignación de tipos apropiados a diversas variables o elementos.
Aquí hay algunos ejemplos:
- Si escribimos software para el banco, entonces no podemos usar las líneas en el fragmento de código que calcula el saldo en la cuenta de otra persona.
- Si estamos trabajando con los datos de una encuesta y queremos entender si alguien respondió una pregunta positiva o negativamente, entonces la respuesta "sí" y "no" se codificará de forma más natural utilizando un tipo lógico.
- Al desarrollar un motor de búsqueda grande, debemos limitar el número de caracteres que los usuarios de este sistema pueden ingresar en el campo de consulta de búsqueda. Esto significa que necesitamos verificar algunos datos de cadena para verificar el cumplimiento de ciertos parámetros.
Hoy en programación, hay dos sistemas de tipo principal.
Esto es lo que
Steve Klabnik escribe sobre esto: "Un sistema de tipo estático es el mecanismo por el cual el compilador verifica el código fuente y asigna etiquetas (llamadas" tipos ") a los fragmentos del programa, y luego los usa para sacar conclusiones sobre el comportamiento del programa. Un sistema de tipo dinámico es el mecanismo por el cual el compilador genera código para observar qué tipos de datos (también se denominan "tipos", por coincidencia) son utilizados por el programa ".
¿Qué significa esto? Esto significa que cuando se trabaja con lenguajes compilados, generalmente debe asignar tipos de entidad por adelantado. Gracias a esto, el compilador podrá verificarlos durante la compilación del código y averiguar si será posible crear un programa significativo a partir del código fuente que se le proporcionó.
Recientemente me encontré con una
explicación de la diferencia entre la escritura estática y dinámica. Este es probablemente el mejor texto que he leído sobre este tema. Aquí hay un fragmento: “Solía usar lenguajes estáticamente escritos, pero en los últimos años he estado programando principalmente en Python. Al principio, usar mecanografía estática me molestó un poco. Tenía la sensación de que la necesidad de declarar tipos variables se ralentiza y me obliga a expresar demasiado mis ideas. Python simplemente me dejó hacer lo que quería, incluso si accidentalmente hice algo mal. Usar idiomas con tipeo estático es como dar una tarea a alguien que siempre pregunta de nuevo, aclarando los pequeños detalles del caso que tiene asignado completar. La escritura dinámica es cuando la persona a la que se le asigna la tarea siempre asiente. En este caso, existe la sensación de que te entendió. Pero a veces no hay una certeza total de que la persona a quien se le ha encomendado la tarea haya descubierto adecuadamente lo que se espera de él ”.
Al hablar sobre sistemas de tipos, me encontré con algo que no entendí de inmediato. A saber, los conceptos de "escritura estática" y "escritura dinámica" están estrechamente relacionados con los conceptos de "lenguaje compilado" y "lenguaje interpretado", pero los términos "estático" y "compilado", así como los términos "dinámico" e "interpretado" no son sinónimos . El lenguaje puede escribirse dinámicamente, como Python, y al mismo tiempo compilarse. Del mismo modo, un lenguaje se puede escribir estáticamente, como Java, pero también se puede interpretar (por ejemplo, en el caso de Java, cuando se utiliza Java REPL).
Comparación de tipos de datos en lenguajes tipados estática y dinámicamente
¿Cuál es la diferencia entre los tipos de datos en lenguajes de tipo estático y dinámico?
Cuando se utiliza la escritura estática, los tipos deben declararse por adelantado. Por ejemplo, si trabaja en Java, sus programas se verán así:
public class CreatingVariables { public static void main(String[] args) { int x, y, age, height; double seconds, rainfall; x = 10; y = 400; age = 39; height = 63; seconds = 4.71; rainfall = 23; double rate = calculateRainfallRate(seconds, rainfall); } private static double calculateRainfallRate(double seconds, double rainfall) { return rainfall/seconds; }
Presta atención al comienzo del programa. Allí se declaran varias variables, junto a las cuales hay indicaciones de los tipos de estas variables:
int x, y, age, height; double seconds, rainfall;
Además, los tipos se especifican tanto al declarar funciones como al declarar sus argumentos. Sin estas declaraciones de tipo, el programa no se puede compilar. Al crear programas Java, desde el principio, debe planificar qué tipos tendrán estas o esas entidades. Como resultado, el compilador, mientras procesa el código de dichos programas, sabrá exactamente lo que necesita verificar en el proceso de generación de código de máquina.
Python le quita la molestia a un programador. Un código Python similar podría verse así:
y = 400 age = 39 height = 63 seconds = 4.71 rainfall = 23 rate = calculateRainfall(seconds, rainfall) def calculateRainfall(seconds, rainfall): return rainfall/seconds
¿Cómo funciona todo esto en las entrañas de Python? Continuará ...
Estimados lectores! ¿Qué lenguaje de programación que usaste dejó la impresión más agradable?
