summaryrefslogtreecommitdiff
path: root/src/06_ejec_mod.md
diff options
context:
space:
mode:
authorEkaitz Zarraga <ekaitz@elenq.tech>2020-03-04 13:41:02 +0100
committerEkaitz Zarraga <ekaitz@elenq.tech>2020-03-04 13:41:02 +0100
commite81137474f102d71fe0b25307bcf88810c1b2d43 (patch)
tree840a184cf0b9c08a84c25caf390e4b7696589c9a /src/06_ejec_mod.md
parent403a94590f02479f7be41bbb62aae972e0ab596a (diff)
New arrangement for multilanguage and metadata support
Diffstat (limited to 'src/06_ejec_mod.md')
-rw-r--r--src/06_ejec_mod.md271
1 files changed, 0 insertions, 271 deletions
diff --git a/src/06_ejec_mod.md b/src/06_ejec_mod.md
deleted file mode 100644
index 0c54f4f..0000000
--- a/src/06_ejec_mod.md
+++ /dev/null
@@ -1,271 +0,0 @@
-# Módulos y ejecución
-
-Hasta ahora, has ejecutado el código en la REPL y de vez en cuando has usado
-`F5` en IDLE para ejecutar. Aunque te ha permitido salir del paso, necesitas
-saber más en detalle cómo funciona la ejecución para empezar a hacer tus
-programas. Además, es absurdo que te pelees contra todo, hay que saber qué
-batallas librar, así que necesitarás aprender a importar código realizado por
-otras personas para poder centrarte en lo que más te interesa: resolver tu
-problema.
-
-Este capítulo trata ambas cosas, que están muy relacionadas, y sirve como
-trampolín para el siguiente, la instalación de nuevos paquetes y la gestión de
-dependencias, y los posteriores sobre librerías interesantes que te facilitarán
-el desarrollo de tus proyectos.
-
-Este capítulo ya te capacita casi al cien por cien para la programación aunque
-aún no hemos trabajado su utilidad, pero seguro que alguna idea se te habrá
-ocurrido, si no no estarías leyendo este documento.
-
-## Terminología: módulos y paquetes
-
-En python a cualquier fichero de código (extensión `.py`) se le denomina
-*módulo* (*module*). A cualquier directorio que contenga módulos de código
-python y un fichero llamado `__init__.py`, que puede estar vacío, se le
-denomina *paquete* (*package*). El uso del fichero `__init__.py` permite que
-python busque módulos dentro del directorio.
-
-Piensa en los paquetes como grupos de módulos que incluso pueden anidarse con
-subpaquetes. En la documentación oficial verás en más de una ocasión que se
-trata a los paquetes como si fueran módulos, y tiene cierto sentido, porque,
-normalmente, existe un módulo principal que permite el acceso a un subpaquete.
-Así que, principalmente estás trabajando con un único módulo de un paquete, que
-contiene subpaquetes a los que este módulo hace referencia. Aunque pueda sonar
-algo enrevesado, no te preocupes por ahora: los módulos son ficheros únicos y
-los paquetes conjuntos de ellos.
-
-## Ejecución
-
-Ya conoces un par de maneras de ejecutar tus módulos de python. Usar la REPL,
-introduciéndole el código que quieres ejecutar, llamar a la función «ejecutar
-módulo» de IDLE con la tecla `F5` e incluso llamar a la shell de sistema con un
-comando similar a este:
-
-``` bash
-python mi_archivo.py
-```
-
-Normalmente, los ficheros de python se ejecutan de este último modo en
-producción, mientras que los dos anteriores son más usados a la hora de
-desarrollar. Realmente son métodos similares, en todos ellos el intérprete
-accede al fichero o contenido que recibe y ejecuta las líneas una a una.
-
-Existe también una opción adicional muy usada que sirve para ejecutar módulos
-que el sistema sea capaz de encontrar por sí mismo, en lugar de indicarle la
-ruta, se le puede indicar simplemente el nombre del módulo usando la opción
-`-m`:
-
-``` bash
-python -m nombre_de_modulo
-```
-
-## Importación y *namespaces*
-
-Anteriormente hemos pasado sobre la sintaxis de la importación de forma muy
-superficial pero tampoco es mucho más compleja a lo que ha aparecido. La
-sentencia `import` permite importar diferentes módulos a nuestro programa como
-en el siguiente ejemplo:
-
-``` python
->>> import datetime
->>> datetime
-<module 'datetime' from '/usr/lib/python3.6/datetime.py'>
-```
-
-Han pasado, sin embargo, muchas cosas interesantes en el ejemplo. En primer
-lugar, python ha buscado y encontrado el módulo `datetime` en el sistema y, en
-segundo lugar, ha creado un objeto módulo llamado `datetime` que atesora todas
-las definiciones globales del módulo `datetime`.
-
-Empezando por el final, python usa lo que se conoce como *namespace* de forma
-muy extendida. Los *namespaces*, de nombre (*name*) y espacio (*space*), son
-una herramienta para separar contextos ampliamente usada. Los objetos, en
-realidad, son una caso de *namespace* ya que cuando se llama a un método se le
-dice cuál es el contexto de la llamada, es decir: al método de qué objeto se
-llama.
-
-Para los módulos el proceso es el mismo. La sentencia `import` trae un módulo
-al programa pero lo esconde tras su *namespace*, de este modo, para acceder a
-algo definido en el recién importado módulo es necesario indicarle el nombre de
-éste de la siguiente manera:
-
-``` python
->>> import datetime
->>> datetime.date.today()
-datetime.date(2019, 12, 3)
-```
-
-En el ejemplo se accede a la clase `date` dentro del módulo `datetime`, y se
-lanza su función `today`, que indica el día de hoy. Como puedes apreciar, el
-operador `.` se utiliza del mismo modo que en las clases y objetos, y en
-realidad es difícil saber cuándo se está accediendo a una clase y cuándo a un
-módulo, aunque tampoco es necesario saberlo.
-
-Para no tener que escribir el nombre del módulo completo, existe otra versión
-de la sentencia `import` que tiene un comportamiento muy similar:
-
-``` python
->>> import datetime as dt
->>> dt.date.today()
-datetime.date(2019, 12, 3)
-```
-
-En este ejemplo, se ha cambiado el nombre del módulo a uno más corto decidido
-por el programador, `dt`. El funcionamiento es el mismo, simplemente se ha
-cambiado el nombre para simplificar. Este cambio de nombre también es útil
-cuando se va a importar un módulo cuyo nombre es igual que alguna otra
-definición. Cambiando el nombre se evitan colisiones.
-
-Existen versiones además, que permiten importar únicamente las funciones y
-clases seleccionadas, pero que las añaden al *namespace* actual, para evitar
-tener que usar el prefijo.
-
-``` python
->>> from datetime import date
->>> date.today()
-datetime.date(2019, 12, 3)
-```
-
-En este último ejemplo, se trae la clase `date` al contexto actual. También
-existe la posibilidad de importar más de una definición del módulo, usando la
-coma para separarlas, o todo lo que el módulo exponga mediante el símbolo `*`.
-Es peligroso, sin embargo, traer definiciones al namespace actual de forma
-descuidada, sobre todo con la última opción, porque, es posible que se repitan
-nombres por accidente y se pisen definiciones. Los namespaces se inventan con
-el fin de separar las definiciones y evitar colisiones de este tipo.
-
-### Búsqueda
-
-Una vez descrito cómo se interactúa con los módulos importados, es necesario
-describir dónde se buscan estos módulos.
-
-Los módulos se buscan en los siguientes lugares:
-
-1. El directorio del fichero ejecutado o el directorio de trabajo de la REPL
-2. Los directorios indicados en el entorno.
-3. La configuración por defecto (depende de la instalación)
-
-Esto significa que si guardas un archivo de python en IDLE y guardas otro más
-en el mismo directorio con el nombre `modulo.py` podrás importarlo usando
-`import modulo` en el primero, ya que comparten directorio. Lo mismo ocurre con
-los paquetes, crear un directorio con nombre `paquete` y añadirle un fichero
-vacío llamado `init.py` te permitirá hacer `import paquete`. Si añadieras más
-módulos dentro del paquete, podrías importar cada uno de ellos mediante
-`paquete.modulo`.
-
-> NOTA: Los nombres de los ficheros deben coincidir con el el nombre del módulo
-> más la extensión `.py`. En el caso de los directorios, saltar a un
-> subdirectorio implica acceder a un paquete, por lo que se añadirá un punto
-> (`.`).
-
-El primer punto sirve para facilitar que organices tu proyecto de python en
-varios módulos, separando así la funcionalidad en diferentes archivos.
-
-Los últimos dos puntos son los que permiten a python encontrar su librería
-estándar y los módulos de sistema. El tercero depende de la instalación y del
-formato de ésta: si python está instalado como portable no será igual que si se
-instala en el sistema del modo habitual. El segundo punto también puede variar
-de un sistema a otro, pero en resumen se trata de varias variables de entorno
-de sistema que le indican a python dónde buscar (normalmente toman el nombre
-`PYTHONPATH`, pero no es siempre así). El segundo punto puede alterarse de modo
-que en función de lo que se le indique, se puede pedir a python que busque los
-módulos en un lugar u otro.
-
-Estos lugares de búsqueda se pueden mostrar de la siguiente manera:
-
-``` python
->>> import sys
->>> print(sys.path)
-[ '',
- '/usr/lib/python36.zip',
- '/usr/lib/python3.6',
- '/usr/lib/python3.6/lib-dynload',
- '/usr/local/lib/python3.6/dist-packages',
- '/usr/lib/python3/dist-packages']
-```
-
-En función del sistema en el que te encuentres y la configuración que tengas,
-python mostrará diferente resultado.
-
-Rescatando un ejemplo previo:
-
-``` python
->>> import datetime
->>> datetime
-<module 'datetime' from '/usr/lib/python3.6/datetime.py'>
-```
-
-Ahora entiendes por qué es capaz de encontrar `datetime` en
-`/usr/lib/python3.6`, carpeta listada en `sys.path`, bajo el nombre
-`datetime.py`.
-
-## Ejecución vs Importación: `__main__` *guard*
-
-A la hora de importar un módulo, python procesa el contenido de éste ya que
-necesita definir las funciones, clases, valores, etc. a exportar: ejecuta el
-módulo.
-
-Python define una forma de separar la funcionalidad del código de sus
-definiciones con el fin de poder crear código cuyas definiciones sean
-reutilizables mediante la importación en otro módulo, sin que tenga ninguna
-funcionalidad cuando esto ocurra, pero habilitando que tenga funcionalidades
-cuando sea llamado directamente.
-
-Un ejemplo de uso de esto puede ser un módulo de acceso a ficheros, por
-ejemplo, que visualice el contenido del fichero cuando se llame de forma
-directa pero que cuando se importe únicamente aporte las funciones de lectura y
-escritura sin leer y mostrar ningún fichero.
-
-Para que los módulos puedan tener esta doble vida, python define la variable
-`__name__` que representa en qué nivel del *scope* se está ejecutando el módulo
-actual. La variable `__name__` toma el valor del nombre del módulo cuando éste
-está siendo importado y el valor `__main__` cuando ha sido llamado de forma
-directa o está siendo ejecutado en la REPL. `__main__` es el *scope* global de
-los programas, por lo que cuando algo se declara en él, implica que es el
-programa principal.
-
-Para poder diferenciar cuándo se ha ejecutado un módulo de forma directa y
-cuando se ha importado se utiliza lo que se conoce como `__main__` *guard*:
-
-``` python
-if __name__ == "__main__":
- # Este bloque sólo se ejecuta cuando el módulo es el principal
-```
-
-Aunque igual es un poco incómodo de entender de primeras, encontrarás esta
-estructura en casi cualquier módulo de código python. Se utiliza
-constantemente, incluso para los casos en los que no se pretende que el código
-pueda importarse. Es una buena práctica incluir el *guard* para separar la
-ejecución de las definiciones, de este modo, quien quiera saber cuál es la
-funcionalidad del módulo tendrá mucho más fácil la búsqueda.
-
-Puedes leer más sobre este tema en la documentación de python[^main-guard].
-
-[^main-guard]: <https://docs.python.org/3/library/__main__.html>
-
-
-Siguiendo este concepto, también existe el un estándar de nomenclatura de
-ficheros. El nombre `__main__.py` hace referencia al fichero que contiene el
-código que se incluiría dentro del *guard* y será el fichero que python buscará
-ejecutar siempre que se le pida ejecutar un paquete o un directorio sin
-especificar qué módulo debe lanzar. Por ejemplo, ejecutar `python .`[^dot] en
-la shell de sistema es equivalente a ejecutar `python __main__.py`.
-
-[^dot]: `.` significa directorio actual en cualquiera de los sistemas
- operativos comunes.
-
-
-## Lo que has aprendido
-
-En este capítulo corto has aprendido lo necesario sobre importación de módulos
-y ejecución de código. Conocer en detalle el patrón de búsqueda de módulos de
-python es primordial para evitar problemas en el futuro y organizar los
-proyectos de forma elegante.
-
-Además, el `__main__` *guard* era una de las últimas convenciones de uso común
-que quedaban por explicar y una vez vista ya eres capaz de leer proyectos de
-código fuente que te encuentres por ahí sin demasiados problemas.
-
-Los próximos capítulos, basándose en lo aprendido en éste, te mostrarán cómo
-instalar nuevas dependencias y cómo preparar tu propio código para que pueda
-ser instalado de forma limpia y elegante.