martes, 3 de enero de 2017

T1. PAQUETES (PACKAGES) DE PYTHON: ORDENANDO EL ARMARIO.

COLONIA DE PALOMERAS, BARRANCOS DE GÜÍMAR, SUR DE TENERIFE.
   
      No perdamos de vista, insistimos en ello, que los módulos nos permiten organizar mucho mejor nuestro código, lo aclara y lo vuelve más eficaz. A este concepto contribuye también el de PAQUETE (package) de Python.
Un paquete  no es otra que un directorio, una carpeta (folder). Recordemos que un directorio es un género de contenedor virtual donde se almacenan, o pueden almecenarse, por una parte, subdirectorios que, a su vez, pueden contener otro subdirectorios hasta un número n de los mismos con archivos (o no) en su interior ("árbol de subdirectorios") o, por otra parte, archivos (file) directamente, sin incluirlos en subdirectorio alguno. Los archivos que se almacenan en un directorio se agrupan en función de la relación procedimental que guardan entre sí, por ejemplo, si 'coche' fuera un paquete, sus ficheros, módulos en Python, podrían ser motor.py, chasis.py, carburador.py, cajadecambios.py, conducción.py, depósito_combustible.py, etc..., pero no hidrodinámica.py, que podría integrarse en un paquete llamado 'náutica', o cocina_vegana.py, que podría integrarse en un paquete llamado 'agricultura_ecológica' o en otro que pudiera llamarse 'formas_de_alimentación', o incluso en ambos.
Lo podemos ver sintéticamente en el siguiente esquema:



Partiendo de un directorio, el intérprete de Python genera de manera automática, sin que nosotros tengamos que hacer nada, un "espacio de nombre" (namespace) de las variables contenidas en dicho directorio con la ortografía característica de los mismos.
Pero..., claro. Aunque ya hemos empleado este concepto de namespace en alguna que otra ocasión, no sabemos todavía lo que es. Hagamos, pues, una aproximación al menos a lo que significa el "espacio de nombres".
En Python, el concepto de "nombre" (name) es muy similar al concepto de que ya conocemos de "variable" en el sentido de "poner nombre" a una variable (referencia a un espacio de la memoria donde almacenar un dato o un conjunto de ellos): el nombre (name) sería la "referencia". Sin embargo, debemos aportar un añadido.
Veamos.
En Python se le puede poner nombre a casi todo: a las variables ('a', 'frutas', 'pasivo', 'pares', etc.), a los valores/datos que almacenan las primeras (7, 12.98, ["a","b","c"], {"helio", "oxígeno", "argón", "neón"}, etc.), a las funciones definidas por el usuario (def) (def suma(a,b): s = a + b return s ==> el nombre de esta función es 'suma'), módulos ("chasis.py", "motor.py", "frenos.py", etc.), paquetes ("coche", "contabilidad", "registro_civil", etc.).
También en Python, todo lo que hemos visto hasta ahora son objetos: números (int, float, hex, oct,...), cadenas, tuplas, diccionarios, funciones, etc, son objetos. Y los objetos tienen nombre porque de alguna manera tienen que ser llamados para poderlos utilizar, para que sean útiles, para poder acceder a ellos.
Por simple deducción, un "espacio de nombres" es un constructo, una especie de listado virtual que Python, como hemos dicho, genera automáticamente en algún lugar inextricable de su cerebro binario, donde guarda y conserva amorosamente todos esos nombres de objetos (variables, datos, funciones, etc.).
Ya sabemos que un módulo no es otra cosa que un fichero, un archivo (file) que contiene código Python y que, a su vez, se almacena en un directorio (folder) concreto. Obviamente, para poder importarlo tal y como acabamos de ver en la entrada anterior, tenemos que "llamarlo por su nombre", esto es, aquéllo que hayamos escrito delante de la extensión .py. 
Necesariamente, cada módulo tiene que tener su propio nombre, un nombre distinto a los demás para que Python pueda reconocerlo e importarlo a nuestro código, tal y como le solicitamos. Si contáramos con dos módulos que comparten un mismo nombre que almacenan funciones/métodos distintos, que ejecutan acciones diferentes, al importar, llamar o invocar al módulo por su nombre, el intérprete de Python importará al primero que encuentre en su búsqueda sin tener en cuenta si se trata del módulo que queremos o no. Por esta razón, cada módulo recibe su propio "espacio de nombres" (namespace) global. 

     El concepto de namespace se extiende a todo lo que lleve nombre que, en Python, lo es casi todo porque, no lo olvidemos, todo son objetos y cada objeto lleva su propio nombre para poder invocarlo en cualquier momento del desarrollo de nuestro código. Y esta idea se extiende de manera un poco más especial a las variables, a los nombres, "referencias", de las variables de tal modo que, a menos que nosotros no le cambiemos su nombre de manera expresa, éste mantenga su "espacio de nombres" y no se SOBREESCRIBA y nos encontremos en la tesitura de llamar a una variable que contenga datos no deseados, o bien que una variable que contiene datos concretos asuma un nombre nuevo que no le hemos proporcionado de manera expresa. ¡Ay mi peluda cabecita!

