miércoles, 12 de febrero de 2014

Operaciones con fechas y horas. Calendarios




Los módulos datetime y calendar amplían las posibilidades del módulo time que provee funciones para manipular expresiones de tiempo.

Al comienzo de un programa tendremos que importar estos módulos para tener acceso a un conjunto amplio de clases y funciones:

from datetime import datetime, date, time, timedelta
import calendar

Mostrar fecha y hora (datetime)


ahora = datetime.now()  # Obtiene fecha y hora actual
print("Fecha y Hora:", ahora)  # Muestra fecha y hora
print("Fecha y Hora UTC:",ahora.utcnow())  # Muestra fecha/hora UTC
print("Día:",ahora.day)  # Muestra día
print("Mes:",ahora.month)  # Muestra mes
print("Año:",ahora.year)  # Muestra año
print("Hora:", ahora.hour)  # Muestra hora
print("Minutos:",ahora.minute)  # Muestra minuto
print("Segundos:", ahora.second)  # Muestra segundo
print("Microsegundos:",ahora.microsecond)  # Muestra microsegundo

Comparando fechas y horas (datetime, date)


print("Horas:")
hora1 = time(10, 5, 0)  # Asigna 10h 5m 0s
print("\tHora1:", hora1)
hora2 = time(23, 15, 0)  # Asigna 23h 15m 0s
print("\tHora2:", hora2)

# Compara horas
print("\tHora1 < Hora2:", hora1 < hora2)  # True

print("Fechas:")
fecha1 = date.today()  # Asigna fecha actual
print("\tFecha1:", fecha1)

# Suma a la fecha actual 2 días
fecha2 = date.today() + timedelta(days=2)
print("\tFecha2:", fecha2)

# Compara fechas
print("\tFecha1 > Fecha2:", fecha1 > fecha2)  # False

Aplicando formatos a fechas y horas (Máscaras)


Las siguientes claves se combinan para aplicar formatos:

%a Nombre local abreviado de día de semana
%A Nombre local completo de día de semana
%b Nombre local abreviado de mes
%B Nombre local completo de mes
%c Representación local de fecha y hora
%d Día de mes [01,31]
%H Hora (horario 24 horas) [00,23]
%I Hora (horario 12 horas) [01,12]
%j Número de día del año [001,366]
%m Mes [01,12]
%M Minuto [00,59]
%p Etiqueta AM o PM
%S Segundo
%U Nº semana del año. Se considera al Domingo como primer día de semana [00,53]
%w Establece el primer día de semana [0(Domingo),1(Lunes)... 6].
%W Nº semana del año (Se considera al Lunes como primer día de semana) [00,53]
%x Fecha local
%X Hora local
%y Año en formato corto [00,99]
%Y Año en formato largo
%Z Nombre de Zona Horaria


Ejemplos:

# Asigna formato de ejemplo1
formato1 = "%a %b %d %H:%M:%S %Y"

# Asigna formato de ejemplo2
formato2 = "%d-%m-%y %I:%m %p"

hoy = datetime.today()  # Asigna fecha-hora

# Muestra fecha-hora según ISO 8601
print("Fecha en formato ISO 8601:", hoy)

# Aplica formato ejemplo1
cadena1 = hoy.strftime(formato1)  

# Aplica formato ejemplo2
cadena2 = hoy.strftime(formato2)  

# Muestra fecha-hora según ejemplo1
print("Formato1:", cadena1)

# Muestra fecha-hora según ejemplo2
print("Formato2:", cadena2)

Para convertir una cadena a objeto datetime


objeto_datetime = datetime.strptime(cadena1, formato1)
print("strptime:", fecha1.strftime(formato1))

Operaciones con fechas y horas


Se utiliza la función timedelta que permite operar con: microseconds, milliseconds, seconds, minutes, hours, days y weeks

hoy = date.today()  # Asigna fecha actual
ayer = hoy  timedelta(days=1)  # Resta a fecha actual 1 día
mañana = hoy + timedelta(days=1)  # Suma a fecha actual 1 día
diferencia_en_dias = mañana  hoy  # Resta las dos fechas

Otros ejemplos de operaciones con otras unidades de tiempo


hoy_mas_1_millon_segundos = hoy + timedelta(seconds=1000000)
ahora = datetime.now() 
hora_actual = time(ahora.hour, ahora.minute, ahora.second)
mas_5m = ahora + timedelta(seconds=300)
mas_5m = time(mas_5m.hour, mas_5m.minute, mas_5m.second)
racion_de_5h = timedelta(hours=5)
mas_5h = ahora + racion_de_5h

print("Ayer:", ayer)
print("Hoy:", hoy)
print("Mañana:", mañana)
print("Diferencia en días entre mañana y hoy:", 
      diferencia_en_dias.days)
print("La fecha de hoy más 1 millón de segundos:", 
      hoy_mas_1_millon_segundos)
print("Hora actual:", hora_actual)
print("Hora actual + 5 minutos:", mas_5m)
print("Hora actual + 5 horas:", mas_5h)

Diferencia entre dos fechas (datetime)


# Asigna datetime de la fecha actual
fecha1 = datetime.now()

# Asigna datetime específica
fecha2 = datetime(1995, 11, 5, 0, 0, 0)
diferencia = fecha1 - fecha2
print("Fecha1:", fecha1)
print("Fecha2:", fecha2)
print("Diferencia:", diferencia)
print("Entre las 2 fechas hay ", 
      diferencia.days, 
      "días y ", 
      diferencia.seconds, 
      "seg.")

Diferencia entre dos fechas en días (datetime y strptime)


formato_fecha = "%d-%m-%Y"
fecha_inicial = datetime.strptime("01-10-2013", 
                                  formato_fecha)
fecha_final = datetime.strptime("25-12-2013", 
                                formato_fecha)
diferencia = fecha_final - fecha_inicial
print("Fecha inicial:", fecha_inicial)
print("Fecha final:", fecha_final)
print("Diferencia:", diferencia.days, "días")

Diferencia de dos fechas en días, introducidas por teclado


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  diferencia-entre-fechas-teclado.py
#
#  Diferencia de dos fechas en días introducidas por teclado,
#  con control de errores.
#

from datetime import datetime

def main():
 # Establecer formato de las fechas a introducir: dd/mm/aaaa
 
 formato = "%d/%m/%Y"
 
 # Bucle 'sin fin' 
 
 while True:
  try:
   # Introducir fecha inicial utilizando el formato definido
   
   fecha_desde = input('Introducir fecha inicial (dd/mm/aaaa): ')   
   
   # Si no se introduce ningún valor se fuerza el final del bucle 
   
   if fecha_desde == "":
    break
   
   # Introducir fecha final utilizando el formato definido   
   
   fecha_hasta = input('Introducir fecha final   (dd/mm/aaaa): ') 

   # Si no se introduce ningún valor se fuerza el final del bucle 
   
   if fecha_hasta == "":
    break
   
   # Se evaluan las fechas según el formato dd/mm/aaaa
   # En caso de introducirse fechas incorrectas se capturará
   # la excepción o error
   
   fecha_desde = datetime.strptime(fecha_desde, formato)
   fecha_hasta = datetime.strptime(fecha_hasta, formato)
   
   # Se comprueba que fecha_hasta sea mayor o igual que fecha_desde
   
   if fecha_hasta >= fecha_desde:
    
    # Se cálcula diferencia en día y se muestra el resultado
    
    diferencia = fecha_hasta - fecha_desde
    print("Diferencia:", diferencia.days, "días")
    
   else:
    print("La fecha fecha final debe ser mayor o igual que la inicial")
   
  except:
   print('Error en la/s fecha/s. ¡Inténtalo de nuevo!')
   
 return 0

if __name__ == '__main__':
 main()

A partir de una hora se obtiene fracción del día


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# A partir de una hora introducida por teclado se obtiene
# fracción del día, teniendo en cuenta que 24 horas = 86400 seg
# Formato de entrada: hh:mm:ss
# Valores Hora...: 0 a 23
# Valores Minuto.: 0 a 59
# Valores Segundo: 0 a 59

from datetime import datetime
formato = "%H:%M:%S"

while True:
 try:
  hhmmss = input('Introducir hora (hh:mm:ss): ')
  if hhmmss == "":
   break
  
  hhmmss = datetime.strptime(hhmmss, formato)
  horas = hhmmss.hour
  minutos = hhmmss.minute
  segundos = hhmmss.second
  hhmmss_seg = (horas * 60 * 60) + (minutos * 60) + segundos 
  resultado = float(hhmmss_seg / 86400)
  print("Resultado: ", resultado)
 
 except:
  print('Error en el formato de hora introducido.')
  print('-> Formato válido: hh:mm:ss  ¡Inténtalo de nuevo!')

Diferencia de dos fechas (date)


hoy = date.today()
navidad_año_proximo = date(2024, 12, 25)
faltan = navidad_año_proximo - hoy
print ("Hoy:", hoy)
print ("La navidad del 2024", navidad_año_proximo)
print ("Faltan", faltan.days, "días")

Expresar una fecha en formato largo


print("Hoy es...", datetime.ctime(fecha1))

