sábado, 3 de diciembre de 2016

T1. IMPORTACIONES. HACIENDO CRECER TU PROYECTO.

VISTA PARCIAL DE LA VEGA LAGUNERA, CENTRO ESTE DE TENERIFE.

    Dado lo importante que resulta conocer bien para nuestra formación como futuros  programadores el concepto de módulo que desarrollamos en la entrada anterior, y todo cuanto se relaciona directamente con él, vamos a traer aquí otra definición, algo más técnica, expuesta en Introducción a la programación con Python, de los profesores d. Andrés Marzal y dña. Isabel Gracia, de la Universidad Jaime I: "...y es que Python tiene una manera de poner definiciones en un archivo y usarlos en un script o en una instancia interactiva del intérprete. Tal archivo es llamado módulo. Las funciones definidas de un módulo pueden ser importadas a otros módulos o al módulo principal (la colección de variables a la que tenemos acceso en un script en el nivel superior y en el módulo calculadora). Un módulo es un archivo que contiene definiciones y declaraciones (variables y funciones) de Python. El nombre del archivo (el que le damos nosotros) es el nombre del módulo con el sufijo (extensión) .py agregado dentro de un módulo, el nombre del mismo (como una cadena o string) está disponible en el valor de la variable global '__name__'.




    ¡Ufff! ¡Vaya tela!, ¿Eh? No nos preocupemos: seguro que algunos de los aspectos citados por los profesores nos suenan de algo. Otros los veremos a continuación. Lo que ahora importa es "pillar" el fondo de la cuestión.





Finalmente, recapitulamos con esta otra que liga el concepto de módulo con el de librería dado que ambos elementos están estrechamente vinculados entre sí: los módulos constituyen "colecciones" de funciones (tanto nativas o built-ins como definidas por el usuario) que podemos utilizar desde nuestros propios programas. Así, conviene que las funciones se agrupen en módulos de acuerdo a su ámbito de aplicación. La distribución estándar de Python nos ofrece un gran número de módulos predefinidos. Cada módulo agrupa las funciones de un ámbito de aplicación. Por ejemplo, las funciones matemáticas se agrupan en el módulo "math"; las que tratan con cadenas literales de texto, en el módulo "string"; las que generan números al azar, en "random"; las que analizan documentos html, en "htmllib"; las que trabajan con fechas de calendario, en "calendar"; las que permiten un cliente propio de ftp (protocolo de intercambio de ficheros, file transfer protocol) en redes de ordenadores, en "ftplib"; etc. Cada una de éstas (math, htmllib, random, ftplib,...) son librerías que, como acabamos de decir, aglutinan módulos en base a un ámbito concreto de aplicación.



Aunque no se distingan todo lo bien que quisiéramos, éste es un ejemplo de casi todas las librerías integradas de las que podemos disponer en Python, la que nos implementa por defecto el lenguaje cuando lo instalamos en nuestro disco duro, cada una de ellas con sus correspondientes clases y funciones (las clases las estudiaremos en el manual dedicado a la Programación orientada a Objetos).
Y por cierto, ya que estamos,... ¿Y qué módulos tenemos disponibles en Python? Para conocerlos tan sólo tenemos que escribir en el SHELL del IDLE de Python el siguiente comando: >>> help("modules"), lo que casi de inmediato, nos muestra un amplio listado ordenado alfabéticamente de módulos propios, esto es, de los que hayamos creado nosotros mismos; de la librería estándar de Python, y los módulos importados de terceros, es decir, procedentes de librería externas de Python creadas por otros desarrolladores y que están a nuestra entera y libre disposición en la red.






Cuidado con escribir en el SHELL  >>> dir("modules") por emulación de la expresión >>> dir("__builtins__") que ya conocemos y que, hagamos memoria, nos devolvía un listado de las funciones preconstruidas de Python. En este caso, nos devuelve un listado de métodos asociados a las strings.


... que, como podemos ver, el recurso a la función help() no nos sirve de mucha ayuda que digamos a menos que escribamos específicamente el nombre del módulo, el operador punto y el nombre del método deseado.


Podemos acceder a cualquier módulo y conocer sus contenidos y potencialidades acudiendo de nuevo a la función help(), tal y como muestra el ejemplo. Para este caso hemos elegido el módulo calendar, devolviéndonos un listado de sus métodos/funciones.



   

      En las páginas anteriores, recordemos, construimos un módulo al que pusimos por nombre 'at', con su correspondiente extensión o sufijo .py ¿Estará, por algún casual, en nuestro extenso listado de librerías Python? pues... ¡Sí! ¡Sí que está! lo he subrayado yo con mis patas en la siguiente captura. ¡Guau!






