Packages

Cuando comenzamos a usar Python, tarde o temprano llegaremos al usar módulos y paquetes.

En Python, un módulo es un objeto que sirve como contenedor para organizar codigo en Python. Cada módulo tiene asignado un espacio de nombres y dentro de ese espacio de nombres puede haber cualquier cantidad de objetos, y como en Python todo es un objeto, tambien puede contener otros módulos.

En el siguiente ejemplo se importa el módulo math; math es el espacio de nombres para un monton de funciones, clases y valores relacionados con operaciones matematicas; el nombre pi es uno de esos y se encuentra dentro del espacio de nombres math.

>>> import math
>>> math.pi
3.141592653589793
>>>

En lenguajes como C, lo equivalente es #include <math.h>, pero la diferencia esta en que todas las funciones, variables y constantes de la libreria se quedan disponibles en el espacio de nombres global. Cuando se incluyen muchas librerias y el codigo se hace muy grande, se corre el peligro de contaminar el espacio de nombres (namespace pollution). Otro problema es la colisión de nombres (namespace collision o namespace clash), que en nuestro ejemplo, ocurriría si alguna otra libreria define una variable o una funcion con el nombre pi.

Con los módulos de Python se matan dos pajaros de un tiro: 1) son una manera de organizar codigo y 2) se reduce la posibilidad de colisión de nombres y contaminar el espacio de nombres global.

Ademas de los módulos, Python tiene el concepto de paquetes Un paquete es un módulo de Python que contiene otros módulos y/o paquetes. La diferencia entre un módulo y un paquete es que el paquete contiene un atributo __path__ que indica la ruta en el disco duro donde esta almacenado el paquete.

Aca un ejemplo de un módulo:

>>> import os
>>> os
<module 'os' from '/usr/lib64/python2.7/os.pyc'>
>>> os.__package__

>>>

Ahora dos paquetes, json y gtk:

>>> import gtk
>>> gtk
<module 'gtk' from '/usr/lib64/python2.7/site-packages/gtk-2.0/gtk/__init__.pyc'>
>>> import json
>>> json
<module 'json' from '/usr/lib64/python2.7/json/__init__.pyc'>

Notaste alguna diferencia? os es un archivo mientras quegtk y json son archivos con el nombre __init__.py que estan dentro de un directorio con el mismo nombre del paquete.

Nota: pyc es la extension para archivos de python compilados. Casi siempre vienen acompanhados de el archivo .py original. Anda y abre los archivos .py correspondientes para que veas que no hay nada mágico.

Tanto módulos como paquetes tienen muchos mas detalles que no voy a cubrir por el momento, basta con que te quedes con lo siguiente: en Python, los archivos con extension .py son módulos, mientras que cualquier directorio que contenga un archivo con el nombre __init__.py se convierte en un paquete.

¿Dónde estan los módulos de Python?

Si en Python tanto los módulos y los paquetes son archivos y directorios con archivos ¿Te has preguntado de donde saca Python los módulos?

La libreria estándar de Python se encuentra en algun lugar del sistema de archivos. El lugar depende de si el sistema operativo es Windows, Linux, MacOS y si el sistema es de 64 bits o de 32.

En un Fedora 20 a 64 bits, la libreria estándar se encuentra en el directorio /usr/lib64/python2.7/. Los paquetes y módulos que no son parte de la libreria estándar de Python se encuentran en /usr/lib64/python2.7/site-packages/gtk-2.0/. Como ya dije, la ruta depende de el sistema operativo y nunca debemos de fiarnos de una ruta en especifico, en cambio, debemos hacer uso del módulo sys para saber la ruta actual donde Python entra a buscar módulos y paquetes.

El Python Path

Al iniciar un interprete de python, sys.path se inicializa con una lista de los directorios del sistema donde se encuentra instalado Python y la libreria estándar. La ruta de este directorio varia de sistema en sistema. Por ejemplo, en mi computadora:

>>> import sys
>>> sys.path
['', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/usr/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages/gtk-2.0', '/usr/lib64/python2.7/site-packages/wx-2.8-gtk2-unicode', '/usr/lib/python2.7/site-packages']

Y este es el Python path. Es una lista de cadenas que le indican a python a qué lugares del sistema debe ir a buscar módulos.

Esta lista de cadenas se inicializa a partir de la variable de entorno PYTHONPATH. Pero lo mas común es que no este definida.

El detalle mas importante del Python Path se encuentra en que la estructura de datos usada para almacenar las cadenas es una Lista y las listas son mutables. Eso quiere decir que si manipulamos el Python Path podemos indicarle a Python nuevas rutas a donde debe ir a buscar módulos y paquetes.

Herramientas como virtualenv como Buildout se aprovechan de esta caracteristica.