A partir de una fecha se obtiene tupla con año, nº semana y día de semana


print("Fecha", fecha1, 
      "Año, nº sem., día sem.:", 
      datetime.isocalendar(fecha1))

A partir de una fecha se obtiene tupla con año, nº semana y día de semana


También, se muestra el día de la semana en letras (abreviado).

print("Desglose de la fecha", fecha2,":")
tupla_mensajes = ("Año", "Núm. semana", "Núm. día de semana")
tupla_valores = datetime.isocalendar(fecha2)
tupla_diassem = ("Lun", "Mar", "Mié", "Jue","Vie", "Sáb","Dom")
for mensaje,valor in zip(tupla_mensajes, tupla_valores):
 print(mensaje,"-->", valor)
 
print("Día de semana-->", tupla_diassem[tupla_valores[2]-1])

Obtener día de la semana por su número 


La función weekday() devuelve el número de día de la semana a que corresponda la fecha indicada, según los siguientes valores por día:  0-Lunes, 1-Martes, 2-Miércoles, 3-Jueves, 4-Viernes , 5-Sábado y 6-Domingo

dia_semana = datetime.weekday(fecha1)
print(fecha1, "->", dia_semana,"->", 
      tupla_diassem[dia_semana])

Obtener y contar los días que sean martes entre dos fechas


from datetime import datetime, timedelta

formato = "%d/%m/%Y"
contador = 0            
fechadesde = input('Fecha desde (dd/mm/aaaa): ')
fechahasta = input('Fecha hasta (dd/mm/aaaa): ')
if fechadesde == '' or fechahasta == '':
    exit()

try:                    
    fechadesde = datetime.strptime(fechadesde, formato)
    fechahasta = datetime.strptime(fechahasta, formato)    
    if fechadesde > fechahasta:
        print('Fecha desde debe ser menor o igual que hasta')
    
    while fechadesde <= fechahasta:
        if datetime.weekday(fechadesde) == 1: 
            contador +=1
            fechaactual = fechadesde.strftime(formato)
            print(contador, fechaactual, 'es martes')
        fechadesde = fechadesde + timedelta(days=1)
                
except:
    print('Fecha incorrecta')

Obtener día de la semana por su número


La función isoweekday() devuelve el número de día de la semana a que corresponda la fecha indicada, según los siguientes valores por día:  1-Lunes, 2-Martes, 3-Miércoles, 4-Jueves, 5-Viernes, 6-Sábado y 7-Domingo.

dia_semana = datetime.isoweekday(fecha1)
print(fecha1, "->", dia_semana,"->", 
      tupla_diassem[dia_semana-1])

Dado el ordinal se obtiene la fecha correspondiente


print("Si la fecha 01-01-0001 tiene el ordinal 1 entonces...")
for num in range(1,7):
    print("El día", 10 ** num , 
          "se corresponde con", 
          date.fromordinal(10 ** num))

Dada una fecha se obtiene un ordinal (01-01-0001 -> 1)


fecha3 = datetime(1, 1, 1, 0, 0, 0)
print("La fecha", fecha3, 
      "tiene el ordinal", 
      date.toordinal(fecha3))
print("La fecha", fecha1, 
      "tiene el ordinal", 
      date.toordinal(fecha1))

Obtener una tupla a partir de fecha-hora (datetime)


tupla_fechahora = fecha1.timetuple()
for elemento in tupla_fechahora:
 print(elemento)

Convertir un ordinal en fecha-hora (fromtimestamp)


El ordinal 0 se corresponde con la fecha -> 1-1-1970 01:00:00

print("Ordinal 0 -> 1-1-1970 01:00:00")
ordinales_tiempo = (0, 1, 2, 60, 3600)
for elemento in ordinales_tiempo:
    print(elemento, "->" , datetime.fromtimestamp(elemento))

Obtener calendario del mes actual (calendar.month)


año = date.today().year 
mes = date.today().month
calendario_mes = calendar.month(año, mes)
print(calendario_mes)

Obtener calendario del mes actual (calendar.TextCalendar)


Se establece el lunes como primer día de la semana

calendario = calendar.TextCalendar(calendar.MONDAY)
calendario.prmonth(año, mes)

Obtener matriz con calendario de mes actual: (Calendar monthdayscalendar)


calendario = calendar.Calendar()
for elemento in calendario.monthdayscalendar(año, mes):
    print(elemento)

Obtener matriz de tuplas con calendario: (Calendar monthdays2calendar)


El primer valor de cada par es el número de día del mes y el segundo valor se corresponde con el número de día de la semana: 0:lunes, 1:martes, 2:miércoles, etc.

calendario = calendario.monthdays2calendar(año, mes)
for elemento in calendario:
    print(elemento)

Calendario completo del año 2018


Día de comienzo: Lunes

print(calendar.TextCalendar(calendar.MONDAY).formatyear(2018, 
                                                        2, 1, 1, 2))


Relacionado:

Ir al índice del tutorial de Python

Capturar usuario actual e introducir contraseña (no visible)


El módulo getpass puede emplearse para capturar en un sistema el nombre de usuario actual y para introducir desde teclado una contraseña sin que ésta sea visible.

import getpass

# Captura usuario actual del sistema
usuario = getpass.getuser()  

# Permite introducir una contraseña (no visible)
password = getpass.getpass()  

print(usuario, password)

Generar un archivo log

Crear un fichero log para una aplicación con funciones del módulo logging.

import os, platform, logging

if platform.platform().startswith('Windows'):
    fichero_log = os.path.join(os.getenv('HOMEDRIVE'), 
                               os.getenv("HOMEPATH"),
                               'test.log')
else:
    fichero_log = os.path.join(os.getenv('HOME'), 'test.log')

print('Archivo Log en ', fichero_log)
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s : %(levelname)s : %(message)s',
                    filename = fichero_log,
                    filemode = 'w',)
logging.debug('Comienza el programa')
logging.info('Procesando con normalidad')
logging.warning('Advertencia')

Ejemplo de salida de test.log:

2013-01-01 20:38:44,235 : DEBUG : Comienza el programa
2013-01-01 20:38:44,236 : INFO : Procesando con normalidad
2013-01-01 20:38:44,237 : WARNING : Advertencia

Advertencias con el módulo warnings

Si la versión de un programa está por debajo de la 3 genera un “warning” personalizado.

import sys, warnings

if sys.version_info.major < 3:
    warnings.warn('Necesitas Python 3.0', RuntimeWarning)
else:
    print('Tiene la versión de Python adecuada')

Ejecutar un comando externo

A continuación, se muestran varias posibilidades para ejecutar comandos externos desde un programa Python:

#!usr/bin/env Python
# -*- coding: utf-8 -*-

import os, sys
import subprocess

# Ejecutar un comando con "os.system(comando)" y mostrar en
# pantalla la salida del comando y el resultado de la 
# ejecución.
# Si su valor es 0 la ejecución finalizó con éxito.

valor1 = os.system("whoami")
print("Resultado:", valor1)

# Ejecutar un comando "erróneo" con "os.system(comando)"

valor2 = os.system("whoamix")
print("Resultado:", valor2)

# Ejecutar varios comandos con "os.system(comando)"

comando3 = "ls -l | grep 'txt' >textos.txt"
valor3 = os.system(comando3)
print("Resultado:", valor3)

# Ejecutar un comando con "os.popen(comando)" y capturar su 
# salida

comando4 = "uname -srmo"
salida4 = os.popen(comando4).read()
print("Salida:\n", salida4)

# A continuación, se muestran varios ejemplos con el módulo 
# "subprocess" que genera un nuevo proceso para ejecutar el
# comando permitiendo controlar su ejecución y obtener su 
# salida y/o errores que pudieran darse.

# Ejecutar un comando externo con "subprocess.call", mostrar 
# su salida y el resultado de su ejecución.

valor5 = subprocess.call(["ping", "-c 6", "www.elpais.es"])
print("Este texto se mostrará después de ejecutar el comando")
print("Resultado:", valor5)

# Ejecutar un comando externo en paralelo con 
# "subprocess.Popen" con wait() se espera a que termine
# la ejecución del subproceso
# Todas las líneas de código delante de wait() se 
# ejecutarán en paralelo a la ejecución del comando.
# También, se mostrará si la ejecución terminó o no
# con éxito

proceso6 = subprocess.Popen(['ls', '-lha'])
for num in range(100):
    print ("Este texto se mostrará antes")

valor6 = proceso6.wait()
print ("Este texto se mostrará después")
print ("Resultado:", valor6)

# Ejecutar un comando externo en paralelo con
# "subprocess.Popen"

proceso7 = subprocess.Popen(['ls', '-lha'])
for num in range(300):
    print ("Este texto se mostrará en paralelo")

# Ejecutar un comando en paralelo con 
# "subprocess.Popen" y capturar su salida y
# los errores que puedieran darse

proceso8 = subprocess.Popen(['ls', '-a'], 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE)
errores8 = proceso8.stderr.read()
salida8 = proceso8.stdout.read()
proceso8.stderr.close()
proceso8.stdout.close()
print("Salida de errores:\n")
errores8 = errores8.decode(sys.getdefaultencoding())
print(errores8)
salida8 = salida8.decode(sys.getdefaultencoding())
print("Salida del comando:\n")
print(salida8)

