{"id":181,"date":"2020-09-15T01:53:56","date_gmt":"2020-09-15T00:53:56","guid":{"rendered":"https:\/\/www.julianmejio.com\/blog\/?p=181"},"modified":"2020-09-15T01:55:47","modified_gmt":"2020-09-15T00:55:47","slug":"python-3-9-nuevo-analizador-sintactico-tipado-generico-incorporado-y-mejoras-en-diccionarios","status":"publish","type":"post","link":"https:\/\/www.julianmejio.com\/blog\/2020\/09\/15\/python-3-9-nuevo-analizador-sintactico-tipado-generico-incorporado-y-mejoras-en-diccionarios\/","title":{"rendered":"Python 3.9: nuevo analizador sint\u00e1ctico, tipado gen\u00e9rico incorporado, y mejoras en diccionarios"},"content":{"rendered":"\n<p>Estamos <em>ad portas<\/em> de la nueva versi\u00f3n de Python, y desde ya tres caracter\u00edsticas se han hecho notar: operadores de fusi\u00f3n y actualizaci\u00f3n de diccionarios, incorporaci\u00f3n del tipado fuerte de colecciones gen\u00e9ricas, y el uso de un nuevo analizador sint\u00e1ctico. Adem\u00e1s hay cambios en m\u00faltiples m\u00f3dulos y como suele ocurrir con cada versi\u00f3n, mejoras en el rendimiento.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Nuevos operadores de manipulaci\u00f3n de diccionarios<\/h2>\n\n\n\n<p>Los diccionarios se han convertido en una de las estructuras de datos m\u00e1s usadas en todos los lenguajes de programaci\u00f3n, e incluso hoy en d\u00eda se usan en la gran mayor\u00eda de API. Dada su simplicidad y lectura amigable han reemplazado al XML en muchos \u00e1mbitos. Es por esto que coloco en primer lugar esta novedad de Python 3.9.<\/p>\n\n\n\n<p>Esta versi\u00f3n traer\u00e1 dos nuevos operadores para diccionarios: el operador Merge (|), y el operador Update (|=). Estos operadores arrojan una excepci\u00f3n l\u00f3gica TypeError hasta la versi\u00f3n 3.8 cuando los operandos son diccionarios.<\/p>\n\n\n\n<p>Adem\u00e1s de la facilidad que conlleva el uso de los nuevos operadores, esto tambi\u00e9n resuelve el problema de la ineficiencia de los actuales m\u00e9todos de manipulaci\u00f3n de diccionarios (D&#8217;Aprano, S. &amp; Bucher, B.). Quienes vivan de diccionarios en Python alguna vez se habr\u00e1n topado con m\u00e9todos como <code>update()<\/code> y  <code>ChainMap()<\/code> para fusionarlos, o incluso habr\u00e1n recurrido a trucos como el desempaquetamiento. De este \u00faltimo: es algo perverso y oscuro que solo introduce bugs en el c\u00f3digo, ya que ignora el tipado de los datos o requiere de condiciones especiales para su correcta operaci\u00f3n, que aunque funcione, viola los principios de portabilidad, sin contar con la ineficiencia.<\/p>\n\n\n\n<p>La mejor forma de ejemplificar el uso de los nuevos operadores es con un corto y sencillo ejemplo:<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>dict1 = {&#39;foo&#39;: &#39;bar&#39;}\ndict2 = {&#39;hello&#39;: &#39;world&#39;}\ndict3 = {&#39;hola&#39;: &#39;mundo&#39;}\n\n\n\n### &quot;Merge&quot; operator ###\ndict_merged = dict1 | dict2\nprint(dict_merged)\n\n# Results:\n# Python 3.8: TypeError\n# Python 3.9: {&#39;foo&#39;: &#39;bar&#39;, &#39;hello&#39;: &#39;world&#39;}\n\n\n\n### &quot;Update&quot; operator ###\ndict_merged |= dict3\nprint(dict_merged)\n\n# Results:\n# Python 3.8: TypeError\n# Python 3.9: {&#39;foo&#39;: &#39;bar&#39;, &#39;hello&#39;: &#39;world&#39;, &#39;hola&#39;: &#39;mundo&#39;}\n<\/code><\/pre><\/div>\n\n\n\n<p>La introducci\u00f3n de estos operadores fue una controversia en donde hasta se aleg\u00f3 que iban en contra de la filosof\u00eda de Python. Afortunadamente la decisi\u00f3n fue afirmativa, y de seguro muchos desarrolladores se alegrar\u00e1n y estar\u00e1n muy agradecidos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Incorporaci\u00f3n del tipado fuerte de colecciones gen\u00e9ricas<\/h2>\n\n\n\n<p>Crec\u00ed con Visual Basic, ASP 3.0 y PHP 4.3. Una caracter\u00edstica en com\u00fan de estos lenguajes es que no eran tipados, no hab\u00eda que declarar un tipo expl\u00edcito junto a las variables. M\u00e1s tarde me enamorar\u00eda de C#; la sintaxis tipo C no fue dura ya que era similar a PHP, sin embargo tuve que cambiar el paradigma de la <em>variable multiusos<\/em> al que estaba acostumbrado, ya que ahora ten\u00eda que definir su tipo de manera expl\u00edcita. Este punto me ayud\u00f3 a refinar mis buenas pr\u00e1cticas de programaci\u00f3n, y tambi\u00e9n incentiv\u00f3 a programar siguiendo el principio de responsabilidad \u00fanica.<\/p>\n\n\n\n<p>Ahora bien, en Python hay algunos casos en los que el tipado fuerte no es posible, al menos sin importar ning\u00fan m\u00f3dulo espec\u00edfico para esto. Por ejemplo, si quieres declarar una funci\u00f3n que retorna un diccionario con tres propiedades de tipo <code>str<\/code>, <code>int<\/code> e <code>int<\/code>. En este caso solo puedes hacerlo al importar el m\u00f3dulo annotations: <code>from __future__ import annotations<\/code>. Desde la versi\u00f3n 3.9 ahora los tipos de colecci\u00f3n gen\u00e9ricos vienen incorporados, o sea que ya no se requiere de una importaci\u00f3n adicional. Los tipos m\u00e1s usados que se incorporan son <code>tuple<\/code>, <code>list<\/code>, <code>dict<\/code>, <code>set<\/code>, <code>frozenset<\/code>, <code>type<\/code>, entre otros.<\/p>\n\n\n\n<p>De nuevo, explico esta caracter\u00edstica con un ejemplo:<\/p>\n\n\n\n<div class=\"hcb_wrap\"><pre class=\"prism line-numbers lang-python\" data-lang=\"Python\"><code>def hello(name: str, birthYear: int, currentYear: int) -&gt; dict[str, int, bool]:\n    age = currentYear - birthYear\n    return {&quot;name&quot;: name, &quot;age&quot;: age, &quot;adult&quot;: age &gt;= 18}\n\nprint(hello(&quot;Julian&quot;, 1950, 2020))\n\n# Results:\n# Python 3.8: TypeError: &#39;type&#39; object is not subscriptable\n# Python 3.9: {&#39;name&#39;: &#39;Julian&#39;, &#39;age&#39;: 70, &#39;adult&#39;: True}<\/code><\/pre><\/div>\n\n\n\n<p>Para que este fragmento de c\u00f3digo funcione en python 3.8 es necesario importar <code>annotations<\/code> como lo expliqu\u00e9 recientemente.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Nuevo analizador sint\u00e1ctico<\/h2>\n\n\n\n<p>Los idiomas al rededor del mundo siguen unas reglas sint\u00e1cticas: direcci\u00f3n de la escritura, caracteres, construcci\u00f3n de las oraciones, orden de los diferentes componentes dentro de una premisa, etc. Algunos idiomas son m\u00e1s flexibles y ricos en expresiones que otros, y otros pueden expresar ideas en menos caracteres.<\/p>\n\n\n\n<p>Los lenguajes de programaci\u00f3n se basan en esta teor\u00eda. Python es un lenguaje <em>per se<\/em>, por lo tanto debe seguir ciertas reglas para que el algoritmo tenga alg\u00fan significado. Estas reglas est\u00e1n definidas por el analizador sint\u00e1ctico \u2013el int\u00e9rprete\u2013, y es el que se encarga de transliterar nuestros algoritmos al lenguaje binario. Hasta Python 3.8, se usa un analizador sint\u00e1ctico de tipo LL. La regla fundamental de este tipo de analizador es que la direcci\u00f3n de la escritura es de izquierda a derecha, o sea, las reglas empiezan siempre por el t\u00e9rmino que se encuentra al principio de la l\u00ednea de c\u00f3digo.<\/p>\n\n\n\n<p>El analizador sint\u00e1ctico de Python desde la versi\u00f3n 3.9 es de tipo PEG. La gram\u00e1tica fundamental de este int\u00e9rprete se basa en el <span style=\"text-decoration: underline;\">an\u00e1lisis<\/span> sint\u00e1ctico de las expresiones: el proceso se centra en el reconocimiento de patrones dentro de los algoritmos. El proceso es parecido a las expresiones regulares, pero es m\u00e1s robusto y por cierto requiere de m\u00e1s recursos. PEG tambi\u00e9n cumple con prioridades, lo que resuelve algunos problemas de ambig\u00fcedad frente a analizadores de tipo LL.<\/p>\n\n\n\n<p>La raz\u00f3n principal por la que este cambio se hizo en Python es debido a la limitaci\u00f3n de los analizadores LL sobre los PEG, y Python, aunque era interpretado por LL, hoy en d\u00eda es m\u00e1s natural y l\u00f3gico ser interpretado por PEG. La consecuencia de este cambio es transparente en los altos niveles de abstracci\u00f3n, por lo que no ser\u00e1 notorio, y apenas se percibe una leve mejora en el rendimiento. Estos cambios impactan en mayor medida a niveles m\u00e1s bajos. Por ejemplo, uno de los m\u00f3dulos que est\u00e1 directamente relacionado con este cambio es <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/python\/cpython\/blob\/3.8\/Lib\/ast.py\" target=\"_blank\">ast<\/a>, uno de los m\u00f3dulos que trabaja al m\u00e1s bajo nivel, donde los desarrolladores ya no exploran.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hay m\u00e1s cambios<\/h2>\n\n\n\n<p>La nueva entrega de Python trae cientos de cambios y mejoras en m\u00f3dulos, retrocompatibilidad y caracter\u00edsticas auxiliares que facilitar\u00e1n la vida del desarrollador. Esta es una oportunidad para migrar los c\u00f3digos que aun corren sobre Python 2.7, pero de esta versi\u00f3n moribunda ya hablar\u00e9 luego.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Referencias<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>D&#8217;Aprano, S. &amp; Bucher, B. (2019). <em>Add Union Operators To dict<\/em>. Python Enhancement Proposals #584. Tomado de https:\/\/www.python.org\/dev\/peps\/pep-0584\/<\/li><li>Langa, \u0141. (2019). <em>Type Hinting Generics In Standard Collections<\/em>. Python Enhancement Proposals #585. Tomado de https:\/\/www.python.org\/dev\/peps\/pep-0585\/<\/li><li>Rossum, Galindo, &amp; Nikolaou (2020). <em>New PEG parser for CPython<\/em>. Python Enhancement Proposals #617. Tomado de https:\/\/www.python.org\/dev\/peps\/pep-0617\/<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Estamos ad portas de la nueva versi\u00f3n de Python, y desde ya tres caracter\u00edsticas se han hecho notar: operadores de fusi\u00f3n y actualizaci\u00f3n de diccionarios, incorporaci\u00f3n del tipado fuerte de colecciones gen\u00e9ricas, y el uso de un nuevo analizador sint\u00e1ctico. Adem\u00e1s hay cambios en m\u00faltiples m\u00f3dulos y como suele ocurrir con cada versi\u00f3n, mejoras en [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":189,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[8],"tags":[],"class_list":["post-181","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-desarrollo-de-software"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/www.julianmejio.com\/blog\/wp-content\/uploads\/2020\/09\/python_39.png","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts\/181","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/comments?post=181"}],"version-history":[{"count":4,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts\/181\/revisions"}],"predecessor-version":[{"id":186,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/posts\/181\/revisions\/186"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/media\/189"}],"wp:attachment":[{"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/media?parent=181"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/categories?post=181"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.julianmejio.com\/blog\/wp-json\/wp\/v2\/tags?post=181"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}