Python Avanzado
Python Avanzado
INTRODUCCIÓN
¿QUÉ UTILIZAREMOS DURANTE EL APRENDIZAJE?
PROCESO DE APRENDIZAJE
Organización
Distribución del fin de semana
OBJETIVO 1: LISTAS
Conceptos teóricos
Métodos propios de las listas
FASE 1: Lista
Ahora eres capaz de…
OBJETIVO 2: DICCIONARIOS
Conceptos teóricos
Métodos propios diccionarios
FASE 1: Diccionarios
Ahora eres capaz de…
OBJETIVO 3: RECURSIVIDAD
Conceptos teóricos
Recursividad
FASE 1: Recursividad
Ahora eres capaz de…
OBJETIVO 4: PILAS
Conceptos teóricos
Pilas
FASE 1: Pila
Ahora eres capaz de…
OBJETIVO 5: COLAS
Conceptos teóricos
Colas
FASE 1: Cola
Ahora eres capaz de…
OBJETIVO 6: LIBRERÍA ESTÁNDAR
Conceptos teóricos
Librería estándar
FASE 1: Módulo random
FASE 2: Módulo math
FASE 3: Módulo statistics
FASE 4: Módulo datetime
FASE 5: Módulo os y shutil
Ahora eres capaz de…
OBJETIVO 7: PROGRAMACIÓN PARALELA
Conceptos teóricos
¿Qué es la programación paralela?
Procesos VS Hilos
Global Interpreter Lock
FASE 1: Hilos
FASE 2: Procesos
Ahora eres capaz de…
OBJETIVO 8: BASES DE DATOS
Conceptos teóricos
¿Qué es una base de datos?
Bases de datos relacionales
SQL
SQLite
FASE 1: Creación de la base de datos
FASE 2: Insertando datos
FASE 3: Leyendo datos
FASE 4: Modificando datos
FASE 5: Borrando datos
Ahora eres capaz de…
OBJETIVO 9: MÓDULOS
Conceptos teóricos
FASE 1: Módulos
Ahora eres capaz de…
OBJETIVO 10: PRUEBAS UNITARIAS
Conceptos teóricos
¿Qué son los tests unitarios?
Ventajas de uso
Librería unittest
FASE 1: Pruebas unitarias
Ahora eres capaz de…
OBJETIVO 11: Networking
Conceptos teóricos
Protocolo de Internet (IP)
¿Qué son los sockets?
Puertos
¡Todo junto!
Paradigma de programación cliente-servidor
FASE 1: Conociendo tu IP
FASE 2: Sockets en Python
FASE 3: Errores comunes
FASE 4: Servidor con múltiples clientes
Ahora eres capaz de…
PROYECTO FINAL
Base de datos
Servidor
Clase Teléfono
Clase Dirección
Clase Contacto
Módulo de acceso a datos
Módulo de conversión
Módulo de comunicaciones
Programa principal
Cliente
Clase Teléfono
Clase Dirección
Clase Contacto
Módulo de visualización
Módulo de conversión
Programa principal
Ejecución
Ampliando el proyecto…
¡CONSEGUIDO!
ANEXO 1: TERMINAL / CONSOLA / SHELL
SOBRE LOS AUTORES Y AGRADECIMIENTOS
MATERIAL DESCARGABLE
OTROS LIBROS DE LOS AUTORES
INTRODUCCIÓN
Habéis sido muchos los que desde que publicamos el libro “Aprende Python
en un fin de semana” nos habéis escrito para pedirnos que publicásemos una
continuación del libro, con conocimientos más avanzados, pero con la misma
mecánica de aprendizaje.
En el libro vais a encontrar una serie de objetivos que van desde aprender
estructuras de datos específicas hasta aprender a utilizar bases de datos o
programación paralela.
¡Empecemos!
¿QUÉ UTILIZAREMOS DURANTE EL APRENDIZAJE?
Lo primero que debes instalar es el programa que utilizarás para hacer todos
los ejercicios, el IDLE de Python. Puedes descargarlo de
https://www.python.org/downloads/ seleccionando el sistema operativo que
tengas, aunque de forma automática la página detecta el sistema operativo
que estás utilizando y te añade un botón para descargarlo en la parte superior
de la página.
¡Eso es todo!
PROCESO DE APRENDIZAJE
En este primer objetivo vamos a explicarte los métodos propios que tienen las
listas y que añaden funcionalidades muy útiles a la hora de trabajar con ellas.
Las listas en Python poseen una serie de métodos que permiten realizar
operaciones complejas de forma sencilla y con una simple instrucción. La
gran mayoría de métodos siguen el siguiente patrón:
Lista.NombreMétodo(Parámetros)
sort
Método que realiza la ordenación de la lista si es posible realizarla. Por
defecto la ordenación es ascendente, en caso de querer una ordenación
descendente hay que indicarlo por parámetro al método (reverse=true).
reverse
Método que invierte el orden de la lista.
count
Método que cuenta el número de veces que aparece un elemento en la lista y
lo devuelve como resultado de la ejecución de este. El método recibe como
parámetro el elemento a contar.
index
Método que devuelve la posición de la primera ocurrencia en la lista del
elemento pasado como parámetro (parámetro obligatorio). Por defecto, la
búsqueda de la primera ocurrencia se realiza recorriendo la lista de izquierda
a derecha (de la posición 0 a las superiores). El método tiene además dos
parámetros opcionales, el primero se utiliza para indicar en qué posición
empezar a buscar y el segundo para indicar en qué posición terminar de
buscar.
extend
Método que añade elementos de una lista a la lista que ejecuta el método,
obteniendo como resultado una lista compuesta por la unión de los elementos
de ambas listas.
clear
Método que elimina todos los elementos de la lista.
append
Método que añade el elemento pasado como parámetro a la lista, obteniendo
como resultado la lista con el elemento añadido. El elemento puede ser de
cualquier tipo de dato.
insert
Método que añade en la posición de la lista indicada por el primer parámetro
el elemento pasado como segundo parámetro, obteniendo como resultado la
lista con el elemento añadido en la posición indicada. El elemento que ocupe
esa posición y los de posiciones superiores serán desplazados hacia la
derecha dentro de la lista.
remove
Método que elimina la primera ocurrencia empezando por la izquierda (índice
0) de la lista del elemento indicado como parámetro. En caso de no encontrar
el elemento, la función devolverá un error.
pop
Método que elimina un elemento de la lista y lo devuelve como resultado de
la operación. Es decir, la lista es modifica eliminando el elemento que es
retornado por el método. El método tiene un parámetro opcional para indicar
el elemento a borrar, en caso de no indicar el elemento la operación se
realizará sobre el último elemento de la lista.
En este segundo objetivo vamos a explicarte los métodos propios que tienen
los diccionarios y que añaden funcionalidades muy útiles a la hora de trabajar
con ellos.
Diccionario.NombreMétodo(Parámetros)
El primer ejercicio consiste en aprender los métodos propios copy, clear, pop
y popitem. Veámoslos en detalle:
copy
Método que realiza una copia del diccionario y lo devuelve como resultado
de la ejecución.
clear
Método que eliminar todos los elementos del diccionario.
pop
Método que obtiene el valor de la clave indicada como parámetro y que
elimina dicho elemento del diccionario. Es decir, elimina el elemento del
diccionario y lo devuelve como resultado de la operación. En caso de no
encontrar la clave devolverá un error.
popitem
Método que realiza la misma funcionalidad que el método pop pero sobre un
elemento aleatorio del diccionario.
get
Método que devuelve el valor de la clave pasada como parámetro
(obligatorio). El método posee un segundo parámetro opcional para indicar
qué devolver en caso de no encontrar la clave en el diccionario, por defecto el
valor que se devuelve es “None”.
update
Método que une el diccionario pasado como parámetro al diccionario que
ejecuta el método. En caso de que el diccionario pasado como parámetro
contenga elementos con las mismas claves que el que ejecuta el método, los
elementos del diccionario resultante serán aquellos del diccionario pasado
como parámetro. Los elementos que no existen serán añadidos como nuevos
elementos.
setdefault
Método que intenta insertar un elemento en el diccionario si no existe en el
diccionario. En caso de existir el elemento lo que hace únicamente el método
es devolver el valor del elemento existente en el diccionario.
items
Método que devuelve un objeto iterable compuesto por todos los elementos
del diccionario.
keys
Método que devuelve un objeto iterable compuesto por todas las claves de los
elementos del diccionario.
values
Método que devuelve un objeto iterable compuesto por todos los valores de
los elementos del diccionario.
El objetivo está compuesto por una única fase en la que realizarás varios
ejercicios para aprender a utilizarla.
Conceptos teóricos
Recursividad
La función Factorial incluye tanto el caso base, el valor del que hay que
calcular la factorial es 1, como el caso recursivo, el valor es mayor que uno.
La función mcd incluye tanto el caso base, cualquiera de los dos números es
0, como el caso recursivo, que ejecutará la recursividad con nuevos valores
basados en el valor de ambos números para calcularlos. Fíjate en los valores
que se van pasando en el caso recursivo, dependiendo del valor que
contengan ambos números se pasan unos valores u otros.
vectorenteros = [1,2,3,4,5,6,7,8,9]
print("Vector de enteros: ", vectorenteros)
elementosasumar = int(input("¿Cuántos elementos quieres sumar?: "))
if (elementosasumar > 0) & (elementosasumar <= len(vectorenteros)):
print("Resultado: ",SumarVector(vectorenteros,elementosasumar-1))
else:
print("ERROR: El número de elementos a sumar es erróneo")
En este cuarto objetivo vamos a explicarte qué son las pilas y cómo puedes
utilizarlas. Es muy importante que para este objetivo tengas claros los
conceptos que explicamos en el libro anterior sobre programación orientada a
objetos, ya que es la base para la construcción de pilas.
El objetivo está compuesto por una única fase en la que realizarás varios
ejercicios para aprender a utilizarlas.
Conceptos teóricos
Pilas
Antes de entrar en detalles de qué son las pilas, queremos que pienses en una
pila de platos. Cuando añades un plato a la pila lo que haces es ponerlo arriba
del todo, y cuando retiras un plato de la pila lo que haces es retirar el plato
que se encuentra en la parte superior del plato. Pues, básicamente, una pila en
programación es una estructura de datos que funciona de la misma manera.
Las pilas están compuestas por elementos en los que el primer elemento es el
elemento más nuevo en la misma, a la hora de coger un elemento cogeremos
el elemento más arriba de la pila (el más nuevo) y a la hora de dejar un
elemento lo dejaremos en lo más alto de la pila. En las pilas, el último en
entrar será el primero en salir.
Gráficamente:
Tal y como veremos en la fase, donde aprenderás a implementar pilas, la base
para construir pilas en Python son la programación orientada a objetos y las
listas.
FASE 1: Pila
En el ejercicio vas a definir una clase pila muy básica, con las siguientes
operaciones:
def EstaVacia(self):
if len(self.__items) == 0:
return True
else:
return False
def Retirar(self):
return self.__items.pop()
def MostrarPila(self):
print("Pila: ", self.__items,"<-- CIMA")
pila = Pila()
for i in range(10):
pila.Apilar(i)
pila.MostrarPila()
pilareves = Pila()
while not(pila.EstaVacia()):
pilareves.Apilar(pila.Retirar())
pilareves.MostrarPila()
def EstaVacia(self):
if len(self.__items) == 0:
return True
else:
return False
def Apilar(self, item):
self.__items.append(item)
def Retirar(self):
return self.__items.pop()
def LeerCima(self):
return self.__items[len(self.__items)-1]
def MostrarPila(self):
print("Pila: ", self.__items,"<-- CIMA")
def SimuladorPila():
fin = False
pila = Pila()
while not(fin):
opc = input("Opcion:")
if (opc=='1'):
item = input("Introduzca elemento a apilar: ")
pila.Apilar(item)
print("Elemento apilado: ",item)
elif(opc=='2'):
if pila.EstaVacia():
print("La pila está vacía, no puede retirarse ningún elemento")
else:
item = pila.LeerCima()
pila.Retirar()
print("Elemento retirado: ",item)
elif(opc=='3'):
if pila.EstaVacia():
print("La pila está vacía, no puede leerse la cima")
else:
print("La cima es: ", pila.LeerCima())
elif(opc=='4'):
if pila.EstaVacia():
print("La pila está vacía")
else:
print("La pila no está vacía")
elif(opc=='5'):
pila.MostrarPila()
elif(opc=='6'):
fin = 1
print ("""*****************
Simulador de Pila
*****************
Menu
1) Apilar
2) Retirar
3) Leer cima
4) ¿Está vacía?
5) Mostrar pila
6) Salir""")
SimuladorPila()
def EstaVacia(self):
if len(self.__items) == 0:
return True
else:
return False
def Retirar(self):
return self.__items.pop()
def LeerCima(self):
return self.__items[len(self.__items)-1]
def LeerFondo(self):
pilaauxiliar = Pila()
while not(self.EstaVacia()):
pilaauxiliar.Apilar(self.Retirar())
valorfondo = pilaauxiliar.LeerCima()
while not(pilaauxiliar.EstaVacia()):
self.Apilar(pilaauxiliar.Retirar())
return valorfondo
def NumeroElementos(self):
pilaauxiliar = Pila()
while not(self.EstaVacia()):
pilaauxiliar.Apilar(self.Retirar())
numeroelementos = 0
while not(pilaauxiliar.EstaVacia()):
self.Apilar(pilaauxiliar.Retirar())
numeroelementos = numeroelementos + 1
return numeroelementos
def MostrarPila(self):
print("Pila: ", self.__items,"<-- CIMA")
def SimuladorPila():
fin = False
pila = Pila()
while not(fin):
opc = input("Opcion:")
if (opc=='1'):
item = input("Introduzca elemento a apilar: ")
pila.Apilar(item)
print("Elemento apilado: ",item)
elif(opc=='2'):
if pila.EstaVacia():
print("La pila está vacía, no puede retirarse ningún elemento")
else:
item = pila.LeerCima()
pila.Retirar()
print("Elemento retirado: ",item)
elif(opc=='3'):
if pila.EstaVacia():
print("La pila está vacía, no puede leerse la cima")
else:
print("La cima es: ", pila.LeerCima())
elif(opc=='4'):
if pila.EstaVacia():
print("La pila está vacía, no puede leerse el fondo")
else:
print("El fondo es: ", pila.LeerFondo())
elif(opc=='5'):
if pila.EstaVacia():
print("La pila está vacía")
else:
print("La pila no está vacía")
elif(opc=='6'):
pila.MostrarPila()
elif(opc=='7'):
print("Número de elementos en la pila: ", pila.NumeroElementos())
elif(opc=='8'):
fin = 1
print ("""*****************
Simulador de Pila
*****************
Menu
1) Apilar
2) Retirar
3) Leer cima
4) Leer fondo
5) ¿Está vacía?
6) Número de elementos
7) Mostrar pila
8) Salir""")
SimuladorPila()
La siguiente imagen muestra un ejemplo de uso de los dos nuevos métodos
añadidos en el ejercicio:
Ahora eres capaz de…
En este quinto objetivo vamos a explicarte qué son las colas y cómo puedes
utilizarlas. Del mismo modo que en el objetivo anterior, es muy importante
que para este objetivo tengas claros los conceptos que explicamos en el libro
anterior sobre programación orientada a objetos, ya que, al igual que para las
pilas, es la base para la construcción de colas.
El objetivo está compuesto por una única fase en la que realizarás varios
ejercicios para aprender a utilizarlas.
Conceptos teóricos
Colas
Antes de entrar en detalles de qué son las colas, queremos que pienses en una
cola de un supermercado. Cuando vas a las cajas del supermercado a pagar la
compra te pones en una cola en la que las personas que están delante tuya
pagarán antes que tú y las personas que se vayan incorporando a la cola
después de ti pagarán después que tú. En las colas, el primero en entrar será
el primero en salir.
Las colas están compuestas por elementos en los que el primer elemento es el
elemento que más tiempo lleva en esta y, a la hora de “coger” un elemento de
la cola cogeremos el primer elemento de esta, y, a la hora de “dejar” un
elemento en la cola lo dejaremos en la última posición de esta.
Gráficamente:
Tal y como veremos en la fase, donde aprenderás a implementar colas, la
base para construir colas en Python son la programación orientada a objetos y
las listas.
FASE 1: Cola
En el ejercicio vas a definir una clase cola muy básica, con las siguientes
operaciones:
La clase pila que utilizará el ejercicio para cambiar el orden de la cola tendrá
los siguientes métodos:
def EstaVacia(self):
if len(self.__items) == 0:
return True
else:
return False
def Apilar(self, item):
self.__items.append(item)
def Retirar(self):
return self.__items.pop()
class Cola:
def __init__(self):
self.__items = []
def EstaVacia(self):
if len(self.__items) == 0:
return True
else:
return False
def Desencolar(self):
return self.__items.pop()
def MostrarCola(self):
print("Cola: ", self.__items,"<-- Primer elemento")
cola = Cola()
for i in range(10):
cola.Encolar(i)
cola.MostrarCola()
pila = Pila()
while not(cola.EstaVacia()):
pila.Apilar(cola.Desencolar())
while not(pila.EstaVacia()):
cola.Encolar(pila.Retirar())
cola.MostrarCola()
def EstaVacia(self):
if len(self.__items) == 0:
return True
else:
return False
def Desencolar(self):
return self.__items.pop()
def LeerPrimerElemento(self):
return self.__items[len(self.__items)-1]
def MostrarCola(self):
print("Cola: ", self.__items,"<-- Primer elemento")
def SimuladorCola():
fin = False
cola = Cola()
while not(fin):
opc = input("Opcion:")
if (opc=='1'):
item = input("Introduzca elemento a encolar: ")
cola.Encolar(item)
print("Elemento encolado: ",item)
elif(opc=='2'):
if cola.EstaVacia():
print("La cola está vacía, no puede desencolarse ningún elemento")
else:
item = cola.LeerPrimerElemento()
cola.Desencolar()
print("Elemento desencolado: ",item)
elif(opc=='3'):
if cola.EstaVacia():
print("La cola está vacía, no puede leerse ningún elemento")
else:
print("El primer elemento es: ", cola.LeerPrimerElemento())
elif(opc=='4'):
if cola.EstaVacia():
print("La cola está vacía")
else:
print("La cola no está vacía")
elif(opc=='5'):
cola.MostrarCola()
elif(opc=='6'):
fin = 1
print ("""*****************
Simulador de Cola
*****************
Menu
1) Encolar
2) Desencolar
3) Leer primer elemento
4) ¿Está vacía?
5) Mostrar cola
6) Salir""")
SimuladorCola()
def EstaVacia(self):
if len(self.__items) == 0:
return True
else:
return False
def Desencolar(self):
return self.__items.pop()
def LeerPrimerElemento(self):
return self.__items[len(self.__items)-1]
def LeerUltimoElemento(self):
colaauxiliar = Cola()
while not(self.EstaVacia()):
ultimoelemento = self.Desencolar()
colaauxiliar.Encolar(ultimoelemento)
while not(colaauxiliar.EstaVacia()):
self.Encolar(colaauxiliar.Desencolar())
return ultimoelemento
def NumeroElementos(self):
colaauxiliar = Cola()
numeroelementos = 0
while not(self.EstaVacia()):
numeroelementos = numeroelementos + 1
colaauxiliar.Encolar(self.Desencolar())
while not(colaauxiliar.EstaVacia()):
self.Encolar(colaauxiliar.Desencolar())
return numeroelementos
def MostrarCola(self):
print("Cola: ", self.__items,"<-- Primer elemento")
def SimuladorCola():
fin = False
cola = Cola()
while not(fin):
opc = input("Opcion:")
if (opc=='1'):
item = input("Introduzca elemento a encolar: ")
cola.Encolar(item)
print("Elemento encolado: ",item)
elif(opc=='2'):
if cola.EstaVacia():
print("La cola está vacía, no puede desencolarse ningún elemento")
else:
item = cola.LeerPrimerElemento()
cola.Desencolar()
print("Elemento desencolado: ",item)
elif(opc=='3'):
if cola.EstaVacia():
print("La cola está vacía, no puede leerse ningún elemento")
else:
print("El primer elemento es: ", cola.LeerPrimerElemento())
elif(opc=='4'):
if cola.EstaVacia():
print("La cola está vacía, no puede leerse ningún elemento")
else:
print("El último elemento es: ", cola.LeerUltimoElemento())
elif(opc=='5'):
if cola.EstaVacia():
print("La cola está vacía")
else:
print("La cola no está vacía")
elif(opc=='6'):
print("Número de elementos: ",cola.NumeroElementos())
elif(opc=='7'):
cola.MostrarCola()
elif(opc=='8'):
fin = 1
print ("""*****************
Simulador de Cola
*****************
Menu
1) Encolar
2) Desencolar
3) Leer primer elemento
4) Leer último elemento
5) ¿Está vacía?
6) Número de elementos
7) Mostrar cola
8) Salir""")
SimuladorCola()
El objetivo está compuesto por cinco fases en la que en cada una de ellas
realizarás varios ejercicios para aprender a utilizar cada uno de los módulos
de la librería estándar de Python que te explicaremos.
Conceptos teóricos
Librería estándar
Para incluir módulos en tus programas tienes que realizarlo con la sentencia
import de la siguiente forma al principio de tus programas:
import NombreLibrería
Una vez importada la librería podrás utilizar en tus programas todas las
clases, constantes y funciones que incluyan.
La librería estándar tiene una librería muy importante que no vamos a
explicarte en este objetivo, le dedicaremos el objetivo número 10 completo
dada la importancia que tiene, dicha librería es unittest.
FASE 1: Módulo random
randrange
Función que devuelve un número aleatorio en un rango especificado por
parámetro.
sample
Función que devuelve una lista de números aleatorios dentro de un rango
establecido por parámetro. La función tiene dos parámetros, el primero es el
rango sobre el que se seleccionarán los números aleatorios y el segundo es el
número de elementos que tendrá la lista que se devuelve.
random
Función que devuelve un número en coma flotante.
choice
Función que selecciona un elemento de la lista que recibe por parámetro al
azar.
La segunda fase del objetivo consiste en el aprendizaje del módulo math, que
te permitirá incluir en tus programas funciones y constantes matemáticas para
facilitarte aquellos desarrollos que realices que requieran operaciones
matemáticas complejas.
Recuerda que para poder utilizar las funciones que provee el módulo math
tienes que importarlo en tu código fuente utilizando la sentencia import math.
fabs
Función que retorna el valor absoluto del número especificado como
parámetro.
factorial
Función que calcula la factorial del número especificado como parámetro.
gcd
Función que calcula el máximo común divisor de dos números especificados
como parámetros.
isnan
Función que comprueba si el parámetro no es un número. La función
retornará False en caso de que sea un número y True en caso contrario.
log
Función que calcula el logaritmo en base X del número especificado como
parámetro. La función tiene dos parámetros, el primero es el número del que
se quiere calcular el logaritmo y el segundo la base del logaritmo.
pow
Función que calcula la potencia del número especificado como parámetro. La
función tiene dos parámetros, el primero de ellos es la base y el segundo el
exponente.
sqrt
Función que calcula la raíz cuadrada del número especificado como
parámetro.
acos
Función que calcula el arcocoseno en radianes del ángulo especificado como
parámetro.
asin
Función que calcula el arcoseno en radianes del ángulo especificado como
parámetro.
atan
Función que calcula la arcotangente en radianes del ángulo especificado
como parámetro.
cos
Función que calcula el coseno en radianes del ángulo especificado como
parámetro.
sin
Función que calcula el seno en radianes del ángulo especificado como
parámetro.
tan
Función que calcula la tangente en radianes del ángulo especificado como
parámetro.
degrees
Función que retorna el valor en grados del ángulo en radianes recibido como
parámetro.
radians
Función que retorna el valor en radianes del ángulo en grados recibido como
parámetro.
Recuerda que para poder utilizar las funciones que provee el módulo
statistics tienes que importarlo en tu código fuente utilizando la sentencia
import statistics.
mean
Función que calcula la media de un listado de números pasados como
parámetro.
median
Función que calcula la mediana de un listado de números pasados como
parámetro.
median_low
Función que calcula la mediana inferior de un listado de números pasados
como parámetro.
median_high
Función que calcula la mediana superior de un listado de números pasados
como parámetro.
mode
Función que calcula la moda de un listado de números pasados como
parámetro.
variance
Función que calcula la varianza de un listado de números pasados como
parámetro.
Recuerda que para poder utilizar las funciones que provee el módulo datetime
tienes que importarlo en tu código fuente utilizando la sentencia import
datetime.
En el objetivo vamos a explicarte una serie de funciones que son básicas para
trabajar con fechas, existen funciones mucho más complejas pero que no se
utilizan mucho. Las funciones que vamos a ver son las siguientes:
datetime.now
Función que retorna la fecha y la hora de ahora mismo.
date.today
Función que retorna el día de hoy.
date
Función que permite crear un objeto de tipo fecha pasándole como
parámetros el año, el mes y el día.
datetime
Función que permite crear un objeto de tipo Datetime pasándole como
parámetros el año, el mes, el día, la hora, los minutos, los segundos y los
microsegundos.
Recuerda que para poder utilizar las funciones que provee el módulo os
tienes que importarlo en tu código fuente utilizando la sentencia import os.
Para poder utilizar las funciones que provee el módulo shutil tienes que
importarlo en tu código fuente utilizando la sentencia import shutil.
getcwd
Función que devuelve el directorio actual de trabajo de la aplicación.
chdir
Función que cambia el directorio de trabajo de la aplicación al pasado por
parámetro.
getpid
Función que devuelve el identificador del proceso del aplicativo.
getuid
Función que devuelve el identificador del usuario del proceso del aplicativo.
listdir
Función que lista el contenido del directorio de trabajo actual.
mkdir
Función que crea un nuevo directorio dentro del directorio de trabajo actual.
rename
Función que renombra un fichero.
copy
Función que realizar la copia del fichero parametrizado en uno nuevo con el
nombre especificado por parámetro.
move
Función que mueve el fichero especificado por parámetro a la ruta
especificada por parámetro.
Remove
Función que elimina el fichero especificado como parámetro.
El ejercicio consiste en borrar tanto los ficheros como el directorio que se han
utilizado en el ejercicio anterior. El código fuente es el siguiente:
import os
import shutil
os.chdir("/Users/alfre/Desktop/Ejercicios 6-5/")
print("Directorio de trabajo: ",os.getcwd())
print("Contenido del directorio: ", os.listdir())
print("¡Eliminar el directorio NuevoDirectorio!")
shutil.rmtree("NuevoDirectorio")
print("Contenido del directorio: ", os.listdir())
print("¡Borrando el fichero ejemplo.txt!")
os.remove("ejemplo.txt")
print("Contenido del directorio: ", os.listdir())
Los pasos básicos para resolver un problema de forma paralela son los
siguientes:
Ventajas y desventajas
La programación paralela presenta una serie de ventajas respecto a la
programación secuencial, son las siguientes:
Procesos VS Hilos
El GIL funciona de forma muy sencilla, aquel hilo que “coja” el GIL será el
hilo que se esté ejecutando hasta que “lo suelte”. De este modo, el GIL “se va
pasando” de hilo en hilo previniendo la ejecución simultánea de los mismos.
Veámoslo gráficamente:
FASE 1: Hilos
Python dispone de una librería llamada threading que es la que contiene todo
lo que necesitas para trabajar con hilos. Para poder utilizarla tienes que
importarla en tu programa, del mismo modo que importas otras librerías:
import threading
Variable = threading.Thread(target=NombreFuncion)
Una vez has creado el hilo el siguiente paso es inicializarlo, para ello es
necesario utilizar el método start, de esta forma el hilo empezará a ejecutarse:
Variable.start()
Los hilos tienen una funcionalidad que permite detener el programa hasta que
termina de ejecutarse el hilo, hablamos del método join.
Variable.join()
La librería threading nos permite obtener el nombre del hilo que se está
ejecutando y el identificador de este, funcionalidades muy útiles que te
permitirán tener una visualización del estado de la ejecución de tu programa.
Las sentencias son las siguientes:
threading.current_thread().getName()
threading.current_thread().ident
El primer ejercicio de la fase tiene como objetivo que aprendas a crear hilos,
ejecutarlos y que veas la diferencia con la ejecución de la función con hilo y
sin hilo.
def MostrarInformacion():
print('Hilo:',threading.current_thread().getName(),'con identificador:', threading.current_thread().ident)
Observa las diferencias entre lo que muestra por pantalla la función cuando la
ejecutas desde el programa principal (MainThread) y cuando lo ejecutas
desde un hilo (Thread-X). Puedes observar que el nombre de cada hilo es
diferente, pero el identificador es el mismo ya que los identificadores son
reutilizables dentro del mismo programa.
def MostrarInformacion():
print('Hilo:',threading.current_thread().getName(),'con identificador:', threading.current_thread().ident)
threading.Thread(name = 'NombreHilo',target=NombreFuncion)
Del mismo modo que en el ejercicio número uno, vamos a añadir pequeñas
paradas (sleep) para que veas cómo se muestra la información del hilo. El
código fuente es el siguiente:
import time
import threading
def MostrarInformacion():
print('Hilo:',threading.current_thread().getName(),'con identificador:', threading.current_thread().ident)
def MostrarInformacion():
print('Hilo:',threading.current_thread().getName(),'con identificador:', threading.current_thread().ident)
def MostrarInformacion():
print('Hilo:',threading.current_thread().getName(),'con identificador:', threading.current_thread().ident)
def MostrarInformacion():
print('Hilo:',threading.current_thread().getName(),'con identificador:', threading.current_thread().ident)
threading.Thread(target=NombreFuncion,args=(Parametros),kwargs=
{ListaParámetrosVariables})
HILOS = 3
HILOS = 3
for num_hilo in range(HILOS):
comienzo = num_hilo*10
fin = 10 + num_hilo*10
hilo = threading.Thread(target=MostrarInformacion,args=(num_hilo,),kwargs={'comienzo':comienzo, 'fin':fin})
hilo.start()
import multiprocessing
Variable = multiprocessing.Process(target=NombreFuncion())
Una vez has creado el proceso el siguiente paso es inicializarlo, para ello es
necesario utilizar el método start, de esta forma el proceso empezará a
ejecutarse:
Variable.start()
Los procesos tienen una funcionalidad que permite detener el programa hasta
que termina de ejecutarse el proceso, hablamos del método join.
Variable.join()
multiprocessing.current_process().name
os.getpid()
def MostrarInformacion():
print("PID: %s, Nombre proceso: %s" % (
os.getpid(),
multiprocessing.current_process().name)
)
if __name__ == '__main__':
MostrarInformacion()
proceso1 = multiprocessing.Process(target=MostrarInformacion)
proceso2 = multiprocessing.Process(target=MostrarInformacion)
proceso3 = multiprocessing.Process(target=MostrarInformacion)
proceso1.start()
proceso2.start()
proceso3.start()
proceso1.join()
proceso2.join()
proceso3.join()
def MostrarInformacion():
print(“PID: %s, Nombre proceso: %s, Nombre hilo: %s” % (
os.getpid(),
multiprocessing.current_process().name,
threading.current_thread().name))
time.sleep(1)
def Proceso():
hilo1 = threading.Thread(target=MostrarInformacion)
hilo2 = threading.Thread(target=MostrarInformacion)
hilo1.start()
hilo2.start()
hilo1.join()
hilo2.join()
if __name__ == ‘__main__’:
proceso1 = multiprocessing.Process(target=Proceso)
proceso2 = multiprocessing.Process(target=Proceso)
proceso3 = multiprocessing.Process(target=Proceso)
proceso1.start()
proceso2.start()
proceso3.start()
proceso1.join()
proceso2.join()
proceso3.join()
if __name__ == ‘__main__’:
NUM_PROCESOS = 3
En este octavo objetivo vamos a explicarte qué son las bases de datos y cómo
se utilizan en Python. Además, aprenderás los conceptos básicos del lenguaje
que se utiliza para trabajar con bases de datos (SQL) y del modelo entidad-
relación.
El objetivo está compuesto por las cinco fases que se indican a continuación:
Las bases de datos son un conjunto de datos de cualquier tipo que son
almacenados para ser usados posteriormente. En otras palabras, una base de
datos almacena grandes cantidades de información que puede ser utilizada o
modificada por aplicaciones informáticas.
Las bases de datos son sistemas complejos que son manejados y gestionados
por un software específico llamado Sistema Gestor de Bases de Datos
(SGBD). Los SGBD permiten a los usuarios de las bases de datos no tener
que preocuparse por cosas como el almacenamiento físico de los datos, su
consistencia, la seguridad, etc. Es decir, los SGBD se sitúan entre el usuario y
la propia base de datos para facilitar las operaciones que el usuario hace con
la base de datos, no teniendo que preocuparse por ésta. Así sería
gráficamente:
Beneficios de uso
Las tablas siempre van a tener un nombre y van a estar compuestas por
atributos en sus columnas y por tuplas de valores en sus filas. La siguiente
imagen muestra como sería una tabla de forma conceptual:
Tal y como puedes ver, en el ejemplo, hemos definido una tabla llamada
Persona que tiene como atributos Nombre, Apellido y Telefono. La tupla
número uno está compuesta por los valores (Leonardo, Da Vinci,
666777888). La tupla número dos está compuesta por los valores (Nikola,
Tesla, 654321987).
Por definición, los atributos de las tablas son valores escalares, esto quiere
decir que en cualquier posición de la tabla existirá un único valor.
Por último, vamos a explicarte lo que son las claves. En el modelo de bases
de datos relacional existen dos tipos de claves:
Claves primarias: es un atributo cuyo valor no puede estar duplicado
en una misma tabla y permite identificar a cada registro de manera
unívoca.
Claves foráneas: es un atributo en una tabla que hace referencia a la
clave primaria de otra tabla.
El tipo de dato que pueden contener los atributos de las tablas tiene que ser
especificado cuando creas la tabla. Hay una gran variedad de tipos de datos,
pero nosotros en el objetivo únicamente vamos a trabajar los tipos de datos
enteros y cadena de texto, que son los más comunes.
Modelo entidad-relación
SQLite
El modelo está compuesto por una entidad llamada “Teléfono Móvil” y otra
“Fabricante”. La relación entre ambas entidades es que un teléfono móvil
estará fabricado por un fabricante y un fabricante puede tener cero o muchos
teléfonos móviles fabricados.
Llegados a este punto ya tienes la base de datos creada para poder continuar
con las siguientes fases del objetivo. La base de datos, al igual que los
ejercicios, se encuentra disponible en el material descargable que
proporcionamos con el libro.
FASE 2: Insertando datos
Veámoslo en detalle:
Lo primero que tienes que hacer para utilizar bases de datos SQLite es
importar el módulo de Python que te permitirá trabajar con ellas:
import sqlite3
Variable = sqlite3.connect('RutaYNombreBaseDatos')
En el parámetro que recibe el método connect tendrás que indicar la ruta del
fichero de la base de datos. El método de conexión devuelve la conexión a la
base de datos, por tanto, tienes que asignarlo a una variable para poder
interactuar con la misma.
Por último, hay que cerrar la conexión a la base de datos con el método
close() de la variable obtenida al realizar la conexión con la base de datos.
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
cursor.execute("INSERT INTO Fabricante VALUES(?,?,?,?,?)", fabricante)
database.commit()
print('¡Registro insertado!')
database.close()
Al ejecutar el ejercicio verás la siguiente salida:
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
cursor.execute("INSERT INTO Fabricante VALUES(?,?,?,?,?)", fabricante)
database.commit()
print('¡Fabricante insertado!')
database.commit()
print('¡Teléfonos insertados!')
database.close()
La tercera fase del objetivo consiste en aprender a leer información que está
almacenada en la base de datos. Comúnmente las lecturas a base de datos se
llaman consultas.
Veámosla en detalle:
Los pasos a seguir en el código fuente para realizar lecturas son parecidos a
los que vimos para las inserciones, pero sin la consolidación de los datos
utilizando commit:
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
database.close()
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
database.close()
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
database.close()
Veámosla en detalle:
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
database.close()
import sqlite3
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
database.close()
Veamos en DB Browser for SQLite cómo han quedado ambas tablas después
de las modificaciones. La siguiente imagen muestra la tabla Fabricante:
Veámoslo en detalle:
Los pasos a seguir en el código fuente para realizar borrados son los mismos
que vimos para inserciones y modificaciones:
database = sqlite3.connect('Telefonos.db')
cursor = database.cursor()
cursor.execute("SELECT * FROM Telefono")
print("Mostrando todos los teléfonos:")
for registro in cursor:
print(registro)
database.close()
En este noveno objetivo vamos a enseñarte a crear tus propios módulos para
que puedas utilizarlos en todos tus programas del mismo modo que utilizabas
la librería estándar que explicamos en el objetivo sexto.
El objetivo está compuesto por una única fase en la que aprenderás a crear
módulos que podrás reutilizar en tus programas.
Conceptos teóricos
La primera y única fase del objetivo consiste en aprender a crear y utilizar tus
propios módulos.
def Restar(minuendo,sustraendo):
return minuendo-sustraendo
def Multiplicar(multiplicando,multiplicador):
return multiplicando*multiplicador
def Dividir(dividendo,divisor):
try:
resultado = dividendo/divisor
return resultado
except ZeroDivisionError:
return -1
def Sumar():
sumando1 = int(input("Introduce primer sumando:"))
sumando2 = int(input("Introduce segundo sumando:"))
print ("Resultado:", operacionesaritmeticas.Sumar(sumando1,sumando2))
def Restar():
minuendo = int(input("Introduce el minuendo:"))
sustraendo = int(input("Introduce el sustraendo:"))
print ("Resultado:", operacionesaritmeticas.Restar(minuendo,sustraendo))
def Multiplicar():
multiplicando = int(input("Introduce el multiplicando:"))
multiplicador = int(input("Introduce el multiplicador:"))
print ("Resultado:", operacionesaritmeticas.Multiplicar(multiplicando,multiplicador))
def Dividir():
dividendo = int(input("Introduce el dividendo:"))
divisor = int(input("Introduce el divisor:"))
print ("Resultado:", operacionesaritmeticas.Dividir(dividendo,divisor))
def Calculadora():
fin = False
while not(fin):
opc = int(input("Opcion:"))
if (opc==1):
Sumar()
elif(opc==2):
Restar()
elif(opc==3):
Multiplicar()
elif(opc==4):
Dividir()
elif(opc==5):
fin = 1
NombreMódulo.Operación.
direccion1 = direccion.Direccion()
En este décimo objetivo vamos a explicarte qué son las pruebas unitarias, por
qué son importantes y qué beneficios tiene su uso.
El objetivo está compuesto por una única fase en la que, utilizando el módulo
de la librería estándar unittest, aprenderás a utilizar pruebas unitarias.
Conceptos teóricos
Realizar pruebas del código fuente que escribes es una de las tareas más
importantes a la hora de desarrollar software. Cuando se empieza a programar
se suele entender que realizar pruebas es ejecutar el código y comprobar que
el código hace lo que tiene que hacer, pero, existe un mecanismo que permite
realizar pruebas de código fuente de forma automática, las pruebas unitarias.
La teoría sobre las pruebas unitarias dice que se deben escribir a medida que
escribes el código fuente, que vayas añadiendo pruebas a cada función,
método o módulo a medida que lo escribes, para, de este modo, asegurar el
correcto funcionamiento del código que estás escribiendo. Pero, de la teoría a
lo que realmente suele pasar en muchos proyectos hay una distancia muchas
veces insalvable y que provoca la baja calidad de muchos proyectos. En este
caso se pueden identificar dos escenarios diferentes:
Ventajas de uso
El uso de pruebas unitarias tiene una serie de ventajas que nos gustaría
resaltar:
Librería unittest
Los resultados que una prueba puede devolver son los siguientes:
class Pruebas(unittest.TestCase):
def testOK(self):
pass
unittest.main()
class Pruebas(unittest.TestCase):
def test(self):
raise AssertionError()
unittest.main()
unittest.main()
def MayorQue(num1,num2):
if num1>num2:
return True
else:
return False
class Pruebas(unittest.TestCase):
def test(self):
self.assertTrue(MayorQue(7,5))
unittest.main()
def MayorQue(num1,num2):
if num1<num2:
return True
else:
return False
class Pruebas(unittest.TestCase):
def test(self):
self.assertTrue(MayorQue(7,5))
unittest.main()
class Pruebas(unittest.TestCase):
def test_suma(self):
self.assertEqual(operacionesaritmeticas.Sumar(8,9),17)
def test_resta(self):
self.assertEqual(operacionesaritmeticas.Restar(9,3),6)
def test_multiplicar(self):
self.assertEqual(operacionesaritmeticas.Multiplicar(5,6),30)
def test_dividir(self):
self.assertEqual(operacionesaritmeticas.Dividir(9,3),3)
unittest.main()
En este undécimo objetivo vamos a explicarte qué son los sockets y cómo
puedes construir sistemas software basados en ellos.
Los sockets son el mecanismo que utilizan dos computadoras para poder
hablar entre si a través de la red. Cada computadora utilizará un socket de su
sistema para comunicarse con un socket del sistema de la otra computadora,
y, mediante ellos ambas computadoras podrán intercambiar mensajes e
información.
Puertos
Para explicar los puertos necesitamos que veas la dirección IP como una
dirección de una calle y los puertos como los diferentes pisos que hay en esa
dirección. Piensa por un momento en la dirección “Calle Mayor 3” y
aseméjala con las direcciones IP, pues, las diferentes viviendas que haya en
esa calle (1ªA, 4ºB, 3ºC, etc) aseméjalos con los puertos que puede tener una
dirección IP.
Puertos reservados
Si quieres saber más sobre todo lo que controla la IANA puedes verlo aquí:
https://www.iana.org.
¡Todo junto!
Llegados a este punto veamos cómo funciona todo esto junto con un ejemplo.
Por otro lado, vamos a tener otra computadora, el cliente, que tiene la
dirección IP 172.16.12.246 y que va a ejecutar una aplicación que se
conectará y se comunicará con el servidor. Para realizar la comunicación con
el servidor el cliente abrirá un socket en el conjunto de puertos dinámicos
para poder comunicarse, por ejemplo, el 49353.
Microsoft Windows
A continuación, tienes una imagen del mensaje que verás con la información
de la IP en caso utilizar una conexión Wi-Fi:
Unix y Mac
Para sistemas operativos Unix y Mac sigue los siguientes pasos:
Python posee una librería que permite utilizar sockets en tus aplicaciones y
que tendrás que importarla en el código fuente de la siguiente manera:
import socket
socket: método que devuelve una instancia de tipo socket para que la
utilices en tu programa.
gethostname: método que devuelve el nombre de la máquina.
bind: método que configura el socket devuelto por el socket con el
nombre de la máquina y el puerto que utilizará.
listen: método que abre el puerto del socket y lo pone en modo
escucha.
connect: método que permite al cliente conectarse a un socket abierto
por el servidor.
accept: método mediante el cual el servidor acepta la conexión de un
cliente. Devuelve un objeto que permite manejar la conexión con el
cliente y también una cadena de texto con la dirección IP del cliente.
close: cierra el socket.
send: permite enviar información a través del socket al otro extremo,
bien sea el cliente o el servidor.
recv: permite recibir información a través del socket abierto.
Servidor
import socket
s = socket.socket()
nombre = socket.gethostname()
puerto = 12345
s.bind((nombre, puerto))
s.listen()
while True:
c, addr = s.accept()
print('Conexión recibida de ', addr)
c.send(b'Gracias por conectar')
c.close()
Cliente
import socket
s = socket.socket()
ip = "127.0.0.1"
puerto = 12345
s.connect((ip, puerto))
print('Información recibida: ',s.recv(1024))
s.close()
Servidor
import socket
s = socket.socket()
nombre = socket.gethostname()
puerto = 12345
s.bind((nombre, puerto))
s.listen()
while True:
c, addr = s.accept()
print('Conexión recibida de ', addr)
info = b'Gracias por conectar'
print('Información enviada: ', info)
c.send(info)
print('Informacion recibida: ',c.recv(1024))
info = b'El gusto es mio'
print('Información enviada: ', info)
c.send(info)
c.close()
Cliente
import socket
s = socket.socket()
ip = "127.0.0.1"
puerto = 12345
s.connect((ip, puerto))
print('Información recibida: ',s.recv(1024))
info = b'Ya me desconecto, un placer'
print('Información enviada: ', info)
s.send(info)
print('Información recibida: ',s.recv(1024))
s.close()
Servidor
import socket
s = socket.socket()
nombre = socket.gethostname()
puerto = 12345
s.bind((nombre, puerto))
s.listen()
fin = False
c, addr = s.accept()
print('Conexión recibida de ', addr)
Cliente
import socket
s = socket.socket()
ip = "127.0.0.1"
puerto = 12345
s.connect((ip, puerto))
fin = False
Fíjate cómo hemos convertido en este ejercicio las cadenas de texto a bytes.
Mediante el método bytes que recibe la cadena de texto y el modo de
codificarla (“utf-8”) convertiremos la cadena de texto en una cadena de bytes
para poder enviarla. Para decodificar la información que recibimos
utilizaremos el método decode, que devolverá la cadena de texto resultante de
la conversión.
La ejecución de los aplicativos tienes que realizarla desde la consola o
terminal. Veamos un ejemplo de ejecución:
FASE 3: Errores comunes
La tercera fase del objetivo consiste en explicarte los errores más comunes
que puedes recibir a la hora de trabajar con sockets.
Para simular el error lo que vamos a hacer es ejecutar un cliente sin tener un
servidor abierto, el código fuente es el siguiente:
import socket
s = socket.socket()
ip = "127.0.0.1"
puerto = 12345
s.connect((ip, puerto))
s.close()
s = socket.socket()
nombre = socket.gethostname()
puerto = 888
s.bind((nombre, puerto))
s.listen()
while True:
c, addr = s.accept()
print('Conexión recibida de ', addr)
c.send(b'Gracias por conectar')
c.close()
Para simular el error lo que vamos a hacer es ejecutar un servidor dos veces.
El código fuente es el siguiente:
import socket
s = socket.socket()
nombre = socket.gethostname()
puerto = 12345
s.bind((nombre, puerto))
s.listen()
while True:
c, addr = s.accept()
print('Conexión recibida de ', addr)
c.send(b'Gracias por conectar')
c.close()
Ejecutando el código dos veces obtendremos el error en la segunda ejecución,
tal y como puedes comprobar en la siguiente imagen:
FASE 4: Servidor con múltiples clientes
Para poder tener un servidor que acepte más de un único cliente lo que tienes
que hacer es crear un hilo para cada cliente que se conecte al servidor. Ese
hilo será el encargado de realizar las comunicaciones con el cliente y de
cerrar la conexión cuando se acabe la interacción entre ambos.
El código fuente del ejercicio es el siguiente:
Servidor
import socket
import threading
def HiloCliente(conexion,direccion):
conexion.send(str.encode('Bienvenido al servidor'))
while True:
recibido = conexion.recv(1024)
print(direccion,'=',recibido.decode('utf-8'))
respuesta = 'El servidor dice: ' + recibido.decode('utf-8')
if not recibido:
break
conexion.send(str.encode(respuesta))
conexion.close()
SocketServidor = socket.socket()
host = '127.0.0.1'
puerto = 30000
SocketServidor.bind((host, puerto))
print('¡Esperando conexiones!')
SocketServidor.listen()
while True:
cliente, direccion = SocketServidor.accept()
print('Nuevo cliente: ' + direccion[0] + ':' + str(direccion[1]))
hilo = threading.Thread(target=HiloCliente,args=(cliente,direccion[0] + ':' + str(direccion[1]),))
hilo.start()
SocketServidor.close()
Cliente
import socket
SocketCliente = socket.socket()
host = '127.0.0.1'
puerto = 30000
SocketCliente.connect((host, puerto))
respuesta = SocketCliente.recv(1024)
print(respuesta.decode('utf-8'))
while True:
Input = input('Escribe algo: ')
SocketCliente.send(str.encode(Input))
respuesta = SocketCliente.recv(1024)
print(respuesta.decode('utf-8'))
SocketCliente.close()
Tal y como puedes ver, hemos arrancado tres clientes y hemos enviado
mensajes diferentes con cada uno de ellos. Recuerda que puedes arrancar
tantos clientes como quieras.
Ahora eres capaz de…
Veamos cómo queda la tabla tras crearla con DB Browser for SQLite:
La entidad teléfono estará compuesta por los siguientes atributos:
Veamos cómo queda la tabla tras crearla con DB Browser for SQLite:
Servidor
Clase Teléfono
Clase Dirección
La clase Dirección es la que almacenará la información de la entidad
Dirección de la base de datos. Estará compuesta por los siguientes atributos:
Clase Contacto
class Contacto:
def __init__(self, idcontacto, nombre, apellidos, fechanacimiento):
self.__Id = idcontacto
self.__Nombre = nombre
self.__Apellidos = apellidos
self.__FechaNacimiento = fechanacimiento
self.__ListaTelefonos = []
self.__ListaDirecciones = []
def GetId(self):
return self.__Id
def GetNombre(self):
return self.__Nombre
def GetApellidos(self):
return self.__Apellidos
def GetFechaNacimiento(self):
return self.__FechaNacimiento
def GetListaTelefonos(self):
return self.__ListaTelefonos
def GetListaDirecciones(self):
return self.__ListaDirecciones
def SetNombre(self, nombre):
self.__Nombre = nombre
def SetApellidos(self, apellidos):
self.__Apellidos = apellidos
def SetFechaNacimiento(self, fechanacimiento):
self.__FechaNacimiento = fechanacimiento
def SetListaTelefonos(self, listatelefonos):
self.__ListaTelefonos = listatelefonos
def SetListaDirecciones(self, listadirecciones):
self.__ListaDirecciones = listadirecciones
class BaseDatos:
def __init__(self):
self.__ruta = 'Contactos.db'
def LeerContactos(self):
try:
database = sqlite3.connect(self.__ruta)
cursor = database.cursor()
contactos = []
database.close()
return contactos
except:
print("ERROR: No se pueden leer los contactos")
return []
telefonos = []
for registro in cursortelefono:
telefonos.append(Telefono.Telefono(registro[0],registro[1],registro[2]))
return telefonos
except:
print("ERROR: No se pueden leer los teléfonos")
return []
direcciones = []
contactos = []
database.close()
return contactos
except:
print("ERROR: No se pueden leer contactos por nombre")
return []
contactos = []
database.close()
return contactos
except:
print("ERROR: No se pueden leer contactos por teléfono")
return []
infocontacto = (contacto.GetNombre(),contacto.GetApellidos(),contacto.GetFechaNacimiento())
cursor.execute("INSERT INTO Contacto (Nombre,Apellidos,FechaNacimiento) VALUES(?,?,?)", infocontacto)
contactoid = cursor.lastrowid
database.commit()
return True
except:
print("ERROR: No se puede insertar el contacto")
return False
database.commit()
return True
except:
print("ERROR: No se puede borrar el contacto")
return False
Módulo de conversión
def StringAContacto(cadena):
try:
print(cadena)
# Obtención de los datos del contacto y creación del objeto con los valores
datoscontacto = cadena.split("#")[0].split("|")
contacto = Contacto.Contacto(0,datoscontacto[0],datoscontacto[1],datoscontacto[2])
if len(datostelefono)>0:
telefonos = []
# Procesamiento de todos los teléfonos y almacenamiento en una lista
for item in datostelefono:
telefono = Telefono.Telefono(0,item.split("|")[0],item.split("|")[1])
telefonos.append(telefono)
# Añade los teléfonos al contacto
contacto.SetListaTelefonos(telefonos)
if len(datosdirecciones)>0:
direcciones = []
# Procesamiento de todas las direcciones y almacenamiento en una lista
for item in datosdirecciones:
direccion = Direccion.Direccion(0,item.split("|")[0],item.split("|")[1],item.split("|")[2],item.split("|")[3])
direcciones.append(direccion)
# Añade las direcciones a la lista
contacto.SetListaDirecciones(direcciones)
return contacto
except:
print("ERROR: No puede convertirse la cadena a tipo contacto")
return None
def ContactosAString(contactos):
try:
cadena = ""
# Cada contacto será insertado en la cadena uno a uno
for contacto in contactos:
# Datos del contacto
cadena += "*"
cadena += contacto.GetNombre()
cadena += "|"
cadena += contacto.GetApellidos()
cadena += "|"
cadena += contacto.GetFechaNacimiento()
# Datos de sus teléfonos
cadena += "#"
listatelefonos = contacto.GetListaTelefonos()
if type(listatelefonos) != type(None):
for telefono in listatelefonos:
cadena += "-"
cadena += str(telefono.GetNumeroTelefono())
cadena += "|"
cadena += str(telefono.GetDescripcion())
# Datos de sus direcciones
cadena += "#"
listadirecciones = contacto.GetListaDirecciones()
if type(listadirecciones) != type(None):
for direccion in listadirecciones:
cadena += "-"
cadena += str(direccion.GetCalle())
cadena += "|"
cadena += str(direccion.GetPiso())
cadena += "|"
cadena += str(direccion.GetCiudad())
cadena += "|"
cadena += str(direccion.GetCodigoPostal())
return cadena
except:
print("ERROR: No puede convertirse el tipo contacto a cadena de texto")
return None
Módulo de comunicaciones
def HiloCliente(conexion,direccion):
fin = False
while not fin:
try:
recibido = conexion.recv(1024)
recibido = recibido.decode('utf-8')
if recibido == "5":
fin = True
mensaje = str(ProcesarMensaje(recibido))
conexion.send(str.encode(mensaje))
except:
print("ERROR: Hilo cliente")
fin = True
conexion.close()
def ProcesarMensaje(mensaje):
try:
listamensaje = mensaje.split('&')
# Buscar contacto por nombre
if listamensaje[0] == "1" and listamensaje[1] == "1":
return BuscarContactoNombre(listamensaje[2])
# Buscar contacto por teléfono
if listamensaje[0] == "1" and listamensaje[1] == "2":
return BuscarContactoTelefono(listamensaje[2])
if listamensaje[0] == "2":
return CrearContacto(listamensaje[1])
if listamensaje[0] == "3" and listamensaje[1] == "1":
return BorrarContactoNombre(listamensaje[2])
if listamensaje[0] == "3" and listamensaje[1] == "2":
return BorrarContactoTelefono(listamensaje[2])
if listamensaje[0] == "4":
return BuscarTodosLosContactos()
except:
print("ERROR: Procesando el mensaje recibido")
return ""
def CrearContacto(contactostring):
contacto = Conversion.StringAContacto(contactostring.lstrip("*"))
basedatos = BaseDatos.BaseDatos()
if basedatos.InsertarContacto(contacto) == True:
return "1"
else:
return "0"
def BuscarTodosLosContactos():
basedatos = BaseDatos.BaseDatos()
datos = basedatos.LeerContactos()
if len(datos)>0:
return Conversion.ContactosAString(datos)
else:
return "0"
def BuscarContactoNombre(nombre):
basedatos = BaseDatos.BaseDatos()
datos = basedatos.LeerContactosNombre(nombre)
if len(datos)>0:
return Conversion.ContactosAString(datos)
else:
return "0"
def BuscarContactoTelefono(telefono):
basedatos = BaseDatos.BaseDatos()
datos = basedatos.LeerContactosTelefono(telefono)
if len(datos)>0:
return Conversion.ContactosAString(datos)
else:
return "0"
def BorrarContactoNombre(nombre):
basedatos = BaseDatos.BaseDatos()
datos = basedatos.LeerContactosNombre(nombre)
respuesta = "1"
for contacto in datos:
if basedatos.BorrarContactoId(contacto.GetId()) == False:
respuesta = "0"
return respuesta
def BorrarContactoTelefono(telefono):
basedatos = BaseDatos.BaseDatos()
datos = basedatos.LeerContactosTelefono(telefono)
respuesta = "1"
for contacto in datos:
if basedatos.BorrarContactoId(contacto.GetId()) == False:
respuesta = "0"
return respuesta
Programa principal
El programa principal lo único que va a hacer es abrir un socket para que los
clientes puedan conectarse y cada vez que reciba la conexión de un cliente
creará un hilo que es el que se encargará de la gestión de las comunicaciones
con dicho cliente.
SocketServidor = socket.socket()
host = '127.0.0.1'
puerto = 30000
SocketServidor.bind((host, puerto))
SocketServidor.listen()
print('¡Servidor arrancado!')
while True:
cliente, direccion = SocketServidor.accept()
print('Nuevo cliente conectado: ' + direccion[0] + ':' + str(direccion[1]))
hilo = threading.Thread(target=Comunicacion.HiloCliente,args=(cliente,direccion[0] + ':' + str(direccion[1]),))
hilo.start()
SocketServidor.close()
Cliente
Clase Teléfono
Clase Dirección
Clase Contacto
class Contacto:
def __init__(self):
self.__Id = ""
self.__Nombre = ""
self.__Apellidos = ""
self.__FechaNacimiento = ""
self.__ListaTelefonos = []
self.__ListaDirecciones = []
def GetId(self):
return self.__Id
def GetNombre(self):
return self.__Nombre
def GetApellidos(self):
return self.__Apellidos
def GetFechaNacimiento(self):
return self.__FechaNacimiento
def GetListaTelefonos(self):
return self.__ListaTelefonos
def GetListaDirecciones(self):
return self.__ListaDirecciones
def SetNombre(self, nombre):
self.__Nombre = nombre
def SetApellidos(self, apellidos):
self.__Apellidos = apellidos
def SetFechaNacimiento(self, fechanacimiento):
self.__FechaNacimiento = fechanacimiento
def SetListaTelefonos(self, listatelefonos):
self.__ListaTelefonos = listatelefonos
def SetListaDirecciones(self, listadirecciones):
self.__ListaDirecciones = listadirecciones
Módulo de visualización
El módulo de visualización se encarga de mostrar todos los mensajes por
pantalla. El módulo está compuesto por las siguientes funciones:
def MostrarMenu():
print ("""Menu
1) Ver contacto
2) Crear contacto nuevo
3) Borrar contacto
4) Mostrar todos los contactos
5) Salir""")
def MostrarMenuBuscar():
print ("""Buscar contactos:
1) Nombre
2) Telefono
3) Volver""")
def MostrarMenuBorrar():
print ("""Borrar contactos por:
1) Nombre
2) Telefono
3) Volver""")
def ObtenerOpcion(texto):
leido = False
while not leido:
try:
numero = int(input(texto))
except ValueError:
print("Error: Tienes que introducir un numero.")
else:
leido = True
return numero
def MostrarContactos(contactos):
try:
print("##### CONTACTOS #####")
if len(datostelefono)>0:
for telefono in datostelefono:
print("Telefono: ", telefono.split("|")[0], "(",telefono.split("|")[1],")")
if len(datosdirecciones)>0:
for direccion in datosdirecciones:
print("Dirección: ", direccion.split("|")[0],direccion.split("|")[1],",",direccion.split("|")[2],",",direccion.split("|")[3])
print("#####################")
except:
print("ERROR: No se pueden mostrar los contactos")
def ProcesoCrearContacto():
try:
print("##### NUEVO CONTACTO #####")
nuevocontacto = Contacto.Contacto()
nuevocontacto.SetNombre(input((">Introduce el nombre del contacto: ")))
nuevocontacto.SetApellidos(input((">Introduce los apellidos del contacto: ")))
nuevocontacto.SetFechaNacimiento(input((">Introduce la fecha de nacimiento del contacto: ")))
telefonos = []
fin = ""
while fin != "No":
fin = input(">¿Quieres añadir un teléfono? Si / No:")
if fin == "Si":
nuevotelefono = Telefono.Telefono()
nuevotelefono.SetNumeroTelefono(input((">Introduce el telefono del contacto: ")))
nuevotelefono.SetDescripcion(input((">Introduce la descripción del telefono: ")))
telefonos.append(nuevotelefono)
nuevocontacto.SetListaTelefonos(telefonos)
direcciones = []
fin = ""
while fin != "No":
fin = input(">¿Quieres añadir una direccion? Si / No:")
if fin == "Si":
nuevadireccion = Direccion.Direccion()
nuevadireccion.SetCalle(input((">Introduce la calle de la direccion del contacto: ")))
nuevadireccion.SetPiso(input((">Introduce el piso de la direccion del contacto: ")))
nuevadireccion.SetCiudad(input((">Introduce la ciudad del contacto: ")))
nuevadireccion.SetCodigoPostal(input((">Introduce el codigo postal del contacto: ")))
direcciones.append(nuevadireccion)
nuevocontacto.SetListaDirecciones(direcciones)
return Conversion.ContactoAString(nuevocontacto)
except:
print("ERROR: Proceso de crear un contacto")
return None
Módulo de conversión
def ContactoAString(contacto):
try:
cadena = ""
# Inserta en la cadena los datos del contacto
cadena += "*"
cadena += contacto.GetNombre()
cadena += "|"
cadena += contacto.GetApellidos()
cadena += "|"
cadena += contacto.GetFechaNacimiento()
# Inserta en la cadena los datos de los teléfonos
cadena += "#"
listatelefonos = contacto.GetListaTelefonos()
if type(listatelefonos) != type(None):
for telefono in listatelefonos:
cadena += "-"
cadena += str(telefono.GetNumeroTelefono())
cadena += "|"
cadena += str(telefono.GetDescripcion())
# Inserta en la cadena los datos de las direcciones
cadena += "#"
listadirecciones = contacto.GetListaDirecciones()
if type(listadirecciones) != type(None):
for direccion in listadirecciones:
cadena += "-"
cadena += str(direccion.GetCalle())
cadena += "|"
cadena += str(direccion.GetPiso())
cadena += "|"
cadena += str(direccion.GetCiudad())
cadena += "|"
cadena += str(direccion.GetCodigoPostal())
return cadena
except:
print("ERROR: Convirtiendo el contacto a cadena")
return None
Programa principal
SocketCliente = socket.socket()
host = '127.0.0.1'
puerto = 30000
SocketCliente.connect((host, puerto))
print('¡Conectado al servidor!')
while True:
Visualizacion.MostrarMenu()
opcion = Visualizacion.ObtenerOpcion('Opcion: ')
# Buscar contactos (Visualizar)
if opcion == 1:
Visualizacion.MostrarMenuBuscar()
finbuscar = False
while not finbuscar:
opcionbuscar = Visualizacion.ObtenerOpcion('Opcion: ')
if opcionbuscar == 1:
parametro = input("Introduzca el nombre: ")
finbuscar = True
elif opcionbuscar == 2:
finbuscar = True
parametro = input("Introduzca el teléfono: ")
elif opcionbuscar == 3:
finbuscar = True
if opcionbuscar != 3:
try:
mensaje = str(opcion) + "&" + str(opcionbuscar) + "&" + parametro
SocketCliente.send(str.encode(mensaje))
recibido = SocketCliente.recv(4096)
recibido = recibido.decode('utf-8')
print(recibido)
Visualizacion.MostrarContactos(recibido)
except:
print("ERROR: Búsqueda de contactos")
# Crear contacto nuevo
elif opcion == 2:
try:
nuevocontacto = Visualizacion.ProcesoCrearContacto()
SocketCliente.send(str.encode(str(opcion) + "&" + nuevocontacto))
recibido = SocketCliente.recv(4096)
recibido = recibido.decode('utf-8')
if recibido == "1":
print("# Contacto insertado")
else:
print("ERROR: No se puede insertar el contacto")
except:
print("ERROR: Creando un contacto")
# Borrar contactos
elif opcion == 3:
Visualizacion.MostrarMenuBorrar()
finbuscar = False
while not finbuscar:
opcionbuscar = Visualizacion.ObtenerOpcion('Opcion: ')
if opcionbuscar == 1:
parametro = input("Introduzca el nombre: ")
finbuscar = True
elif opcionbuscar == 2:
finbuscar = True
parametro = input("Introduzca el teléfono: ")
elif opcionbuscar == 3:
finbuscar = True
if opcionbuscar != 3:
try:
mensaje = str(opcion) + "&" + str(opcionbuscar) + "&" + parametro
SocketCliente.send(str.encode(mensaje))
recibido = SocketCliente.recv(4096)
recibido = recibido.decode('utf-8')
if recibido == "1":
print("# Contactos borrados")
else:
print("ERROR: Se produjeron errores durante el borrado")
except:
print("ERROR: Borrando contactos")
# Mostrar todos los contactos
elif opcion == 4:
try:
SocketCliente.send(str.encode(str(opcion)))
recibido = SocketCliente.recv(4096)
recibido = recibido.decode('utf-8')
Visualizacion.MostrarContactos(recibido)
except:
print("ERROR: Mostrando todos los contactos")
# Salir
elif opcion == 5:
SocketCliente.send(str.encode(str(opcion)))
print("Cerrando cliente...")
break
SocketCliente.close()
Ejecución
Una vez tienes creada la base de datos y escrito todo el código fuente es el
momento de ejecutar el proyecto final. Para ello sólo tienes que arrancar
primero el servidor y posteriormente el cliente, presta atención a que la ruta
de la base de datos es correcta y la configuración de puertos también.
¿Te atreves?
¡CONSEGUIDO!
¡Enhorabuena! ¡Has llegado al final del libro! Para que seas consciente de
todo lo que has aprendido en un fin de semana te hemos preparado un
resumen con los hitos que has alcanzado:
Del mismo modo que con IDLE, el terminal de Python permite ejecutar
sentencias de Python:
El terminal de Python no sólo permite ejecutar sentencias de Python, sino que
también permite la ejecución de programas escritos en Python. La ejecución
de programas desde el terminal se realiza de forma diferente a lo que hemos
visto, se tiene que ejecutar el comando de apertura del terminal seguido de la
ruta con el programa a ejecutar. Dentro del material descargable hemos
incluido un fichero llamado “pruebaterminal.py” que muestra por pantalla un
mensaje. Veamos cómo lo ejecutaríamos:
http://timeofsoftware.com/python-avanzado-ejercicios/
OTROS LIBROS DE LOS AUTORES