# Ejecutar un comando externo con "subprocess.Popen" y 
# obtener su salida y los errores que puedan darse (Otra 
# manera de hacerlo)
# En el ejemplo se provoca un error y se muestra el texto
# de su salida

proceso9 = subprocess.Popen(["ping", 
                            "-zz 4", 
                            "www.elpais.es"], 
                            stdout=subprocess.PIPE)
salida9, errores9 = proceso9.communicate()
print(salida9.decode(sys.getdefaultencoding()))
if errores9 != None:
    print(errores9.decode(sys.getdefaultencoding()))

# Para resolver variables de entorno, patrones globales y
# otras caracteristicas de la shell hay que incluir el 
# parámetro "shell = True"

print("Correcto  : subprocess.call('echo $HOME', shell=True)")
print("Incorrecto: subprocess.call('echo $HOME')")
# Es equivalente a shell = False

subprocess.call('echo $HOME', shell=True)

# Ejecutar un comando externo con subprocess.Popen() y
# obtener su salida en tiempo real

comando11 = "ping -c3 www.elpais.es"
resultado11 = subprocess.Popen(comando11, 
                               shell=True, 
                               stdout=subprocess.PIPE)
for salida11 in resultado11.stdout:
    print(salida11.decode(sys.getdefaultencoding()).rstrip())

# Ejecutar un comando externo con subprocess.Popen()
# y obtener la salida en tiempo real (Otra forma de
# hacerlo)

comando12 = "ping -c2 www.elpais.es"
resultado12 = subprocess.Popen(comando12, 
                               shell=True, 
                               stdout=subprocess.PIPE)
while resultado12.poll() is None:
    salida12 = resultado12.stdout.readline()
    print(salida12.decode(sys.getdefaultencoding()).rstrip())


Ir al índice del tutorial de Python

Ejecutar programas con argumentos

Desde la línea de comandos se puede ejecutar un programa con argumentos separándolos con espacios. Tanto el nombre del programa que se ejecuta como los argumentos pasados estarán accesibles con argv del módulo estándar sys.

Si creamos un programa llamado programa.py con el siguiente contenido:

import sys
if(len(sys.argv) > 2):
    print "El nombre del programa es " + sys.argv[0]
    print "El primer parámetro es " + sys.argv[1]
    print "El segundo parámetro es " + sys.argv[2]
else:
    print "Necesario ejecutar con al menos dos parámetros"
    print "python programa.py param1 param2"

Para ejecutarlo con argumentos desde la línea de comandos:

python3 programa.py argumento1 argumento2


martes, 11 de febrero de 2014

Bases de datos SQLite3


SQLite es un sistema de gestión de base de datos de tipo relacional. Es un proyecto de dominio público creado por D. Richard Hipp que ofrece un gestor de base de datos liviano y robusto; y accesible desde programas escritos en los lenguajes de programación más populares. Algunos de ellos lo tienen embebido y no requieren la instalación de software adicional. Hay programas como Firefox, Opera, Skype, Clementine, OpenOffice y otros que utilizan SQLite.

En este blog hay una Guía Rápida de SQLite para conocer sus fundamentos.

También, en el sitio oficial de SQLite hay abundante documentación y en otros sitios hay herramientas gráficas como SQLiteman y Sqlite Database Browser que facilitan mucho el trabajo con las bases de datos.
.
En Python 3 el módulo sqlite3 permite crear bases de datos y operar con tablas y registros. Para ello, es necesario importar dicho módulo:

import sqlite3


A continuación, basándonos en ejemplos, mostraremos las operaciones más comunes sobre una base de datos SQLite. Antes, crearemos la base de datos y una tabla desde la línea de comandos.

Crear base de datos


sqlite3 contactos.db

Crear tabla


sqlite3 CREATE TABLE agenda (ident INTEGER PRIMARY KEY, nombre VARCHAR(30) UNIQUE, ecorreo VARCHAR(40), telefono INT(9));

Iniciar y cerrar una conexión con la base de datos


con_bd = sqlite3.connect('contactos.db')
con_bd.close()

Declarar y cerrar un cursor


cursor_agenda = con_bd.cursor()
cursor_agenda.close()

Añadir registro a la tabla agenda


reg = (1, "A", "a@a.a", 1)
cursor_agenda.execute("INSERT INTO agenda VALUES(?,?,?,?)", reg)

Completar la transacción de inserción de registro


con_bd.commit()

Consultar todos los registros de la tabla agenda


cursor_agenda.execute("SELECT * FROM agenda")
for registro in cursor_agenda:
    print(registro)

Consultar registro con parámetro


par = (1,)
cursor_agenda.execute("SELECT * FROM agenda WHERE ident=?", par)
for registro in cursor_agenda:
    print(registro)

Consultar los registros, uno a uno, con fetchone()


cursor_agenda.execute("SELECT * FROM agenda WHERE ident>?", par)
registro = cursor_agenda.fetchone() # Lee el primer registro
print(registro)

Consultar un nº de registros concretos con fetchmany()


par = (0,)
cursor_agenda.execute("SELECT * FROM agenda WHERE ident>?", par)
registros = cursor_agenda.fetchmany(2)  # 2 registros
for registro in registros: print(registro)

Consultar todos los registros, con fetchall()


cursor_agenda.execute("SELECT * FROM agenda WHERE ident>?", par)
registros = cursor_agenda.fetchall()
for registro in registros:
    print(registro)

Mostrar los campos de un registro por su posición


par = (2,)
cursor_agenda.execute("SELECT * FROM agenda WHERE ident=?", par)
for campo in cursor_agenda:
    print("Identificador:", campo[0])
    print("Nombre.......:", campo[1])

Consultar registros por nombre de campos


con_bd = sqlite3.connect("contactos.db")
con_bd.row_factory = sqlite3.Row
cursor_agenda = con_bd.cursor()
cursor_agenda.execute("SELECT * FROM agenda WHERE ident=?", par)
registro = cursor_agenda.fetchone()
print("Nombre", registro['nombre'])
print("Correo", registro['ecorreo'])

Borrar registro


values = (1,)
cursor_agenda.execute('DELETE FROM agenda WHERE ident=?',
                      values)
con_bd.commit()

Modificar campos


cursor_agenda.execute("UPDATE agenda SET ecorreo='a@b' WHERE ident=3")
con_bd.commit()

Deshacer modificación


con_bd.rollback()




Relacionado:


Ir al índice del tutorial de Python

domingo, 9 de febrero de 2014

Expresiones Regulares. Módulo re

El módulo re cuenta con funciones para trabajar con expresiones regulares y cadenas.

La función match()


La función match comprueba si una expresión regular tiene coincidencias con el comienzo de una cadena de texto. Se basa en el siguiente formato:

match(expresiónregular, cadena, [flag])

Valores de flag:

flag re.IGNORECASE:  No se hará diferencia entre mayúsculas y minúsculas
flag re.VERBOSE:  Los comentarios y espacios son ignorados (en la expresión).

import re
cadena1 = 'casa'
cadena2 = 'casas'
cadena3 = 'pasa'

if re.match(cadena1, cadena2):
    print('cadena1 y cadena2 son coincidentes')
else:
    print('cadena1 y cadena2 no son coincidentes')
 
if re.match(cadena1, cadena3):
    print('cadena1 y cadena3 son coincidentes')
else:
    print('cadena1 y cadena3 no son coincidentes')

Comodines


Con match el punto “.” actúa como un comodín para un solo carácter y representa a cualquier carácter, excepto \n 

import re
if re.match('.asa', cadena1) and re.match('.asa', cadena3):
    print('cadena1 y cadena3 terminan en .asa')
else:
    print('cadena1 y cadena3 no terminan en .asa')

Carácter especial


Cualquier carácter especial se escribirá detrás de una barra invertida “\”. Por ejemplo, para expresar el carácter punto y no el comodín lo indicaremos escribiendo \.

import re
extension = '\.jpg'
if re.match(extension, '.jpg') != None:
    print('El archivo es una imagen jpg')

Alternativas


La barra vertical “|” expresa distintas alternativas que podrán darse para que se cumpla la expresión.

import re
extensiones = ['jpg', 'png', 'gif', 'mp3', 'doc']

for tipoarchivo in extensiones:
    if re.match('jpg|png|gif|bmp', tipoarchivo):
        print('La extensión ', tipoarchivo, 'se corresponde con una imagen')
    else:
        print('La extensión ', tipoarchivo, 'no se corresponde con una imagen')

Grupos aislados


Los paréntesis “()” permiten aislar un grupo de caracteres que pueden ser distintos.

import re

palabras = ['careta', 'carpeta', 'colita', 'cateta', 'cocreta', 'caleta', 'caseta']
for termino in palabras:
    if re.match('ca(..|...)ta', termino):
        print(termino)  # careta , carpeta, cateta, caleta, caseta 

maspalabras = ['masa', 'mata', 'mar', 'mana','cama', 'marea']
for termino in maspalabras:
    if re.match('ma(s|m|n)a', termino):
        print(termino)  # masa, mana