Y aún podemos pasarlo por la función help() para que nos suministre información:


Ahora que ya tenemos estos conceptos más claros, retrocedemos y centramos nuestra atención en el script siguiente:

¿Y qué tenemos de nuevo aquí? Pues ni más ni menos que la madre del cordero, la piedra angular del edificio pythoniano, el meollo de la cuestión, la clave del asunto, la viga maestra... la sentencia import.

VERODE EN FLORACIÓN

La sentencia import ("importar") refiere, como su nombre indica, a la noción de "importar", "traer", "invocar", lo que nos habilita para poder usar los módulos que queramos (o necesitemos) en nuestros programas sin la obligación de tener que reescribir código y, ni siquiera, de recurrir a un copy paste que, aunque nos facilita mucho el acto de programar, engrosa, densifica, innecesariamente sin embargo el código, redundando en el concepto de 'reusabilidad' o 'reutilización' de código tan afecto al paradigma de la programación orientada a objetos que apunta, en última instancia, el horizonte al que se dirige este manual.
La sentencia import nos permite decirle al intérprete de Python qué módulo va a ser requerido. Una vez hayamos declarado esta línea de código, en nuestro ejemplo, import x, como hemos invocado a un módulo en concreto por su namespace, 'x', podremos invocar a su vez cualquier objeto (función) que esté definido en x. Por ejemplo, en el supuesto que estudiamos con anterioridad relativo al módulo 'at.py', una vez lo hubiéramos importado, esto es, 'import at', podríamos acceder a todos los objetos que contiene: las funciones 'area_triangulo(b, h)' y 'perimetro_triangulo(b, a, c)'. Para ello hacemos uso del carácter punto, '.', que actúa como separador entre módulo y objeto (función).



Fijándonos en su sintaxis, debemos escribir primero la sentencia import y, a continuación, el nombre del módulo que queremos importar, lo que nos proporciona una accesibilidad total a sus funciones. Esto viene muy bien cuando queremos importar una librería con muchas, muchísimas funciones, porque escribir todas las que podríamos utilizar, como veremos casi ya mismo, se convertiría en una labor costosísima, tremendamente engorrosa y poco práctica.
En el caso de que queramos saber qué funciones almacena tal o cual módulo, tenemos a nuestra mano una vieja conocida, la función dir(nombre_del_módulo), esta vez sí, con el nombre del módulo pasado como argumento de la función.


Si queremos conocer para qué podemos usar una función determinada seleccionando, no tenemos más que teclear de nuevo la función help(), pasándole como argumento el nombre del módulo, el operador punto a continuación y, finalmente, el nombre de la función.



      CUANDO RECURRAMOS A LAS IMPORTACIONES DEBEMOS PROCURAR HACERLO EN UN ORDEN CONCRETO, DE ACUERDO A LA CONVENCIÓN DE USO DE LA COMUNIDAD DE PROGRAMADORES DE PYTHON, IMPORTANDO PRIMERO LOS MÓDULOS DE LA LIBRERÍA NATIVA O ESTÁNDAR, A CONTINUACIÓN LOS MÓDULOS DE LAS LIBRERÍAS DE TERCEROS Y, FINALMENTE, NUESTROS PROPIOS MÓDULOS.

Como vemos, para acceder a una función def (definida por el usuario) cualquiera integrada dentro de un módulo, no tenemos más que importar el módulo primero y, a continuación, mediante la sintaxis namespace del módulo + . + nombre_de_la_función, invocar esa función y pasarle los argumentos que deseamos de acuerdo a los parámetros que hemos preestablecido.


En el siguiente ejemplo podemos comprobar su completa operatividad.


Además de la sentencia import  también podemos utilizar la sentencia from que muestra un comportamiento similar. Ambas difieren en que la segunda nos permite invocar una función (o más) sin necesidad de señalar el módulo que la/las contiene. Veamos cómo podemos emplear la sentencia from con nuestro módulo 'at.py':