La única excepción, para este caso, lo constituyen los módulos anidados, de estructura similar a las listas anidadas que estudiamos en su momento, donde la propia jerarquía a la hora de establecer el orden en que se escriben los módulos determina qué módulo con el mismo nombre debe tomarse en lugar del otro.



Sin embargo, como los namespaces también están perfectamente aislados entre sí, recordemos una vez más que esto lo hace Python de manera automática, siempre y cuando se alojen en módulos con distinto nombre, podemos tener, por ejemplo, un módulo llamado enteros.py y otro llamado decimales.py, y en el interior de cada uno de ellos una función que podríamos llamar, por ejemplo, "quad", que calcula el cuadrado del número que se le pase como argumento. En ambos casos, establecemos, como en el esquema, una ruta de llamada distinta: enteros.quad, para el primer caso, o decimales.quad para el segundo, por lo que no habrá motivo para la confusión.

VISTA DE LA COSTA OCCIDENTAL DE ANAGA DESDE LAS INMEDIACIONES DEL FARO DE ANAGA, NORESTE DE TENERIFE.

Ahora que ya comprendemos un poco mejor eso del "espacio de nombres" (namespace) podemos continuar con nuestra exposición.
En el caso de nuestro módulo de ejemplo que ya hemos visto, at.py, Python creará tres "espacios de nombres" distintos, uno por cada por cada fichero que tenemos en él, en función del nombre (name) que le hemos dado: '__area_triangulo__', '__altura_triangulo__' y '__perimetro_triangulo__'. Estos son los namespaces que ha creado Python automáticamente que contiene nuestro módulo at.py.
Y sí, con esa curiosa ortografía de dobles guión bajo delante y detrás del nombre, sí. Observemos el siguiente esquema:


Así, podremos organizar nuestro código de manera mucho más fluida y eficaz, recordémoslo: esta conversión a namespace la hace Python por sí mismo.
Aclarado esto, vamos a proceder a crear nuestro primer paquete, nuestro primer package. Para verlo mejor, crearemos un segundo módulo al que llamaremos circulo.py y que contendrá dos funciones: una para calcular el área del círculo (area_circulo) y otra para calcular el perímetro (circunferencia).



Aplicamos los procedimientos de guardado que ya vimos en el capítulo dedicado a módulos y, como podemos ver, ya tenemos ambos, at.py y circulos.py, guardaditos y bien calentitos en la librería estándar (stdlib) de Python listos para ser invocados cuando los necesitemos.


Es el momento adecuado para crear un paquete donde almacenar nuestros dos módulos at.py y circulos.py: construimos un nuevo fichero al que llamamos 'pack_areas' de la misma manera que hemos hecho con los módulos y, en él, importaremos los módulos que queramos guardar.



Comprobamos, por si las moscas, que nuestro nuevo módulo/directorio está incluido en la stdlib de Python:



... y comprobar seguidamente su completa operatividad con llamadas a funciones distintas de ambos módulos, at.py y circulos.py:


Sin embargo, desde el punto de vista del intérprete de Python tan sólo tenemos una carpeta/directorio que contiene dos módulos .py. Si queremos transformarlo en un paquete (package) Python con todas las de la ley, tan solo tenemos que añadir un archivo de inicio llamado: '__init__'.py, que estará por encima (jerárquicamente hablando, en el árbol de ficheros) de todos los demás módulos Python.
Este fichero/módulo '__init__'.py puede estar perfectamente vacío, sin contenido alguno. Y esto es incluso lo recomendable, aunque es posible guardar contenido en él.
Para hacerlo debemos proceder de la siguiente manera: abrimos nuestro IDLE de Python y creamos un fichero con ese mismo nombre de la manera habitual.




Podemos comprobar que ha sido almacenado en la librería estándar de Python acudiendo al comando help():



Efectivamente, así ha sido.. Conviene tener presente que cada vez que construyamos un paquete tendremos que inicializarlo (de aquí el constructo __init__) con este fichero, colocando tras él todos aquellos módulos que integran nuestro paquete. Por eso siempre es recomendable, por una parte, tenerlos vacíos y, por otra, copiar o construir unos cuantos para tenerlos siempre a nuestra disposición.
Podemos crear un nuevo fichero incluyendo al principio un fichero __init__ y el resto de módulos a continuación, para sobreescribir luego el paquete `pack__areas', conservando el nombre original. Podemos hacer las pertinentes llamadas para comprobar la fiabilidad y la utilidad de nuestro, ahora sí, package en toda regla.



Recapitulando, cada uno de nuestros archivos se llama en Python módulos, que deben tener una extensión o sufijo .py tras el nombre. Estos módulos, a su vez, pueden agruparse formando paquetes (packages). Un paquete es una carpeta o directorio que contiene archivos *.py. Pero para que un directorio pueda ser considerado un paquete, debe contener un "archivo de inicialización" que llamaremos __init__.py, que conviene dejar en blanco, vacío de contenido.



Es posible que en programas más grandes y complejos, a parte de directorios, tendremos que crear subdirectorios. O para ser más exactos, paquetes que contiene a su vez subpaquetes. Todos estos, junto con el paquete matriz, deben contener el módulo __init__.py como archivo de inicialización. Veamos un esquema de su estructura:



EL PITÓN VOLCÁNICO DE ANAMBRO EMERGIENDO ENTRE LAS NIEBLAS DE LA FRONDA HÚMEDA DE LA LAURISILVA DE ANAGA, NORESTE DE TENERIFE

      EL MÉTODO ESPECIAL __ALL__:

      Pueden darse situaciones en las que, pongamos por caso, queremos importar todos los archivos almacenados en un subpaquete, esto es, un paquete dependiente de otro de mayor jerarquía, una especie de 'paquete-padre' o paquete-raíz, que es lo que se entiende en Python como PAQUETES ANIDADOS. En estas situaciones, podría ocurrir que tardase mucho en cargarse los archivos o que, incluso, se produjeran respuestas no esperadas o indeseadas. Podría resultar más práctico cargar todos los módulos alojados en el mencionado subpaquete recurriendo a una única sentencia, lo que nos permitiría soslayar los posibles inconvenientes que hemos enumerado. ¿Cómo lo hacemos? Tendremos que editar el subpaquete y declarar una sentencia específica, para lo que utilizaremos una nomenclatura especial: __all__, sin sufijo, dado que no es ningún archivo de Python, como sí lo es el inicializador de un paquete (__init__.py) sino una variable, una variable "especial" que guarda una lista de todos los módulos contenidos en el subpaquete. Veamos la siguiente tabla.


Imaginemos ahora que queremos crear la variable __all__ para almacenar los tres módulos que se alojan en el subpaquete 'Técnicos_python'. Procederíamos de la siguiente manera:

                                                                        __all__ = ["Doc", "Pdf", "Txt"]





Ahora podemos realizar la siguiente importación:

                                                                from TEXTOS import Técnicos_python *

Lo que hará entonces el intérprete de Python es que cuando recorra el path, la ruta que lo lleva desde el paquete-raíz 'TEXTOS'  al subpaquete 'Técnicos_python', "mete la nariz" en su contenido y priorizará la variable __all__ sobre la importación módulo a módulo, resolviendo más eficazmente nuestra petición.
No parece tan complicado, ¿verdad?

TABAIBAS AL PIE DEL ROQUE DE JAMA, SUROESTE DE TENERIFE.


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.