Rangos


Los corchetes “[]” se emplean para expresar rangos de numeros, alfabéticos y de otros caracteres especiales.

import re
codigos = ['se1', 'se9', 'ma2', 'se:','se.', 
           'se2', 'hu2', 'se3', 'sea', 'sec']

for elemento in codigos:
    if re.match('se[0-5]', elemento):  # el 3er carácter puede ser nº de 0-5
        print(elemento)

for elemento in codigos:
    if re.match('se[0-5a-z]', elemento):  # nº de 0 a 5 y letra de a a z
        print(elemento)

for elemento in codigos:
    if re.match('se[.:]', elemento):  # el tercer carácter puede ser . ó :
        print( elemento)

for elemento in codigos:
    if re.match('se[^0-2]', elemento):  # debe comenzar por nº de 0 a 2 
        print(elemento)

Caracteres predefinidos


\d  Cualquier carácter que sea dígito
\D  Cualquier carácter que no sea dígito
\w  Cualquier carácter alfanumérico
\W  Cualquier carácter no alfanumérico
\s  Espacio en blanco
\S  Cualquier carácter que no sea espacio

import re
for elemento in codigos:
    if re.match('se\d', elemento):  # el 3er carácter debe ser número
        print( elemento)

Caracteres que permiten repeticiones


+  El carácter de la izquierda aparecerá una o varias veces
*  El carácter de la izquierda aparecerá cero o más veces
?  El carácter de la izquierda aparecerá cero o una vez
{}  Indica el número de veces que debe aparecer el carácter de la izquierda:

{3} 3 veces; {1,4} de 1 a 4; {,3} de 0 a 3; {2,} dos o más veces

import re
codigos = ['aaa111', 'aab11', 'aaa1111', 'aaz1', 'aaa'] 

for elemento in codigos:
    if re.match('aa[a-z]1{2,}', elemento):
        print(elemento)  # aaa111 , aab11, aaa1111

for elemento in codigos:
    if re.match('a+1+', elemento):
        print(elemento)  # aaa111 , aaa1111 

El objeto mo y el método group()


El método group del objeto mo devuelve la cadena encontrada o produce excepción

import re
mo = re.match('ftp://.+\com', 'ftp://ovh.com')
print(mo.group())  # ftp://ovh.com 

Con los paréntesis acotamos los grupos:

import re
mo = re.match('ftp://(.+)\com', 'ftp://ovh.com')
print(mo.group(0))  # ftp://ovh.com 
print(mo.group(1))  # ovh. 
print(mo.groups())  # ('ovh.',). 

La función search()


La función search es como match pero busca coincidencias de un patrón en una cadena de texto y dichas coincidencias pueden aparecer en cualquier lugar. Su formato es: search(patrón, cadena, [flag]) 

import re
palabras = ['paniaguado', 'agüita', 'aguador', 
            'paraguas', 'agua'] 

for elemento in palabras:
    if re.search('agua', elemento):
        print( elemento) # paniaguado, aguador, paraguas, agua 

Coincidencias al comienzo y al final


Busca una subcadena al ^ COMIENZO o al $ FINAL de una cadena:

import re
lista_url = ['http://www.aaa.es',
             'ftp://www.aaa.es',
             'http://www.bbb.es']
for elemento in lista_url:
    if re.search('^ftp://', elemento):
        print(elemento)  # ftp://www.aaa.es

lista_dom = ['.com', '.es']
for elemento in lista_dom:
    if re.search('es$', elemento):
        print(elemento)  # .es

Métodos start() y end()


El método start() devuelve la posición inicial y el método end() la final, si la subcadena está en la cadena.

import re
mo1 = re.search('agua', 'paraguas')
print(mo1.start())  # devuelve 3
print(mo1.end())  # devuelve 7

La función findall()


La función findall() devuelve una lista con las subcadenas que cumplen el patrón en una cadena. El formato que utiliza es: findall(patrón, cadena, [flag])

cadena = 'tengo una yama que yama se llama'
lista = re.findall('..ama', cadena)
print(lista)  # muestra: [' yama', ' yama', 'llama']

La función finditer()


La función finditer() permite usar un iterador para recorrer las subcadenas que cumplen el patrón. El resultado son tuplas con las posiciones de las subcadenas.

cadena = 'tengo una yama que yama se llama'
iterador = re.finditer('ama', cadena)
for encontrado in iterador:
    print(encontrado.span())  # (11, 14) , (20, 23) , (29, 32)

La función compile()


La función compile() se utiliza para compilar una expresión regular, devolviendo un objeto especial llamado RegexObject. La compilación es un paso previo que conlleva la evaluación del patrón que indiquemos en la función; que después utilizaremos con las funciones split(), sub(), subn() y otras. 

Es importante señalar que la mayoría de las operaciones con expresiones regulares que están disponibles como métodos compilados a nivel de módulo,  están también como funciones, con algunas diferencias en sus parámetros. Las funciones son atajos que no requieren el paso de la compilación.

La función sub() con compilación


La función sub() busca y sustituye cadenas usando el siguiente formato:

sub(cadenaparasustituir, cadenadondesebusca, [count=número])

En el ejemplo siguiente se declara una clave y todos sus caracteres no numéricos se sustituyen por "0":

import re
clave = "asdb92z$"

# \D se refiere a cualquier carácter que no es número 
patron = re.compile("\D")   

# Se sustituyen los caracteres encontrados por "0"
nueva_clave = patron.sub("0", clave)

print(nueva_clave)  # 00009200

# Para motrar el tipo de objeto de "patron":
orint(type(patron))

# Otra forma de expresarlo:
nueva_clave = re.compile("\D").sub("0", clave)

Otros ejemplos

import re
oracion = 'la norma es la norma'
patron = re.compile('norma') 
print(patron.sub('ley', oracion))  # la ley es la ley

patron = re.compile('la') 
print(patron.sub('LA', oracion, count=1))
# LA norma es la norma

La función subn() con compilación


La función subn() es como sub() pero devuelve una tupla con dos valores: el primero contiene la cadena resultado después de aplicar las sustituciones y en el segundo el número de sustituciones realizadas.

En el siguiente ejemplo en vez de utilizar el patrón "\D" se emplea "\d" que se refiere a todos los caracteres numéricos. Dicho patrón se utilizará para sustituir todos los caracteres numéricos por el caracter "x":

clave = "asdb92z$"
patron = re.compile("\d")
tupla_resultado = patron.subn("x", clave)
print(tupla_resultado[0])   # asdbxxz$
print(tupla_resultado[1])   # 2

La función split() con compilación


La función split() divide una cadena en subcadenas: split(cadena, [maxsplit=0])
 
import re
meses = 'ene+feb+mar+abr+may+jun'

patron = re.compile('\+')
print(patron.split(meses))  
# ['ene', 'feb', 'mar', 'abr', 'may', 'jun']

patron = re.compile('\+')
print(patron.split(meses, maxsplit=1))  
# ['ene', 'feb+mar+abr+may+jun']


Ir al índice del tutorial de Python

Acercamiento a la biblioteca estándar.


Módulos os, sys, time


A lo largo de la presente guía se utilizan funciones que pertenecen a módulos de la biblioteca estándar de Python. Se recomienda el uso del programa pydoc3 desde la línea de comandos para acceder a la documentación (docstrings) de los mismos.

Listar los módulos disponibles:

$ pydoc3 modules

Mostrar la documentación del módulo os:

$ pydoc3 os

Mostrar la documentación de la función dir:

$ pydoc3 dir

A continuación, se relacionan una selección de funciones de los módulos os, sys, time.

import os, sys, time

# Devuelve si es posible acceder a archivo/directorio
os.access(ruta, modo-acceso)

# Devuelve el directorio actual de trabajo  
os.getcwd()

# Cambia directorio trabajo
os.chdir('/dir1/dir2')  

# Cambia permisos a un archivo
os.chmod(path, mode)

# Cambia propietario de un archivo 
os.chown(path, uid, gid)

# Cambia al directorio raíz
os.chroot(path)

# Devuelve número de CPUs del sistema
os.cpu_count()

# Devuelve el directorio actual 
os.curdir

# Devuelve el directorio padre del directorio actual
os.pardir

# Devuelve nombre del archivo del terminal
os.ctermid()

# Devuelve ruta del dispositivo nulo
os.devnull

# Devuelve diccionario con variables de entorno
os.environ.iteritems()

# Devuelve id usuario real del proceso actual (Unix)
os.getuid()

# Devuelve id grupo real del proceso actual (Unix)
os.getgid()

# Devuelve id usuario efectivo del proceso actual (Unix)
os.geteuid()

# Devuelve id grupo efectivo del proceso actual (Unix)  
os.getegid()

# Devuelve lista grupos suplementarios del proceso actual (Unix)
os.getgroups()

# Devuelve id del proceso actual  
os.getpid()  

# Obtiene valor de variable de entorno
os.getenv(key, default=None)

# Devuelve nombre usuario actual  
os.getlogin()

# Lista contenido de directorio 
listado = os.listdir('/home')

# Crea subdirectorio
os.mkdir(path [,mode=511])