Debemos tener en cuenta, sin embargo, que cuando utilizamos la sentencia from no exista ninguna función definida con el mismo nombre que el módulo, en cuyo caso, se mostraría la última función en ser definida. Por otro lado, si nos vemos en la necesidad de hacer muchas importaciones porque la complejidad del programa así lo requiera, resulta pertinente realizar distintos saltos de línea excepto para la última, o bien, situar los nombres de las funciones que queremos invocar entre paréntesis:


Si contamos con algún conocimiento previo de informática quizás recordemos la sintaxis aquélla que nos decía que, si por ejemplo, tenemos una carpeta que llamamos 'vacaciones__2016' donde hemos guardado todas nuestras fotos de la semanita que nos pasamos en la playa, digamos que unas cien fotos por poner un número redondo, todas ellas en formato jpg y, consecuentemente, cada una con su nombre y su correspondiente extensión o sufijo .jpg (por ejemplo, 'atardecer.jpg',  ''marazul.jpg', 'preciosa_luna_llena.jpg', 'surfing_1.jpg', 'surfing_2.jpg', 'el_chiringuito.jpg', etc.) y queremos mostrarlas todas a nuestros familiares y amigos, podemos recurrir a la sintaxis *.jpg, lo que mostrará en la pantalla de nuestro pc todas las fotos (ficheros) de la carpeta 'vacaciones__2016' que contengan la extensión .jpg (las que puedan tener otra extensión distinta, como .raw, .bmp, .tif u otras, no se mostrarán). Un buen invento, ¿verdad? Pues esta misma sintaxis y con el mismo operador * nos sirve para importar todas las funciones y métodos contenidos en un módulo.
La sintaxis sería ahora la siguiente: from nombre_módulo import *, por ejemplo, from math import *.
Veamos un ejemplo aplicado a nuestro módulo 'at'.


Y si en lugar de tomar todas las funciones del módulo nos interesa sólo trabajar con unas cuantas, podemos recurrir al separador coma, ',', entre los nombres de función que invoquemos.


Con este pequeño esquema se nos aclararán mejor las ideas. Echémosle un vistazo:


HORNO DE TEJA  EN LA LADERA DEL BARRANCO DE IGONCE, ARAFO, SURESTE DE TENERIFE.
Por otra parte, un módulo cualquiera es susceptible de ser importado para cambiarle su nombre y proporcionarle otro diferente, un alias, más acorde con su funcionalidad.
Para ello se utiliza el comando as ("como") seguido del nombre  con el que queremos renombrar la función. Debemos hacerlo a través de la siguiente sintaxis: import nombre_módulo as nuevo_nombre_módulo:





Esta opción, a pesar de ser perfectamente operativa y estar integrada plenamente en Python, no es la más recomendable dado que podría suscitar algún tipo de conflicto con los nombres que proporcionemos como alias. Se recomienda su uso sólo en caso de que las llamadas a ciertos módulos puedan generar confusión, o que su uso contribuya a clarificar el código. Comúnmente, se suele recomendar los módulos de importación habituales ya que sus nombres son inmediatamente reconocidos por Python. Precisamente, para evitar conflictos con los namespaces los desarrolladores de Python han configurado la sentencia as. De aquí la razón última de que existan los alias: impedir conflictos entre los namespaces de módulos y funciones.
El aliasing es un procedimiento en Python y en otros lenguajes de programación, por el cual es posible llamar a un objeto por un nombre, el que queramos, distinto al que le proporcionamos en el momento de su creación. Sin embargo, hay dos maneras de implementar el aliasing en nuestro código en base al tipo de objeto que queramos renombrar:
     ❋ Con la sentencia as: el uso de esta sentencia es exclusivo del ámbito de la importación, como acabamos de ver en el ejemplo. Básicamente, se utiliza en este caso para reducir nombres y/o cadenas de importación (función.subfunción.subsubfunción...), largos y complejos, que nos pueden llevar a cometer errores ortográficos, sustituyéndolos por expresiones literales más pequeñas, sencillas y cómodas de manejar. Eso sí, 📣 tengamos en cuenta que, en este caso, el nombre "original" deja de tener validez y sólo es legible para el intérprete de Python su nuevo alias.


     ❋ Cambiando el nombre sobre la marcha:  es la forma aceptada por Python para todos los demás objetos de Python. En este caso, no usamos la sentencia as y, en su lugar, usamos a un sobrenombre del objeto, pudiendo, esta vez, sí, ser invocado el objeto tanto por su nombre original como por su alias. Los programadores suelen usarlo porque resulta más sencillo y/o útil disponer de una forma alternativa de referirse a un objeto (alias) que copiarlo. Se basa en la sentencia de lógica formal, una forma de silogismo hipotético: si a implica b y b implica c, a implica c y b implica c, esto es a→b ^ b→c∴a⟶c.


Es importante hacer notar que en este caso, la llamada a la función debe hacerse, preferentemente, por el dott method, el método del punto (la notación de punto o el operador punto) como hemos visto en los ejemplos precedentes.
Para concluir con las importaciones, tan sólo exponer unas líneas para aquéllos que deseen profundizar un poquitín más en este tema, sobre el funcionamiento de la importación "a nivel de máquina".
La importación de un módulo en Python constituye la feliz conclusión de tres procedimientos que se llevan a cabo de manera consecutiva. El primero conlleva la localización del fichero que queremos importar en el módulo que hemos consignado a través de un 'path' ("camino", "ruta") de búsqueda. Una vez encuentra el fichero, el intérprete de Python comienza con el segundo procedimiento que consiste en la generación automática de un 'bytecode' ("código de bytes") que se vincula al fichero de acuerdo a la fecha de creación del fichero *.py y de su correspondiente versión *.pyc traducida al código máquina (recordemos que esto lo explicamos hace poco): si la fecha de creación del primero (*.py) es posterior a la fecha de creación del segundo (*.pyc), el intérprete de Python deduce que se ha creado un nuevo fichero *.py y que éste necesita su correspondiente versión *.pyc, y que procederá a crear de manera automática. Una vez concluido este proceso, pasamos al procedimiento final que no es otro que la ejecución del código correspondiente al módulo que hemos seleccionado.

TIRAS DE PLANTÍO EN LAS LADERAS DEL BARRANCO DE ARAYA, ARAFO, SURESTE DE TENERIFE.
Dado el tiempo y el costo en recursos, el intérprete de Python sólo realiza esta operación cuando importa el módulo por primera vez a lo largo de un proceso, por lo que en sucesivas llamadas al mismo recurrirá a la información contenido en la memoria caché.
Y ya que hemos cogido carrerilla... ¿qué es eso del PATH? Bueno... para poder realizar un acto de importación de una manera correcta y eficaz, el intérprete necesita conocer desde qué localización o 'path' ( "ruta") de todo el árbol de ficheros (algo así como desde qué rama del árbol debe empezar a buscar para llegar hasta esa manzana tan jugosa que queremos... importar) debe comenzar a buscar.
Siempre lo hará por el directorio donde reside el fichero *.py que está en proceso de ejecución. Si el resultado no es el esperado, pasa a buscar en el directorio señalado por el valor de la variable de entorno PYTHONPATH (¡Toma ya !). Nada grave, nada grave: se trata de una variable, que puede haber sido creada automáticamente dependiendo del sistema operativo que utilizamos, y de si estamos empleando o no la línea de comandos. Si tampoco la encontrara aquí, examinará todos los directorios de las librerías Python que tengamos guardadas en el disco duro empezando por la librería estándar de Python.












      CON ESTE ESQUEMA 
SEGURO QUE LO TENEMOS 
            MÁS CLARO...



El path de búsqueda faculta al intérprete para importar cualquier módulo y, a través de él, acceder a cualquier clase, propiedad y función contenidas en el mismo, con independencia de su ubicación. Para que resulte efectivo es necesario definir previamente la variable PYTHONPATH.
Si queremos saber cuáles son los directorios inscritos en el path de búsqueda podemos importar el módulo sys de la librería estándar y buscar la lista path que contiene:



Ahí lo tenemos, en orden,desde dónde empieza a buscar hasta dónde termina. Si queremos podemos añadir a la lista una dirección específica donde guardamos los módulos que más solemos emplear en nuestros programas para que empiece la búsqueda "a tiro hecho".
Aprovechando que estamos inmersos en el estudio del path, tomémonos un respiro para hacer una visita a las intimidades de nuestro IDLE de Python: T3. IDLE DE PYTHON 4.
Y seguimos...
Pasemos a la siguiente entrada, T1. PAQUETES (PACKAGES) DE PYTHON: ORDENANDO EL ARMARIO.

MALPAÍS BAJO LA MONTAÑA DE EL SOCORRO, AL FONDO, EN LA COSTA DE GÜÍMAR, SUR DE TENERIFE.


No hay comentarios:

Publicar un comentario