Módulos, paquetes y la librería estándar de
Python
Como ya hemos visto, podemos importar nuevos módulos de la libre‐
ría extándar de Python o de terceros con import <modulo>, pero hay
varias maneras de hacerlo:
In [10]: i
immp
poorrtt mma
atth
h # importa el módulo math
In [11]: i
immp
poorrtt mma
atth
h aass M M # importa el módulo math llamánd
In [12]: f
frro
omm m ma
atth
h iimmp
poorrtt sin, cos, pi # importa las funcione
In [13]: f
frro
omm m ma
atth
h iimmp
poorrtt * # importa todas las funciones de
De manera similar podemos crear un módulo propio que puede usar‐
se como un programa independiente o importase como un módulo y
poder reutilizar sus funciones:
#!/usr/bin/python3
#-*- coding: utf-8 -*-
"""Programa de calculo del cubo de un numero"""
__author__ = "Jorge"
__copyright__ = "Curso de Python"
__credits__ = ["Pepe", "José Luis", "Roberto"]
__license__ = "GPL"
__version__ = "1.0"
__email__ = "[email protected]"
__status__ = "Development"
ddeeff cubo(x):
"""Calcula el cubo de un numero"""
y = x**3
rre
ettu
urrnn y
iiff __name__ == "__main__":
x = int( input("Dame un numero: ") )
y = cubo(x)
print("El cubo de %.2f es %.2f" % (x, y))
Bien, ahora podemos usar este programa como un ejecutable como
ya hemos hecho o importarlo como un módulo y usar la función cu‐
bo(). La primera de comentario multilínea, limitada por comillas tri‐
ples, se asiga automáticamente a la variable mágica doc como la do‐
cumentación del módulo o programa y el resto de variables especia‐
les como información adicional. Igualmente la primera línea de def()
es la documentación de la función. La variable especial name es el
nombre del módulo cuando se usa como tal, que en este caso vale
cubo, pero tiene valor «main» cuando se ejecuta como un programa.
De esta manera distinguimos cuando el código se está ejecutando
como un programa o está siendo llamado como un módulo.
iimmppoorrtt c
cuub
boo
In [20]: cubo.__doc__
Out[20]: 'Programa de calculo del cubo de un numero'
In [21]: cubo.cubo(3)
Out[21]: 27
In [22]: cubo.cubo.__doc__
Out[22]: 'Calcula el cubo de un numero'
In [23]: cubo.__version__
Out[23]: '1.0'
Para poder importar un módulo nuestro, debe estar en el directorio
donde lo estamos llamando, o bien estar en una ruta incluida en el
PATH de la librería o bien en la variable PYTHONPATH.
$ echo $PYTHONPATH
:/home/japp/codigo/lib/:/usr/local/aspylib/:/usr/local/lib/pyt
Alternativamente, se puede incluir el PATH en el programa ejecutable
añadiéndolo a la lista sys.path:
iimmppoorrtt s
syys
s
sys.path.append('/home/japp/mis_modulos/')
En Windows, funciona de forma idéntica pero usando las rutas de
Windows:
sys.path.append('C:\mis_modulos')
Para modificar de forma temporal el PYTHONPATH en Windows haría‐
mos:
C:\>set PATH=C:\Program Files\Python 3.6;%PATH%
C:\>set PYTHONPATH=%PYTHONPATH%;C:\mis_modulos
C:\>python
Si se quiere añadir permanentemente es algo más complicado. Des‐
de el botón de inicio hay que buscar Propiedades del sistema (Sys‐
tem properties) -> Advanced system settings y pinchar en el botón de
variables de entorno, donde se pueden modificar la variables de en‐
torno del sistema (solo el administrador).
Estructura de un paquete de Python
Los paquetes de python son un espacio de nombres que contiene va‐
rios módulos o paquetes, a veces relacionados entre ellos aunque no
tiene porqué. Se crean en un directorio que debe incluir obligatoria‐
mente un fichero especial llamado __init__.py que es el que indica
que se trata de un paquete y luego pueden haber otros módulos e in‐
cluso otros paquetes. La siguiente es la estructura típica de un pa‐
quete:
mi_paquete/
__init__.py
modulo1.py
modulo2.py
utiles/
__init__py
utiles1.py
config.py
El fichero __init__.py puede y suele estar vacío, aunque se puede usar
para importar modulos comunes entre paquetes.
iimmppoorrtt m
mii_
_ppaaqqu
ueet
tee
ffrroomm m
mii_
_ppaaqqu
ueet
tee i
immp
poorrtt utiles1
La librería estándar de Python
La instalación básica de Python viene con una muy completa librería
de módulos para todo tipo de tareas, incluyendo acceso a ficheros y
directorios, compresión de ficheros, ejecución recurrente (multihilo),
email, html, xml, csv y un largo etcétera. Lo más conveniente es con‐
sultar la documentación de la librería estándar para tener una idea de
todo lo disponible, pero podemos probar los más importantes.
Creación y administración de ficheros
La forma más directa y práctica de interactuar con el sistema, inde‐
pendientemente de la plataforma, es empleando el módulo os, que
básicamente es una interfaz para sistema operativo del ordenador
que ejecuta el programa.
iimmppoorrtt o
oss
os.chdir("/home/japp/Documentos/")
os.getcwd()
# /home/japp/Documentos/
# Esto no imita a ls, no distingue ficheros y directorios
ficheros = os.listdir(".") # hay que poner una ruta
ffoorr fichero i
inn ficheros:
print os.path.isdir(fichero) # .isfile(), islink()
Para mayor flexibilidad en la selección de ficheros, por ejemplo usar
caracteres comodín, se puede usar el paquete glob:
ffrroomm g
gllo
obb i
immp
poorrtt glob
ficheros = glob("*.txt")
# Son listas también pero con una ruta relativa, así que no fu
ficheros = glob("/home/japp/") # no devuelve nada
ficheros = glob("/home/japp/*") # Esto si
os.mkdir("registro")
# os.makedirs('/home/japp/Documentos/datos/pruebas') # Linux,
# os.makedirs('C:\\Mis Documentos\\datos\\pruebas') # Window
os.chmod("registro", 0700)
os.rename("registro", "registros")
Lectura y escritura de ficheros de texto
Si queremos leer o escribir ficheros de texto primero hay que abrirlos
en el modo adecuado (r, w, a) para terner una instacia del fichero,
que luego se puede leer a string de varias formas.
# Leo un fichero CSV con código y nombre de paises
fichero = open("paises.csv")
contenido = fichero.read() # Lo mete todo en un único string
fichero.close()
len(contenido)
print(contenido[:30])
#'nombre, name, nom, iso2, iso3,'
fichero = open("paises.csv")
lineas = fichero.readlines() # Lee línea a línea, devuelve un
fichero.close()
len(lineas)
247
De haber querido separar por columnas, pudimos haber usado algo
como:
nombre, name, nom, iso2, iso3, phone_code = lineas
justo después de readlines(), al hacerlo, split() devuelve una
lista de dos elementos (en este caso) que desempaquetamos en las
variables que damos a la izquierda.
Podemos igualmente escribir un fichero creando un fichero en modo
lectura y usar el método write(str) para guardar una cadena de
texto o bien usar writelines(lista) para guardar el contenido de
una lista de strings.
¿Y si el fichero es remoto? hay varias maneras de resolverlo, pero lo
más cómodo es con el módulo uurrlllliibb:
iimmppoorrtt u
urrl
llliibb.
.rre
eqqu
uees
stt
iimmppoorrtt c
cssv
v
# Fichero remoto
# https://gist.github.com/brenes/1095110
url = "https://gist.githubusercontent.com/brenes/1095110/raw/f
# Terremotos del día de USGS
# url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/sum
# Leemos remotamente el fichero csv
respuesta = urllib.request.urlopen(url)
# Pasamos la instancia a un string
contenido = respuesta.read() # o readlines()
# Usamos esta vez el módulo csv de Python para interpretar el
reader = csv.reader(contenido)
Ahora probemos a hacer una selección de los paises que empiezan
por «P», pero en su nombre, no en su código
# Lista de paises que empiezan por P, vacía al principio
lineas_P = []
ffoorr linea iin
n lineas:
codigo, nombre = linea.split(";")
i
iff nombre.startswith('P'):
lineas_P.append(linea)
# Abro el fichero donde voy a guardar
f_out = open("paises_P.txt", "w")
f_out.writelines(lineas_P)
f_out.close()
El fichero resultante es un fichero igual que el anterior pero solo con
los paises que empiezan con «P», uno por línea, pero es es línea a lí‐
nea porque el fichero original incluye caracteres de nueva línea. El
método writelines(lista) no escribe a líneas y éstas deben
añadirse explícitamente:
# Lista de numeros enteros, que paso a string y añado nueva lí
numeros = [str(n)+"\
\nn" f
foor
r n i
inn range(100)]
f_out = open("numeros.txt", "w")
f_out.writelines(numeros)
f_out.close()
Es posible guardar tambien variable en binario para usarlas después,
empleando shelve():
iimmppoorrtt s
shhe
ellvvee
shelf_file = shelve.open('datos')
shelf_file['numeros'] = numeros
shelf_file.close()
# Al cerrar el fichero se guardan los datos, que se pueden rec
shelf_file = shelve.open('datos')
shelf_file['numeros']
El módulo os tiene otros métodos útiles para interactuar con el siste‐
ma y los procresos que ejecuta.
os.getlogin()
#'japp'
os.getgroups()
#[191, 256, 294, 329, 350, 2000]
os.getenv('HOME')
os.putenv('HOME', '/scratch/japp')
os.uname()
# ('Linux', 'vega', '4.1.13-100.fc21.x86_64', '#1 SMP Tue Nov
Si se desea más información sobre el equipo, se puede emplear el
módulo platform, que da información más completa y detallada so‐
bre y ordenador y el SO:
iimmppoorrtt p
plla
attffoor
rmm
print('uname:', platform.uname())
print('system :', platform.system())
print('node :', platform.node())
print('release :', platform.release())
print('version :', platform.version())
print('machine :', platform.machine())
print('processor:', platform.processor())
print('distribution:', " ".join(platform.dist())
"""
uname: ('Linux', 'vega', '4.1.13-100.fc21.x86_64', '#1 SMP Tue
system : Linux
node : vega
release : 4.1.13-100.fc21.x86_64
version : #1 SMP Tue Nov 10 13:13:20 UTC 2015
machine : x86_64
processor: x86_64
distribution: fedora 21 Twenty One
"""
Si se desea mayor control sobre los ficheros y directorios, el módulo
shutil permite operaciones con ficheros a alto nivel.
improt shutil
shutil.copy('paises.csv', 'paises-copy.csv') # Copia un fiche
shutil.copytree("/home/japp/Documentos", "/home/japp/Documento
shutil.move('paises-copy.csv', '/home/japp/Documentos/'
¿Cómo borrar ficheros? Existen tres métodos principales:
os.unlink(path) # Borra el fichero en path
os.rmdir(path) # Borra el directorio en path, que debe
shutil.rmtree(path) # Borra path recursivamente
Si queremos borrar con más cuidado podemos usar condicionales:
ffoorr filename iin
n os.listdir("."):
iif
f filename.endswith('.csv'):
os.unlink(filename)
En el ejemplo anterior hemos hecho un listado sencillo del directorio
en el que estamos. Para hacer una exploración recursiva de un direc‐
torio, distinguiendo en ficheros y directorios, podemos usar
os.walk():
ffoorr directorio, subdirectorios, ficheros i
inn os
print('El directorio ' + directorio)
os.walk() devuelve una tupla de tres elementos con el nombre del
directorio actual, una lista de subdirectorios que contiene y una lista
de ficheros que contiene.
Con el módulo zip se pueden leer y escribir ficheros zip:
fichero_zip = zipfile.ZipFile('datos', 'w')
ficheros = ['medidas_PV_He.txt', 'medidas_radio.txt'
ffoorr fichero i
inn ficheros:
newZip.write(fichero, compress_type=zipfile
fichero_zip.close()
fichero_zip = zipfile.ZipFile("datos.zip")
fichero_zip.namelist()
# informacion sobre un fichero en concreto del zip
bright_star_info = fichero_zip.getinfo('bright_star.tsv'
bright_star_info.file_size
# 926482
bright_star_info.compress_size
# 248269
# Extraigo el contenido
fichero_zip.extract('bright_star.tsv', '/home/japp/Documents/'
fichero_zip.extractall() # todos los ficheros
fichero_zip.close()
Trabajando con fechas y tiempo
La librería estándar de Python incluye varios módulos para tratar y
manipular fechas, tiempo e intervalos. Como con otros módulos, una
vez importado el módulo se define un objeto específico que permite
hacer malabarismos con fechas y tiempo. El módulo principal es
datetime, que permite trabajar con fechas y tiempo mientras que el
módulo time, ofrece métodos avanzados para tiempo, ignorando la
fecha.
iimmppoorrtt d
daat
teettiim
mee
print("La fecha y hora actuales: " , datetime.datetime
print("Fecha y hora en string con formato: " ,
print("Año actual: ", datetime.date.today().strftime
print("Mes del año: ", datetime.date.today().strftime
print("Semana del año: ", datetime.date.today()
print("Número de día de la semana: ", datetime
print("Día del año: ", datetime.date.today().strftime
print("Día del mes: ", datetime.date.today().strftime
print("Día día de la semana: ", datetime.date.today
iimmppoorrtt t
tiim
mee
print("Segundos desde inicio de época: %s" %time
# Para una fecha específica
fecha = datetime.date(1937, 10, 8) #year, month, day
print(fecha.strftime("%A"))
# Friday
print(fecha.strftime("%b %d %Y %H:%M:%S"))
# Oct 08 1937 00:00:00
En el ejemplo anterior usamos el método strftime() para obtener
un string en el formato deseado según la sintaxis de fechas de Pyt‐
hon. De manera similar podemos usar strptime() para convertir
un string de fecha a un objeto date o datetime de Python:
# Fecha en string
fecha_str = "2017-05-16 10:30:00"
# Formato en el que está la fecha en string
fecha_fmt = "%Y-%m-%d %H:%M:%S"
# Objeto datetime a partir de la fecha en string
fecha = datetime.datetime.strptime(fecha_str, fecha_fmt
print(fecha.strftime("%A %d %B, %Y"))
# 'Tuesday 16 May, 2017'
# Cambio de idioma
iimmppoorrtt l
looc
caallee
idioma = locale.setlocale(locale.LC_TIME, "es_ES"
print(fecha.strftime("%A %d %B, %Y"))
# martes 16 mayo, 2017
# Intervalos de tiempo y operaciones con fechas
hoy = datetime.date.today()
print('Hoy:', hoy)
un_dia = datetime.timedelta(days=1)
print('Lapso de un día:', one_day)
ayer = hoy - un_dia
print('Ayer:', ayer)
manhana = hoy + un_dia
print('Manhana :', manhana)
print('Manhana - ayer:', manhana - ayer)
print('Ayer - manhana:', ayer - manhana)
ayer > hoy
FFaallssee
ayer < hoy
TTrruuee
Hay que tener en cuenta que los tiempos se toman de ordenador, in‐
cluyendo la zona horaria, por lo que generalmente serán en hora lo‐
cal. Si queremos convertir a otra zona horaria, debemos usar el mó‐
dulo ppyyttzz:
# Hora local canaria actual
hora_local = datetime.datetime.now()
# datetime.datetime(2017, 5, 12, 10, 30, 0, 379146)
# Hora actual en UTC
hora_utc = datetime.datetime.utcnow()
# datetime.datetime(2017, 5, 12, 9, 30, 0, 226718)
ffrroomm p
pyyt
tzz i
immp
poorrtt timezone
hora_us_pacific = hora_utc.replace(tzinfo=timezone
Finalmente, el módulo ccaalleennddaarr ofrece alguna funciones de calen‐
dario:
iimmppoorrtt c
caal
leenndda
arr
cal = calendar.month(2017, 5)
print(cal)
May 2017
Mo Tu We Th Fr Sa Su
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
print(calendar.TextCalendar(calendar.MONDAY).formatyear
Llamadas al sistema
La forma más sencilla de ejecutar comandos sistema, por ejemplo
para lanzar programas o ejecutar comandos de la consola es el mé‐
todo os.system()
iimmppoorrtt o
oss
os.system('touch /home/japp/Documents')
Sin embargo system() es muy limitado y no permite recoger el re‐
sultado la ejecución, de haberla. Mucho más útil y potente es el mó‐
dulo subprocess:
iimmppoorrtt s
suub
bpprrooc
cees
sss
# Uso básico similar a os.system()
subprocess.call(['ls', '-l'])
Puesto que los canales de entrada y salida del proceso call() es‐
tán ligados a la entrada y salida padre, no puede capturar la salida
del comando que ejecuta, como ocurre con os.system(). Si quere‐
mos capturar la salida podemos emplear check_output() y luego
procesar el resultado como queramos.
output = subprocess.check_output(['ps', '-x'])
print(output)
"""
PID TTY STAT TIME COMMAND
3901 ? S 0:00 sshd: invweb@pts/2
3902 pts/2 Ss 0:00 -bash
4248 pts/2 Sl 0:02 gedit cdb_import.py
4527 ? Sl 0:00 /usr/libexec/dconf-service
6134 ? Sl 0:15 /usr/local/apache//bin/httpd -k sta
13324 pts/2 Sl+ 0:00 /usr/bin/python /usr/bin/ipython
13613 pts/2 R+ 0:00 ps -x
26515 ? S 0:03 sshd: invweb@pts/0
26516 pts/0 Ss+ 0:00 -bash
"""
# Separo for filas
output_lines = output.split("\
\nn")
# Trozo que contiene el comando
output_lines[1][27:]
# Busco los procesos que usan Python
resultados = []
ffoorr line iin
n output_lines:
i
iff 'python' i
inn line.lower():
resultados.append(line[:5]) # Me quedo con trozo que
print(resultados)
Usando tuberías directamente podemos usar parámetros para indi‐
car la entrada y salida y capturar errores. Veamos este ejemplo de
una función que llama al ping del sistema:
ddeeff esta_viva(hostname):
"""
Hace un ping a una maquina para saber si esta conectada
"""
ping = subprocess.Popen(["ping", "-n", "-c 1"
out, error = ping.communicate()
iif
f error == "":
print("El ordenador {} está conectado"
r
reet
tuurrnn T
Trru
uee
eel
lsse
e:
print("El ordenador {} está KO".format(
r
reet
tuurrnn F
Faal
lssee
esta_viva('vega')
Conexión remota por FTP y SSH
La librería estándar de Python incluye un módulo ftp con todas las
funcionalidades necesarias. Veamos un ejemplo para copiar ficheros
locales al FTP público del IAC.
iimmppoorrtt fft
tppl
liibb
iimmppoorrtt oos
s
ffrroomm g gl
loob
b iimmppoorrtt glob
# Origen de los datos
origin_dir = "/home/japp/Documents/"
# directorio destino (en el servidor externo)
destination_dir = "in/curso_python"
# Lista de los ficheros a copiar, todos los *.py
files = glob(origin_dir + "*.py")
ftp = ftplib.FTP("ftp.iac.es")
login = ftp.login("[email protected]", "anonymous")
ftp.cwd(destination_dir)
os.chdir(origin_dir)
ffoorr filename i
inn files:
infile = open(filename, 'r')
ftp.storlines('STOR ' + os.path.basename(filename
infile.close()
Hay que fijarse que solo copia ficheros de uno en uno, si se quiere
copiar recursivamente hay que implementar una copia recursiva con
os.walk() o similar e ir creado directorios con mkdir().
No hay un módulo específico para ssh, pero se puede usar el del sis‐
tema usando el módulo pexpect, que permite manejar envío de in‐
formación entre un servidor y un cliente, en ambas direcciones.
iimmppoorrtt p
peex
xppeecct
t
iimmppoorrtt t
tiim
mee
host = "vega"
password = "secreto"
ssh_newkey = 'Are you sure you want to continue connecting'
ssh = pexpect.spawn("ssh {}".format(host))
i = ssh.expect([ssh_newkey, 'password:', host,
iiff i == 0:
ssh.sendline('yes')
# Se dan una lista de posibles salidas del comando: nueva
# la contraseña o el prompt del sistema si no pide contras
i = ssh.expect([ssh_newkey, 'password: $',
ssh.sendline(password)
ssh.expect(pexpect.EOF)
eelliiff i == 1:
ssh.sendline(password)
ssh.expect(pexpect.EOF, timeout=10)
eelliiff i == 2:
ppa
asss
s
# Extraemos el resultado del comando
p = pexpect.spawn("df -h")
print(p.read())
ssh.close()