# Crea directorios recursivamente
os.makedirs(path[, modo])

# Devuelve path absoluto de archivo/directorio
os.path.abspath(path)

# Devuelve ruta completa del fichero actual  
os.path.abspath(__file__)

# Devuelve directorio base
os.path.basename(path)  

# Devuelve directorio del archivo/directorio
os.path.dirname(path)

# Comprueba si existe fichero/directorio
os.path.exists(path)

# Devuelve fecha/hora de último acceso a archivo/dir 
os.path.getatime(path)

# Obtiene el tamaño de un archivo/directorio  
os.path.getsize(path)

# Devuelve si una ruta es absoluta
os.path.isabs(path)

# Devuelve si la ruta es un archivo  
os.path.isfile(path)

# Devuelve si la ruta es un directorio
os.path.isdir(path)

# Devuelve directorio completo del archivo (desde cualquier directorio)
os.path.dirname(os.path.realpath(__file__))

# Devuelve si la ruta es un enlace simbólico
os.path.islink(path)

# Devuelve si la ruta es un punto de montaje
os.path.ismount(path)

# Devuelve tupla con nombre de archivo y extensión
os.path.splitext(archivo)

# Modifica/Añade variable de entorno
os.putenv(key, value)

# Borra un archivo
os.remove(path)

# Elimina directorios recursivamente
os.removedirs(path) 

# Renombrar un archivo o directorio 
os.rename(old, new)

# Renombra recursivamente 
os.renames(old, new)

# Borra un subdirectorio
os.rmdir(path)

# Crea enlace duro 
os.link(src, dst)

# Crea enlace simbólico
os.symlink(path, nombre-destino) 

# Devuelve la ruta a que apunta enlace simbólico 
os.readlink(path)

# Devuelve estado o descriptor de archivo 
os.stat(path)

# Devuelve separador utilizado en ruta  
os.sep

# Devuelve separador de extensión
os.extsep

# Devuelve separador de líneas
os.linesep

# Separador usado para expresar varias rutas
os.pathsep

# Ejecuta un comando externo  
os.system('ls')

# Muestra información del sistema
os.uname()

# Muestra nombre del sistema
os.uname().sysname  
# Otros atributos: nodename, release, version y machine

# Borra una variable de entorno
os.unsetenv(key)

# Genera cadenas aleatorias de n bytes
os.urandom(n)

# Espera fin de un proceso hijo y devuelve tupla
# con estado pid y salida (unix)
os.wait()  

# Devuelve la lista formada por programa y 
# lista de argumentos agregados al ejecutar
sys.argv  

# Devuelve ruta del ejecutable del intérprete
sys.executable  

# Fuerza salida del intérprete Python
sys.exit()

# Devuelve codificación de caracteres por defecto  
sys.getdefaultencoding()

# Devuelve codificación de caracteres que se utiliza
# para convertir los nombres de archivos unicode en
# nombres de archivos del sistema
sys.getfilesystemencoding()  

# Devuelve paths de Python
sys.path  

# Añade una nueva ruta al path
sys.path.append('ruta')

# Muestra información de módulos Python 
sys.modules

# Obtiene versión de Python
sys.version

# Obtiene información de copyright
sys.copyright

# Obtiene sistema operativo del sistema
sys.platform

# Obtiene información de versión
sys.version_info

# Obtiene versión major
sys.version_info.major >= 3

# Devuelve hora actual en segundos (coma flotante)  
time.time()

# Convierte de segundos a cadena
time.ctime()

# Muestra hora local como tupla
time.localtime()

# Convierte fecha y hora locales a cadena
time.asctime()

# Retarda ejecución un número de segundos  
time.sleep()  



Ir al índice del tutorial de Python

martes, 4 de febrero de 2014

Módulos

Existen varios métodos para crear módulos pero la forma más sencilla es crear un archivo con extensión .py que contenga un conjunto de funciones y/o de clases. Un módulo puede ser importado por otro programa para hacer uso de su funcionalidad, de igual forma que se hace con aquellos módulos que pertenecen a la biblioteca estándar de Python.

La carga de un módulo compilado es más rápida. Los archivos compilados tienen la extensión .pyc y tienen la ventaja de que son independientes de la plataforma.

Ejemplo de uso del modulo sys que ofrece funciones específicas para interactuar con el sistema:

import sys 

print('Las rutas de PYTHONPATH:', sys.path, '\n')

Namespaces y Alias


Cuando se hace referencia a algún elemento que pertenece a un módulo importado se indica previamente su espacio de nombres (namespaces) seguido de un punto “.” como en el ejemplo anterior: sys.path.

En el momento de importar un módulo puede asignarse también un alias con as:

# Carga módulo megamodulo.py y asigna alias:
import megamodulo as mmod

# Se hace referencia a una función del módulo:
mmod.mfuncion 

De un módulo es posible importar sólo aquella función que vamos a utilizar y así cada vez que la usemos evitamos hacer referencia al nombre del módulo. No se suele recomendar este uso porque puede crear conflictos con variables o con funciones que tengan nombres iguales en otros módulos importados en una misma aplicación.

# Se carla la función pi del módulo math
from math import pi

# Este uso no se recomienda:
print('El valor de pi', pi)  # es mejor: math.pi

Mediante el atributo __name__ tenemos acceso al nombre de un módulo. Si accedemos a este atributo cuando se ejecuta un programa podemos conocer si el módulo es ejecutado de forma independiente (en ese caso __name__ = '__main__') o es importado:

if __name__ == '__main__':
    print("Este programa es independiente")
else:
    print("El modulo ha sido importado")

En Geany cuando se comienza a escribir un programa a partir de una plantilla Python (Menú Archivo, Nuevo desde plantilla), en el código inicial se incluye la función main() para situar dentro de ella nuestro código.

Creación y uso de un módulo


En el siguiente ejemplo se crea el módulo moduloseries.py y un programa programa.py lo importa y hace uso de la función sumadesde1aN (que para un número n, suma todo los números que van desde 1 a n).

moduloseries.py:

def sumadesde1aN(pnumero):
    ''' Suma todos los números consecutivos desde 1 hasta
    el número expresado. Si el valor es menor que 1 devuelve 0 '''
    ntotal= 0
    if pnumero >0:
        for nnum in range(1,pnumero+1):
            ntotal = ntotal + nnum
  
    return ntotal
  
__version__ = '1.0'

programa.py:

import moduloseries

valor = 10
print('Suma desde 1 a '+str(valor)+':',
      moduloseries.sumadesde1aN(valor))
print('Versión:', moduloseries.__version__)
print('Nombre:', moduloseries.__name__)
print('Doc:', moduloseries.sumadesde1aN.__doc__)

También sería posible importar la función y la versión del módulo, así:

from moduloseries import sumadesde1aN, __version__

# Importa las funciones pero no la __version__
from moduloseries import *  

La función dir()


La función dir() lista los identificadores que definen un objeto. Para un módulo, los identificadores incluyen las funciones, las clases y variables definidas en ese módulo.

import sys
dir(sys)

Resultado:

['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_getframe', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'hash_info', 'hexversion', 'int_info', 'intern', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoptions']

Paquetes (Packages)


Las variables suelen ir dentro de las funciones, las llamadas variables globales dentro de los módulos. Los módulos suelen organizarse en un tipo de carpetas especiales que se llaman paquetes. Dentro de estas carpetas deben existir necesariamente un archivo llamado __init__.py, aunque esté vacío. No es obligatorio que todos los módulos pertenezcan a un paquete.

La estructura básica de las carpetas de un paquete se parece a:

 - <carpeta definida en sys.path>/

- mismodulos/
- __init__.py
- modulo1/
- __init__.py
- modulo2/
- __init__.py
- codpyton21.py
- modulo3/
- __init__.py
- modulo31/
- __init__.py
- codpython311.py

Un paquete puede contener a otros subpaquetes y éstos, también, módulos. Cuando se importa un módulo es posible indicar su espacio de nombres:

# Importa módulo no empaquetado:
import modulo

# Importa módulo del paquete indicado:
import paquete.modulo

# importa módulo del subpaquete/paquete:
import paquete.subpaquete.modulo  


Ir al índice del tutorial de Python

domingo, 2 de febrero de 2014

Operaciones con archivos


Un archivo es información identificada con un nombre que puede ser almacenada de manera permanente en el directorio de un dispositivo.

Abrir archivo


Antes de poder realizar cualquier operación de lectura/escritura hay que abrir el archivo con open() indicando su ubicación y nombre seguido, opcionalmente, por el modo o tipo de operación a realizar y la codificación que tendrá el archivo. Si no se indica el tipo de operación el archivo se abrirá en modo de lectura y si se omite la codificación se utilizará la codificación actual del sistema. Si no existe la ruta del archivo o se intenta abrir para lectura un archivo inexistente se producirá una excepción del tipo IOerror.

ObjArchivo = open('/home/archivo.txt')
ObjArchivo = open('/home/archivo.txt', 'r')
ObjArchivo = open('/home/archivo.txt', 
                  mode='r', encoding='utf-8')


¿Y qué codificación utiliza nuestro sistema? Podemos averiguarlo ejecutando las siguientes líneas de código:

import locale
print(locale.getpreferredencoding())

Las operaciones que pueden realizarse sobre un archivo:

rLectura
r+Lectura/Escritura
wSobreescritura. Si no existe archivo se creará
aAñadir. Escribe al final del archivo
bBinario
+Permite lectura/escritura simultánea
USalto de línea universal: win cr+lf, linux lf y mac cr
rbLectura binaria
wbSobreescritura binaria
r+bLectura/Escritura binaria


Cerrar archivo


Después de terminar de trabajar con un archivo lo cerraremos con el método close().

ObjArchivo.close()

Leer archivo: read, readline, readlines, with-as


Con el método read() es posible leer un número de bytes determinados. Si no se indica número se leerá todo lo que reste o si se alcanzó el final de fichero devolverá una cadena vacía.

# Abre archivo en modo lectura
archivo = open('archivo.txt','r')

# Lee los 9 primeros bytes
cadena1 = archivo.read(9)

# Lee la información restaste 
cadena2 = archivo.read()

# Muestra la primera lectura  
print(cadena1)

# Muestra la segunda lectura
print(cadena2)

# Cierra el archivo 
archivo.close()  

El método readline() lee de un archivo una línea completa

# Abre archivo en modo lectura
archivo = open('archivo.txt','r')  

# inicia bucle infinito para leer línea a línea
while True: 
    linea = archivo.readline()  # lee línea
    if not linea: 
        break  # Si no hay más se rompe bucle
    print(linea)  # Muestra la línea leída
archivo.close()  # Cierra archivo

El método readlines() lee todas las líneas de un archivo como una lista. Si se indica el parámetro de tamaño leerá esa cantidad de bytes del archivo y lo necesario hasta completar la última linea.

# Abre archivo en modo lectura
archivo = open('archivo.txt','r')

# Lee todas la líneas y asigna a lista
lista = archivo.readlines()  

# Inicializa un contador
numlin = 0  

# Recorre todas los elementos de la lista
for linea in lista:
    # incrementa en 1 el contador  
    numlin += 1
    # muestra contador y elemento (línea)
    print(numlin, linea)
  
archivo.close()  # cierra archivo

with-as permite usar los archivos de forma óptima cerrándolos y liberando la memoria al concluir el proceso de lectura.

# abre archivo (y cierra cuando termine lectura)
with open("indice.txt") as fichero:
    # recorre línea a línea el archivo
    for linea in fichero:
        # muestra línea última leída
        print(linea)  

Escribir en archivo: write, writelines


El método write() escribe una cadena y el método writelines() escribe una lista a un archivo. Si en el momento de escribir el archivo no existe se creará uno nuevo.

cadena1 = 'Datos'  # declara cadena1
cadena2 = 'Secretos'  # declara cadena2

# Abre archivo para escribir
archivo = open('datos1.txt','w')

# Escribe cadena1 añadiendo salto de línea 
archivo.write(cadena1 + '\n')

# Escribe cadena2 en archivo
archivo.write(cadena2) 

# cierra archivo
archivo.close()


# Declara lista
lista = ['lunes', 'martes', 'miercoles', 'jueves', 'viernes']  

# Abre archivo en modo escritura
archivo = open('datos2.txt','w')

# Escribe toda la lista en el archivo
archivo.writelines(lista)  

# Cierra archivo
archivo.close()  

Mover el puntero: seek(), tell()


El método seek() desplaza el puntero a una posición del archivo y el método tell() devuelve la posición del puntero en un momento dado (en bytes).

# Abre archivo en modo lectura
archivo = open('datos2.txt','r')  

# Mueve puntero al quinto byte
archivo.seek(5)  

# lee los siguientes 5 bytes
cadena1 = archivo.read(5) 

# Muestra cadena
print(cadena1) 

# Muestra posición del puntero 
print(archivo.tell())

# Cierra archivo
archivo.close()  

Leer y escribir cualquier objeto a un archivo: pickle


Para leer y escribir cualquier tipo de objeto Python podemos importar el modulo pickle y usar sus métodos dump() y load() para leer y escribir los datos.

# Importa módulo pickle
import pickle

# Declara lista
lista = ['Perl', 'Python', 'Ruby']

# Abre archivo binario para escribir   
archivo = open('lenguajes.dat', 'wb')

# Escribe lista en archivo
pickle.dump(lista, archivo)

# Cierra archivo
archivo.close()

# Borra de memoria la lista
del lista  

# Abre archivo binario para leer
archivo = open('lenguajes.dat', 'rb')

# carga lista desde archivo
lista = pickle.load(archivo)

# Muestra lista  
print(lista)

# Cierra archivo
archivo.close()  


Relacionado: Tempfile: archivos y directorios temporales

Ir al índice del tutorial de Python

Programación funcional. Funciones de orden superior


Python tiene algunas características de la programación funcional, un paradigma de programación basado en un concepto de función más cercano al matemático que al que habitualmente estamos habituados en la programación imperativa.

Python proporciona algunas funciones de orden superior y permite también definir otras a medida. El siguiente ejemplo construye un conversor de números anidando varias funciones en una función de orden superior.

def conversor(sis):
    def sis_bin(numero):
        print('dec:', numero, 'bin:', bin(numero))
 
    def sis_oct(numero):
        print('dec:', numero, 'oct:', oct(numero))
   
    def sis_hex(numero):
        print('dec:', numero, 'hex:', hex(numero))
  
    sis_func = {'bin': sis_bin, 'oct': sis_oct, 'hex': sis_hex}
    return sis_func[sis]

# Crea una instancia del conversor hexadecimal
conversorhex = conversor('hex')

# Convierte 100 de decimal a hexadecimal
conversorhex(100)

# Otro modo de usar el conversor. 
# Convierte 9 de decimal a binario
conversor('bin')(9)

La función map()


La función de orden superior map() aplica una función a una lista de datos y devuelve un iterador que contiene todos los resultados para los elementos de la lista.

En el siguiente ejemplo la función cuadrado calcula el cuadrado de un número. La lista1 contiene una lista de datos numéricos. Con map(cuadrado, lista1) se aplica la función cuadrado a cada elemento de la lista.


def cuadrado(numero):       
    return numero ** 2

lista1 = [-2, 4, -6, 8]

# Convierte a lista el iterador obtenido
lista2 = list(map(cuadrado, lista1))

# Muestra elementos de la lista
print(lista2)  # 4, 16, 36, 64


Para calcular el área de un circulo necesitamos el número pi que esta disponible, con un número suficiente de decimales, en el módulo de la biblioteca estándar math. En el siguiente ejemplo la función area_circulo calcula el área de un circulo. La lista3 tiene una lista de datos numéricos que son longitudes de radios diferentes. Con map(area_circulo, lista3) se aplica la función a cada elemento de la lista.

import math

def area_circulo(radio):
    return math.pi * radio ** 2
 
lista3 = [1, 2, 3]

# Devuelve iterador que es convertido a lista
lista4 = list(map(area_circulo, lista3))
print(lista4)

Para convertir el iterador a una lista hemos empleado la función list(). También, podríamos haber recorrido el iterador con un for...in:

for resultado in map(area_circulo, lista3): 
    print(resultado)

La función filter()


La función filter() aplica un filtro a una lista de datos y devuelve un iterador con los elementos que superan el filtro.


# La función verifica si un número es negativo
def esneg(numero):
    # Devuelve True/False según sea o no nº negativo
    return (numero < 0)

lista5 = [-3, -2, 0, 1, 9, -5]

# Muestra los números negativos de la lista
# La función esneg() es llamada para comprobar, 
# uno a uno, todos los números de la lista
print(list(filter(esneg, lista5)))

La función reduce()


La función reduce() aplica una función a una lista de datos evaluando los elementos por pares. La primera vez se aplica al primer y segundo elemento, la siguiente, se aplicará al valor devuelto por la función junto al tercer elemento y así, sucesivamente, reduciendo la lista hasta que quede un sólo elemento.

A partir de Python 3 si queremos utilizar reduce() debemos importar el módulo functools:

import functools

def multiplicar(x, y):
    print(x * y)  # muestra el resultado parcial
    return x * y

lista = [1, 2, 3, 4]
valor = functools.reduce(multiplicar, lista)
print(valor)  # muestra el resultado final

La función lambda


La función lambda se utiliza para declarar funciones que sólo ocupan una línea. Son objetos que se pueden asignar a variables para usar con posterioridad.

cuadrado = lambda x: x*x

lista = [1,2,3,5,8,13]
for elemento in lista:
    print(cuadrado(elemento))

# Lambda, con 2 argumentos:

area_triangulo = (lambda b,h: b*h/2)
medidas = [(34, 8), (26, 8), (44, 18)]
for datos in medidas:
    base = datos[0]
    altura = datos[1]
    print(area_triangulo(base, altura))

Comprensión de listas


Es un tipo de construcción que consta de una expresión que determina como modificar los elementos de una lista, seguida de una o varias clausulas for y, opcionalmente, una o varias clausulas if. El resultado que se obtiene es una lista, un diccionario o un conjunto.

lista = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Cada elemento de la lista se eleva al cubo
cubos = [valor ** 3 for valor in lista]
print('Cubos de 1 a 10:', cubos)


numeros = [135, 154, 180, 193, 210]
divisiblespor3 = [valor for valor in numeros if valor % 3.0 == 0] 

# Muestra lista con los números divisibles por 3
print(divisiblespor3)  


# Define función devuelve el inverso de un número
def funcion(x):
    return 1/x

L = [1, 2, 3]  # declara lista

# Muestra lista con inversos de cada número
print([funcion(i) for i in L])

# Devuelve un conjunto (elementos no repetidos)
z = {elem for elem in [1, 2, 1, 2, 3, 1]}
print(z)  # {1, 2, 3}

# Devuelve un diccionario
dicc1 = {num: num**2 for num in range(1, 6)}
print(dicc1)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Generadores


Los generadores funcionan de forma parecida a la comprensión de listas pero no devuelven listas sino generadores. Un generador es una clase especial de función que genera valores sobre los que iterar. La sintaxis usada es como la usada en la comprensión de listas pero en vez de usar corchetes se utilizan paréntesis. Para devolver los valores se utiliza yield en vez de return.

# Define generador
def generador(inicio, fin, incremento):
    while(inicio <= fin):
        yield inicio  # devuelve valor
        inicio += incremento

# Recorre los valores del generador
for valor in generador(0, 6, 1):
    # Muestra valores, uno a uno:
    print(valor)  # 0 1 2 3 4 5 6

# Obtiene una lista del generador
lista = list(generador(0, 8, 2))

# Muestra lista
print(lista)  # [0,2,4,6,8]

La función Decorador


Es una función que recibe una función como parámetro y devuelve otra función como valor de retorno. Se utiliza cuando es necesario definir varias funciones que son muy parecidas. La función devuelta actúa como un envoltorio (wrapper) resolviendo lo que sería común a todas las funciones. También se aplica a clases.


# Define decorador
def decorador1(funcion):
    # Define función decorada
    def funciondecorada(*param1, **param2):
        print('Inicio', funcion.__name__)
        funcion(*param1, **param2)
        print('Fin', funcion.__name__)
    return funciondecorada
    
def suma(a, b):
    print(a + b)

suma2 = decorador1(suma)
suma2(1,2)
suma3 = decorador1(suma)
suma3(2,2)

# Otra forma más elegante, usando @:

@decorador1
def producto(arg1, arg2):
    print(arg1 * arg2)

producto(5,5)


# El siguiente decorador genera tablas de sumas
# y multiplicaciones. El código que es común a todas 
# las funciones se declara en la función 'envoltura':

def tablas(funcion):
    def envoltura(tabla=1):
        print('Tabla del %i:' %tabla)
        print('-' * 15)
        for numero in range(0, 11):            
            funcion(numero, tabla)
        print('-' * 15)
    return envoltura

@tablas
def suma(numero, tabla=1):
    print('%2i + %2i = %3i' %(tabla, numero, tabla+numero))

@tablas
def multiplicar(numero, tabla=1):
    print('%2i X %2i = %3i' %(tabla, numero, tabla*numero))

# Muestra la tabla de sumar del 1
suma()

# Muestra la tabla de sumar del 4 
suma(4)

# Muestra la tabla de multiplicar del 1
multiplicar()

# Muestra la tabla de multiplicar del 10
multiplicar(10)  


Ir al índice del tutorial de Python

sábado, 1 de febrero de 2014

Variables locales y variables globales


Una variable local se declara en su ámbito de uso (en el programa principal y dentro de una función) y una global fuera de su ámbito para que se pueda utilizar en cualquier función que la declare como global.

# Define función
def acelerar():
    # Declara la variable 'km' como global
    # Ahora se podrá utilizar dentro de la función
    global km
    
    # Declara variable local (ámbito función)
    tiempo = 1

    # Se incrementa la velocidad en 5 km
    km+= 5

# Define variable local (ámbito programa principal)
km = 10

# Muestra variable 'km'
print('Velocidad:', km)  # velocidad: 10

# Llama a la función acelerar()
acelerar()

# Muestra variable 'km'
print('Velocidad:', km)  # velocidad: 15

# Intenta mostrar la variable 'tiempo'
# Se produce una excepción (error) de tipo NameError
# porque la variable no pertenece a este ámbito:
# NameError: name 'tiempo' is not defined
print('Tiempo:', tiempo)


Relacionado:
Diccionarios de variables locales y globales


Ir al índice del tutorial de Python

Docstrings


Documentando el código


Las cadenas de documentación o docstrings son textos que se escriben entre triples comillas dentro de los programas para documentarlos. Cuando se desarrolla un proyecto donde colaboran varias personas contar con información clara y precisa que facilite la comprensión del código es imprescindible y beneficia a todos los participantes y al propio proyecto.

Las funciones, clases y módulos deben ir convenientemente documentados. La información de las docstrings estará disponible cuando se edite el código y, también, durante la ejecución de los programas:

def area_trapecio(BaseMayor, BaseMenor, Altura):
    '''area_trapecio: Calcula el área de un trapecio.
    area_trapecio = (BaseMayor + BaseMenor) * Altura / 2''' 
    return (BaseMayor + BaseMenor) * Altura / 2
  
print(area_trapecio(10,4,4))  # Resultado: 28
print(area_trapecio.__doc__) 

La sentencia print(area_trapecio.__doc__) muestra la información de la docstrings:

area_trapecio: Calcula el área de un trapecio.
area_trapecio=(BaseMayor+BaseMenor)*Altura/2

Para recuperar la información de las docstrings en el modo interactivo utilizaremos la función help(); y en la línea de comandos haremos uso del comando pydoc3:


>>>help(area_trapecio)

$ pydoc3 os

Es frecuente agrupar varias funciones en un mismo archivo (módulo) acompañadas con información escrita suficiente que explique cómo utilizarlas, para que pueda ser consultada en cualquier momento por los programadores.

En el siguiente archivo (geometriaplana.py) se incluyen varias funciones para calcular el área de algunas figuras geométricas; de forma que puedan utilizarse en cualquier programa que escribamos con posterioridad, Las funciones incluyen documentación que explica brevemente para qué sirven y especifican los argumentos que utilizan:

geometriaplana.py:

'''Funciones de geometría plana
   Para el cálculo del área de las siguientes figuras:
   
'''

from math import pi

def area_cuadrado(Lado):
    '''Función area_cuadrado: Calcula área de un cuadrado.
    area_cuadrado = Lado ** 2 '''
    return (Lado ** 2)

def area_rectangulo(Base, Altura):
    '''Función area_rectangulo: Calcula área de un rectángulo.
    area_rectangulo = Base * Altura '''
    return (Base * Altura)

def area_triangulo(Base, Altura):
    '''Función area_triangulo: Calcula área de un triángulo.
    area_triangulo = Base * Altura / 2 '''
    return (Base * Altura / 2)

def area_paralelogramo(Base, Altura):
    '''Función area_paralelogramo: Calcula área de un paralelogramo.
    area_paralelogramo = Base * Altura '''
    return (Base * Altura)

def area_trapecio(BaseMayor, BaseMenor, Altura):
    '''Función area_trapecio: Calcula área de un trapecio.
    area_trapecio = (BaseMayor + BaseMenor) * Altura / 2'''
    return (BaseMayor + BaseMenor) * Altura / 2
   
def area_circulo(Radio):
    '''Función area_circulo: Calcula área de un circulo.
    area_ciruculo = Pi * Radio ** 2 '''
    return (pi * Radio ** 2)

 

Ver documentación en la consola



$ pydoc3 geometriaplana



Guardar la documentación en formato HTML


$ pydoc3 -w geometriaplana

La opción -w hará que se cree un archivo con la documentación en formato HTML.



Buscar documentación indicando una palabra clave


$ pydoc3 -k geometria

Resultado:
geometriaplana

Iniciar servicio web con documentación en el puerto indicado


$ pydoc3 -p 8080

A continuación, iniciar navegador web y acceder a la siguiente URL:

http://localhost:8080


Utilizar funciones en programas y acceder a documentación


#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  calculoareas.py
# 

from geometriaplana import *  

def main():
    print(area_paralelogramo.__name__)
    print(area_paralelogramo.__doc__) 
    print("Ejemplo area_paralelogramo(6,4):", 
          area_paralelogramo(6,4),"\n")  # Resultado: 28
 
    print(area_cuadrado.__name__) 
    print(area_cuadrado.__doc__)
    print("Ejemplo area_cuadrado(5):", 
          area_cuadrado(5),"\n")  # Resultado: 25
    return 0

if __name__ == '__main__':
    main()
En el programa (calculoareas.py) se importa el módulo anterior (geometriaplana.py) para realizar algunos cálculo de áreas y, a continuación, acceder al nombre de la función que se utiliza en un momento dado (__name__) y a su documentación (__doc__).


Al ejecutar el programa obtendríamos la siguiente salida:


Si utilizamos las consolas IPython 3 QT Console o del entorno de desarrollo IDLE en las que se ofrece información mientras se escriben los comandos Python; cuando escribamos las funciones aparecerá la documentación incluida en las docstrings:


Funciones


Una función es como una caja negra: una vez creada no debemos preocuparnos por lo que tiene en su interior, simplemente, tenemos que recordar su nombre y los datos que necesita para resolver un proceso. Generalmente, devuelven un resultado.

La principal virtud de una función está en la reutilización del código, es decir, una vez creada puede ser llamada cada vez que se necesite. Para mejor aprovechamiento debemos procurar que las funciones ofrezcan soluciones a necesidades muy concretas.

Funciones con un número fijo de parámetros


La siguiente función calcula el área de un triángulo. Una vez definida se utiliza para calcular el área de dos triángulos de distintas dimensiones.

Para definir la función escribiremos def seguido del nombre de la función y entre paréntesis los dos parámetros que son necesarios para calcular el área del triángulo: base y altura. Con return la función devolverá el resultado de la fórmula matemática expresada. Los dos parámetros son obligatorios. Si alguno falta habrá una excepción.

def area_triangulo(base, altura):  # define función con dos parámetros
    ''' Calcular el área de un triangulo'''  # cadena de documentación
    return base * altura / 2  # devuelve el resultado de la expresión

print(area_triangulo(6, 4))  # la función retornará el valor 12
print(area_triangulo(3.5, 2.4))  # la función retornará el valor 4.2

Funciones con un número variable de parámetros


La siguiente función suma la distancia de un número variable de tramos. Si se utiliza sin aportar ningún valor devolverá 0. También, como cabría pensar es posible pasar variables.

def distancia(*tramos): # define función con nº variable de parámetros
    ''' Suma distancia de tramos '''  # cadena de documentación
    total = 0  # inicializa variable numérica 
    for distancia in tramos:  # recorre, uno a uno, los tramos...
        total = total + distancia  # … y acumula la distancia
    return total  # devuelve la suma de todos los parámetros

tramo1 = 10
print(distancia(tramo1, 20, 30, 40))  # la función devuelve 100 
print(distancia())  # la función retornará el valor 0

Funciones con parámetros con valores por defecto 


La función pagar tiene el parámetro dto_aplicado con el valor 5 asignado por omisión. Dicho valor se utilizará en la solución en el caso de omitirse este dato cuando sea llamada la función.

def pagar(importe, dto_aplicado = 5):
    ''' La función aplica descuentos '''
    return importe - (importe * dto_aplicado / 100)

print(pagar(1000))  # 950
print(pagar(1000, 10))  # 900

Función con todos los parámetros con valores por defecto


Todos los parámetros tienen un valor por defecto. Cuando se utiliza la función si se especifican los nombres de los parámetros éstos pueden estar en distinto orden.

def repite_caracter(caracter="-", repite=3):
    return caracter * repite

print(repite_caracter())  # Se utilizan valores por omisión
print(repite_caracter('.',30))  # Muestra línea con 30 puntos
print(repite_caracter(repite=10, caracter='*'))  # Muestra: **********

Funciones con parámetros que contienen diccionarios


La función porc_aprobados tiene el parámetro **aulas que es un diccionario que contendrá las aulas de una escuela con el número alumnos de cada una. Cuando es llamada la función se pasa también el número de alumnos que aprobaron el curso. La función suma los alumnos de todas las aulas y calcula el porcentaje de aprobados.

def porc_aprobados(aprobados, **aulas):
    ''' Calcula el % de aprobados '''
 
    total=0
    for alumnos in aulas.values():
        total += alumnos
 
    return aprobados * 100 / total

porcentaje_aprobados = porc_aprobados(48, A = 22, B = 25, C = 21)
print(porcentaje_aprobados)

Funciones que devuelven más de un valor 


La función elemento_quimico recibe un símbolo químico y devuelve el número atómico del elemento correspondiente y su denominación. Para ello, utiliza un diccionario en el que las claves son los símbolos químicos y los valores son cadenas que contienen para cada elemento su número atómico y denominación, unidos por un guión. Mediante el símbolo se accede a la cadena que luego es dividida con split en dos partes (utilizando como separador el propio guión '-'). split devuelve una lista con las dos partes. En lista[0] queda el número atómico y en lista[1] la denominación, los dos valores que devuelve esta función.

def elemento_quimico(simbolo):
    ''' Devuelve número atómico y denominación del elemento '''
 
    elementos = {'H':'1-Hidrógeno', 'He':'2-Helio', 'Li':'3-Litio'}
    elemento = elementos[simbolo]
    lista = elemento.split('-')
    return (lista[0], lista[1])

num_atomico, denomina = elemento_quimico('He')
print('Núm. Atómico:', num_atomico)
print('Denominación:', denomina)

Funciones sin return


Una función sin return devuelve None si es asignada a una variable o llamada desde un print(). Por lo demás, funcionan igual que cualquier otra función.

def repite(caracter='-', repite=3):
    print(caracter * repite)

repite('=', 20)

Funciones generadas a partir de otras


A partir de un función existente es posible generar una nueva. Después, ambas podrán usarse de igual forma.

at = area_triangulo  # la función calcula área de un triángulo  
print at(10,4)  # la nueva función usa los argumentos base y altura 



Relacionado:

Excepciones




Las excepciones o errores que se pueden producir durante la ejecución de un programa Python se gestionan con una construcción try-except. Una excepción puede ocurrir al intentar operar con datos de distinto tipo, dividir un número por cero, teclear un tipo de dato no esperado, acceder a un archivo que no existe y en otras situaciones previsibles. Para cuando sucedan es importante decidir qué respuesta dar en cada caso y evitar que el programa suspenda su ejecución de manera inesperada.

En el bloque try se incluye el código que puede producir la excepción y en except el código que la tratará convenientemente. En un bloque except TipoError se capturará un tipo de error concreto, que habrá que indicarlo. Por ejemplo, si se intenta convertir una cadena de texto de caracteres alfabéticos a número entero el tipo es ValueError o si se opera con una variable no declarada el tipo es NameError.

try:  # contiene el código que puede producir la excepción
except:  # contiene el código que gestionará cualquier error
except TipoError:  # contiene el código que gestionará un tipo de error concreto
else:  # contiene el código que se ejecutará en caso de no haber error
finally:  # contiene el código que se ejecutará en cualquier caso.

El siguiente ejemplo calcula el factorial de un número. Si no se introduce un número entero se producirá una excepción:

try:
    numero = int(input('Introducir un número: '))
    factorial = 1
    for num in range(1, numero+1):
        factorial *= num

    print(factorial) 

except:
    print('Debe introducir un número entero') 

A continuación, se utilizan el resto de clausulas disponibles para la gestión de excepciones.

try:  # Bloque de código a “vigilar”
    texto = input('Teclear :')  # introducir un dato

except KeyboardInterrupt:  # captura excepción de interrupción 
    print('\nSe ha pulsado ctrl+c') # Interrupción al presionar Ctrl+c

else:  # se ejecuta si no hay error
    print('Ha tecleado {}'.format(texto)) # muestra cadena introducida
 
finally:  # se ejecuta tanto si hay error como si no
    print('fin de programa')  # muestra mensaje final

Excepciones a medida


La flexibilidad en la gestión de excepciones se amplia cuando los programadores pueden definir sus propios tipos de errores. Para ello, es necesario crear una clase que herede de la clase Exception o de alguna de sus hijas y después llamarla con raise:

# Define clase a partir de Exception
class LongPassw(Exception):
    '''Excepción definida por usuario'''
    def __init__(self, longitud):  # define método constructor ...   
        Exception.__init__(self)  # … de excepción ... 
        self.longitud = longitud  # … y con atributo longitud
  
try:  # bloque de código a vigilar
    clave = input('Teclear contraseña: ')  # introducir una cadena
    if len(clave) < 6:  # si longitud de cadena es menor de 6 
        raise LongPassw(len(clave))  # llama a excepción de usuario 

except LongPassw as lp:  # excepción de usuario   
    print('LongPassw: Error por longitud: {0}'.format(lp.longitud))

else:  # se ejecuta si no hay error
    print('No se ha producido error.')  # muestra mensaje

De obligado cumplimiento: assert


Con assert se fijan las condiciones que debe cumplir un objeto y si éstas no se cumplen en un momento determinado, producirá una excepción que hay que interceptar y tratar convenientemente.

En el siguiente ejemplo se define una lista con seis elementos. A continuación, mediante un bucle se irán eliminando elementos, uno a uno, desde el final de la lista. La condición establecida para que no se produzca la excepción es que la lista tenga al menos dos elementos. Cuando haya dos y se intente borrar de nuevo se producirá la excepción AssertionError.

try:  # bloque de código a vigilar
    lista = [1, 2, 3, 4, 5, 6]  # define lista
    print(lista)  # muestra lista
    while True:  # bucle infinito hasta error
        print('Elemento a borrar',lista[-1])
        lista.pop()  # borra elemento
        assert len(lista) > 1  # la lista debe tener al menos 2 
        print(lista)  # muestra lista después de borrado

except AssertionError:  # excepción para assert
    print('Error al intentar borrar elemento  ')  # mensaje de assert
    print('La lista debe contener al menos 2')



Ir al índice del tutorial de Python