{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 5. Programacion Orientada a Objetos\n", "\n", "La programación orientada a objetos es uno de los métodos más eficaces para escribir software. En la programación orientada a objetos se escriben clases que representan situaciones y situaciones del mundo real, y se crean objetos basados en estas clases. Cuando se escribe una clase, se define el comportamiento general que puede tener toda una categoría de objetos.\n", "\n", "Cuando se crean objetos individuales de la clase, cada objeto está equipado automáticamente con el comportamiento general; Usted puede entonces dar a cada objeto cualesquiera rasgos únicos que usted desea. Usted se sorprenderá de lo bien que las situaciones del mundo real pueden ser modeladas con la programación orientada a objetos. Hacer un objeto de una clase se denomina creación de instancias y se trabaja con **instancias de una clase**. En esta sección escribirá clases y creará instancias de esas clases. Especificará el tipo de información que se puede almacenar en instancias y definirá acciones que se pueden tomar con estas instancias." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Alt text](../images/cars.jpg \"Optional title\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Diferencias entre la Programación Estructurada y la Programación Orientada a Objetos" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Supongamos que tenemos los datos de los alumnos de una universidad, vamos a comparar este problema usando dos tipos de estructuras de datos. La primera es una lista de diccionarios donde cada diccionario representa a un alumno" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "alumnos= [\n", " {'Nombre': 'Carlos', 'Apellidos':'Guzman', 'codigo':'20132315E'},\n", " {'Nombre': 'Jose', 'Apellidos':'Sanchéz', 'codigo':'20133298H'} \n", "]" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def imprimir_alumnos(alumnos, codigo):\n", " for m in alumnos:\n", " if (codigo == m['codigo']):\n", " print('{} {}'.format(m['Nombre'],m['Apellidos']))\n", " return\n", " \n", " print('Alumno no encontrado')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Carlos Guzman\n" ] } ], "source": [ "imprimir_alumnos(alumnos, '20132315E')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Alumno no encontrado\n" ] } ], "source": [ "imprimir_alumnos(alumnos,'20135212G')" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def borrar_alumno(alumnos, codigo):\n", " for i,c in enumerate(alumnos):\n", " if (codigo == c['codigo']):\n", " del( alumnos[i] )\n", " print(str(c),\" ha sido borrado\")\n", " return\n", " \n", " print('Alumno no encontrado')\n" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'Nombre': 'Carlos', 'Apellidos': 'Guzman', 'codigo': '20132315E'} ha sido borrado\n" ] } ], "source": [ "borrar_alumno(alumnos, '20132315E')" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Alumno no encontrado\n" ] } ], "source": [ "borrar_alumno(alumnos,'20135212G')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Esta forma de programar no es muy eficiente, por ello se creo el paradigma de la POO, esto nos ofrece una abstracción mas limpia y sencilla, además nos da unas buenas prácticas de software." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ahora veamos como se veria con programación orientada a objetos" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "class Alumno:\n", " \n", " def __init__(self, codigo, nombre, apellidos):\n", " self.codigo = codigo\n", " self.nombre = nombre\n", " self.apellidos = apellidos\n", " \n", " def __str__(self):\n", " return '{} {}'.format(self.nombre,self.apellidos)\n", " \n", "\n", "class Salon:\n", " \n", " def __init__(self, alumnos=[]):\n", " self.alumnos = alumnos\n", " \n", " def mostrar_alumnos(self, codigo=None):\n", " for c in self.alumnos:\n", " if c.codigo == codigo:\n", " print(c)\n", " return\n", " print(\"Alumno no encontrado\")\n", " \n", " def borrar_alumnos(self, codigo=None):\n", " for i,c in enumerate(self.alumnos):\n", " if c.codigo == codigo:\n", " del(self.alumnos[i])\n", " print(str(c),\" ha sido borrado\")\n", " return\n", " print(\"Alumno no encontrado\")" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "Alan = Alumno(nombre=\"Alan\", apellidos=\"Orbregoso\", codigo=\"20145283J\")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "Alex = Alumno(nombre=\"Alex\", apellidos=\"Salazar\", codigo=\"20141276H\")" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "<__main__.Alumno at 0x7faf584b9630>" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Alex" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "salon1 = Salon(alumnos=[Alan, Alex])" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Alan Orbregoso\n" ] } ], "source": [ "salon1.mostrar_alumnos(\"20145283J\")" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Alan Orbregoso ha sido borrado\n" ] } ], "source": [ "salon1.borrar_alumnos(\"20145283J\")" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[<__main__.Alumno at 0x7faf584b9630>]" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "salon1.alumnos" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Antes de explorar la programación orientada a objetos vamos a hechar un vistazo de nuestros objetos" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Función `type()`\n", "Sirve para determinar la clase de un objeto." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "__main__.Animal" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class Animal:\n", " pass\n", "\n", "perro = Animal()\n", "\n", "type(perro)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vemos que nuestro objeto perro pertenece al tipo Animal. En python todo es un objeto, pueden ser de clases construidas por Python, o creadas por nosotros mismos. En el caso anterior creamos una clase sencilla llamada Animal." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(10)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(3.14)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type({})" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type([])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creación y uso de una clase\n", "\n", "Puede modelar casi cualquier cosa usando clases. Comencemos escribiendo una clase simple, **Robot**, que representa a un robot, no un robot en particular, sino cualquier robot. Esto será como nuestro molde a la hora de crear robots.\n", "¿Qué sabemos de la mayoría de los Robots? \n", "Nuestro Robot tendra un nombre y una posición inicial y se moverá en el eje X de izquierda a derecha. Esas dos piezas de información (nombre y pos_x) y esos dos comportamientos (moverse de izquierda o derecha) irán a nuestra clase Robot. Esta clase le dirá a Python cómo hacer que un objeto represente un Robot. Después de escribir nuestra clase, la usaremos para hacer instancias individuales, cada una de las cuales representa un Robot específico.\n", "\n", "Antes de crear nuestras clases definiremos:\n", "\n", "- **Atributos:** Hacen referencia a las variables internas de la clase.\n", "- **Métodos:** Hacen referencia a las funciones internas de la clase." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "# Creando la Clase de Robot\n", "# Cada instancia creada de la clase Robot almacenará un nombre y su posicion en el eje X\n", "# y le daremos a cada robot la capacidad de mover_derecha() y mover_izquierda():\n", "\n", "# Definimos la clase Robot\n", "class Robot():\n", " \n", " # __init__ viene a ser el constructor de nuestra clase, se llamará automaticamente al crear la clase Robot\n", " def __init__(self, nombre , pos_x=0):\n", " \"\"\" inicializando los atributos nombre y edad\n", " self sirve para hacer referencia a los métodos y atributos base de una clase dentro de sus propios métodos.\"\"\"\n", " self.nombre = nombre\n", " self.pos_x = pos_x\n", " \n", " # Métodos\n", " def mover_derecha(self):\n", " self.pos_x = self.pos_x + 1\n", " print(self.nombre + \" se está moviendo hacia la derecha\")\n", " print(self.nombre + \" ahora se encuentra en la posicion: \" + str(self.pos_x) )\n", " \n", " def mover_izquierda(self):\n", " self.pos_x = self.pos_x - 1\n", " print(self.nombre + \" se está moviendo hacia la izquierda\")\n", " print(self.nombre + \" ahora se encuentra en la posicion: \" + str(self.pos_x) )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### El método `__init __()`\n", "\n", "Una función que forma parte de una clase es un **método**. Todo lo que aprendió acerca de las funciones también se aplica a los métodos; La única diferencia práctica por ahora es la forma en que llamaremos a los métodos. El método **`__init__()`** es un método especial que Python ejecuta automáticamente cada vez que creamos una nueva instancia basada en la clase Robot. Este método tiene dos subrayados , una convención que ayuda a evitar que los nombres de métodos predeterminados de Python entren en conflicto con los nombres de métodos.\n", "\n", "Definimos el método **`__init__()`** para tener tres parámetros: `self`, nombre y posición. El parámetro self es necesario en la definición del método, y debe aparecer antes que los otros parámetros. Debe incluirse en la definición porque cuando Python llama a este método **`__init__()`** más adelante (para crear una instancia Robot), la llamada al método pasará automáticamente el argumento self.\n", "\n", "Las dos variables definidas tienen cada una el prefijo **`self`**. Cualquier variable prefijada con self está disponible para todos los métodos de la clase, y también podremos acceder a estas variables a través de cualquier instancia creada desde la clase. Self.nombre = nombre toma el valor almacenado en el nombre del parámetro y lo almacena en el nombre de la variable, que se adjunta a la instancia que se está creando. El mismo proceso ocurre con self.pos_x = pos_x. Las variables accesibles a través de instancias como ésta se denominan atributos.\n", "\n", "La clase Robot tiene otros dos métodos definidos: **moverse_derecha()** y **moverse_izquierda()**. Debido a que estos métodos no necesitan información adicional como un nombre o pos_x, solo los definimos para tener un parámetro, self. Las instancias que creamos más adelante tendrán acceso a estos métodos. En otras palabras, podrán moverse. \n", "\n", "Simplemente imprimen un mensaje diciendo que el robot se está moviendo hacia la izquierda o derecha. Si esta clase fuera escrita para controlar un robot, estos métodos dirigirían los movimientos que hacen que un robot salte o camine, etc." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Crear una instancia de una clase\n", "\n", "Piense en una clase como un conjunto de instrucciones sobre cómo crear una instancia. El perro de clase es un conjunto de instrucciones que le dice a Python cómo hacer que las instancias individuales representen a robots específicos. Hagamos una instancia que represente a un robot específico:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "El nombre de mi robot es: Wally.\n", "Mi robot se encuentra en: 2 en el eje X\n" ] } ], "source": [ "mi_robot = Robot('Wally',2)\n", "\n", "print(\"El nombre de mi robot es: \" + mi_robot.nombre + \".\")\n", "print(\"Mi robot se encuentra en: \" + str(mi_robot.pos_x) + \" en el eje X\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Llamando a métodos\n", "Después de crear una instancia de la clase Robot, podemos usar la notación de puntos para llamar a cualquier método definido en Robot. Vamos a hacer que nuestro Robot se mueva a la izquierda o a la derecha" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Eva se está moviendo hacia la derecha\n", "Eva ahora se encuentra en la posicion: 6\n", "Eva se está moviendo hacia la derecha\n", "Eva ahora se encuentra en la posicion: 7\n", "Eva se está moviendo hacia la derecha\n", "Eva ahora se encuentra en la posicion: 8\n", "Eva se está moviendo hacia la izquierda\n", "Eva ahora se encuentra en la posicion: 7\n" ] } ], "source": [ "mi_robot = Robot('Eva', 5)\n", "mi_robot.mover_derecha()\n", "mi_robot.mover_derecha()\n", "mi_robot.mover_derecha()\n", "mi_robot.mover_izquierda()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Modificación de valores de atributo\n", "\n", "Puede cambiar el valor de un atributo de varias maneras: puede cambiar el valor directamente a través de una instancia, establecer el valor a través de un método." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Modificar el valor de un atributo directamente\n", "La forma más sencilla de modificar el valor de un atributo es acceder al atributo directamente a través de una instancia. Aquí ponemos la posicion del robot directamente:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8\n" ] } ], "source": [ "mi_robot = Robot('Eva', 5)\n", "mi_robot.pos_x = 8\n", "print(mi_robot.pos_x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Modificar el valor de un atributo a través de un método\n", "Puede ser útil tener métodos que actualicen ciertos atributos para usted. En lugar de acceder al atributo directamente, pasa el nuevo valor a un método que gestiona la actualización internamente. Aquí hay un ejemplo que muestra un método llamado __`update_pos()`__:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "class Robot():\n", " \n", " def __init__(self,nombre,pos_x):\n", " \"\"\" inicializando los atributos nombre y edad\"\"\"\n", " self.nombre = nombre\n", " self.pos_x = 0 # configurando el valor predeterminado\n", " \n", " def mover_derecha(self):\n", " self.pos_x = self.pos_x + 1\n", " print(self.nombre + \" se está moviendo hacia la derecha\")\n", " print(self.nombre + \" ahora se encuentra en la posicion: \" + str(self.pos_x) )\n", " \n", " def mover_izquierda(self):\n", " self.pos_x = self.pos_x - 1\n", " print(self.nombre + \" se está moviendo hacia la izquierda\")\n", " print(self.nombre + \" ahora se encuentra en la posicion: \" + str(self.pos_x) )\n", " \n", " def update_pos(self,num):\n", " self.pos_x = num" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [], "source": [ "robotin = Robot(\"Androide 17\",8)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1235\n" ] } ], "source": [ "robotin.update_pos(1235)\n", "print(robotin.pos_x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Métodos especiales de clase" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### - Constructores y destructores" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Se ha creado el curso Algoritmos\n" ] } ], "source": [ "class Curso:\n", " # Constructor de clase (al crear la instancia)\n", " def __init__(self,nombre,codigo,profesor):\n", " self.nombre = nombre\n", " self.codigo = codigo\n", " self.profesor = profesor\n", " print(\"Se ha creado el curso \",self.nombre)\n", " \n", " # Destructor de clase (al borrar la instancia)\n", " def __del__(self):\n", " print(\"Se está borrando el curso\", self.nombre)\n", " \n", "Curso1 = Curso(\"Algoritmos\",\"CC302\",\"Alexei Romanov\")" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Se ha creado el curso Estructura de Datos\n", "Se está borrando el curso Algoritmos\n" ] } ], "source": [ "Curso1 = Curso(\"Estructura de Datos\",\"CC304\",\"Henry Peralta\")\n", "# Al reinstanciar la misma variable se crea de nuevo y se borra la anterior" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### - String\n", "\n", "Para devolver una cadena por defecto al convertir un objeto a una cadena con str(objeto):" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Se ha creado el curso Algoritmos\n" ] } ], "source": [ "class Curso:\n", " # Constructor de clase (al crear la instancia)\n", " def __init__(self,nombre,codigo,profesor):\n", " self.nombre = nombre\n", " self.codigo = codigo\n", " self.profesor = profesor\n", " print(\"Se ha creado el curso \",self.nombre)\n", " \n", " # Destructor de clase (al borrar la instancia)\n", " def __del__(self):\n", " print(\"Se está borrando el curso\", self.nombre)\n", " \n", " # Redefinimos el método string\n", " def __str__(self):\n", " return \"{} es un curso con codigo : {} y lo dictará el profesor {} \".format(self.nombre,self.codigo,self.profesor)\n", " \n", "Curso3 = Curso(\"Algoritmos\",\"CC302\",\"Alexei Romanov\")" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Algoritmos es un curso con codigo : CC302 y lo dictará el profesor Alexei Romanov '" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "str(Curso3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Ejemplo del uso de clases" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ejemplo 1" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "31 -17\n" ] } ], "source": [ "class NumeroComplejo:\n", " def __init__(self, real, img):\n", " self.real = real\n", " self.img = img\n", "\n", " def modulo(self):\n", " return (self.real**2 + self.img**2)**(1/2)\n", "\n", " def conjugado(self):\n", " return NumeroComplejo(self.real, -self.img)\n", "\n", " def producto(self, w):\n", " real = self.real * w.real - self.img * w.img\n", " img = self.real * w.img + self.img * w.real\n", " return NumeroComplejo(real, img)\n", " \n", "z = NumeroComplejo(3, 4)\n", "w = NumeroComplejo(1, -7)\n", "\n", "x = z.producto(w)\n", "\n", "print(x.real,x.img)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Ejemplo 2" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "class Cancion:\n", " \n", " # Constructor de clase\n", " def __init__(self, titulo, duracion, artista):\n", " self.titulo = titulo\n", " self.duracion = duracion\n", " self.artista = artista\n", " print('Se ha creado la cancion:',self.titulo)\n", " \n", " def __str__(self):\n", " return '{} ({})'.format(self.titulo, self.artista)\n", " \n", "class Lista_Reproduccion:\n", " \n", " canciones = [] # Esta lista contendrá objetos de la clase Cancion\n", " \n", " def __init__(self,canciones=[]):\n", " self.canciones = canciones\n", " \n", " def agregar(self,p): # p será un objeto Cancion\n", " self.canciones.append(p)\n", " \n", " def mostrar(self):\n", " for p in self.canciones:\n", " print(p) # Print toma por defecto str(p)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Se ha creado la cancion: Rolling in the Dep\n", "Se ha creado la cancion: Happy\n" ] } ], "source": [ "c1 = Cancion(\"Rolling in the Dep\",\"3:15\",\"Adele\")\n", "c2 = Cancion(\"Happy\",\"2:45\",\"Farell\")\n", "l = Lista_Reproduccion([c1,c2])" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rolling in the Dep (Adele)\n", "Happy (Farell)\n" ] } ], "source": [ "l.mostrar()" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Se ha creado la cancion: Riptide\n" ] } ], "source": [ "l.agregar(Cancion(\"Riptide\",\"3:24\",\"Vance Joy\"))" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Rolling in the Dep (Adele)\n", "Happy (Farell)\n", "Riptide (Vance Joy)\n" ] } ], "source": [ "l.mostrar()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Encapsulación\n", "\n", "Consiste en denegar el acceso a los atributos y métodos internos de la clase desde el exterior, para así poder mantener la integridad de la información de nuestros objetos.\n", "\n", "En Python no existe, pero se puede simular precediendo atributos y métodos con dos guiones bajos **`__`**" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "gerson\n", "512\n", "El usuario es: gerson\n", "La contraseña es: gerson\n" ] } ], "source": [ "class Usuario:\n", " \n", " # Constructor de clase\n", " def __init__(self, username, password):\n", " self.username = username\n", " self.password = password\n", " def showUser(self):\n", " print(\"El usuario es: \" + self.username)\n", " def showPassword(self):\n", " print(\"La contraseña es: \" + self.username)\n", " \n", "gerson = Usuario(\"gerson\",\"512\")\n", "print(gerson.username)\n", "print(gerson.password)\n", "gerson.showUser()\n", "gerson.showPassword()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Es una mala práctica poder acceder a los atributos y métodos de un objeto de esta manera" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "ename": "AttributeError", "evalue": "'Usuario2' object has no attribute 'username'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 16\u001b[0m \u001b[0misabel\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mUsuario2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"isabel\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\"343\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 17\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0misabel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0musername\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0misabel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpassword\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mAttributeError\u001b[0m: 'Usuario2' object has no attribute 'username'" ] } ], "source": [ "class Usuario2:\n", " \n", " # Constructor de clase\n", " def __init__(self,username,password):\n", " self.__username = username\n", " self.__password = password\n", " def showUser(self):\n", " print(\"El usuario es: \" + self.__username)\n", " def __showPassword(self):\n", " print(\"La contraseña es: \" + self.__password)\n", " \n", " # Para acceder a un método privado podemos hacer\n", " def metodo_publico(self):\n", " self.__showPassword()\n", " \n", "isabel = Usuario2(\"isabel\",\"343\")\n", "print(isabel.username)\n", "print(isabel.password)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vemos que ahora no podemos acceder a nuestros atributos ya que ahora esta encapsulado" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "El usuario es: isabel\n" ] }, { "ename": "AttributeError", "evalue": "'Usuario2' object has no attribute 'showPassword'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0misabel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshowUser\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0misabel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshowPassword\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m#No podemos acceder al método showPassword ya que también esta encapsulado\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'Usuario2' object has no attribute 'showPassword'" ] } ], "source": [ "isabel.showUser()\n", "isabel.showPassword() #No podemos acceder al método showPassword ya que también esta encapsulado" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Para poder acceder a nuestro método privado podemos crear un método público que lo llame:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "La contraseña es: 343\n" ] } ], "source": [ "isabel.metodo_publico()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Herencia\n", "\n", "No siempre tienes que empezar de cero al escribir una clase. Si la clase que estás escribiendo es una versión especializada de otra clase que escribiste, puedes usar la herencia. Cuando una clase hereda de otra, automáticamente asume todos los atributos y métodos de la primera clase. La clase original se llama la clase padre y la nueva clase es la clase hoja. La clase hija hereda todos los atributos y métodos de su clase padre, pero también es libre de definir nuevos atributos y métodos propios." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [], "source": [ "class Vehiculo:\n", " \n", " # Constructor de clase\n", " def __init__(self, matricula, modelo, potenciaCV):\n", " self.matricula = matricula\n", " self.modelo = modelo\n", " self.potenciaCV = potenciaCV\n", " " ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " MATRICULA\tCSA312\n", " MODELO\tToyota\n", " POTENCIA\t500W\n", " NRO LICENCIA \t 1235123\n", " \n" ] } ], "source": [ "class Taxi(Vehiculo):\n", "\n", " nroLicencia = \"\"\n", "\n", " def __str__(self):\n", " return \"\"\"\n", " MATRICULA\\t{}\n", " MODELO\\t{}\n", " POTENCIA\\t{}\n", " NRO LICENCIA \\t {}\n", " \"\"\".format(self.matricula,self.modelo,self.potenciaCV,self.nroLicencia)\n", " \n", "vehiculo1 = Taxi(\"CSA312\",\"Toyota\",\"500W\")\n", "vehiculo1.nroLicencia = \"1235123\"\n", "print(vehiculo1)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", " MATRICULA\tSDE312\n", " MODELO\tBMW\n", " POTENCIA\t500W\n", " NRO PLAZAS \t 31\n", " \n" ] } ], "source": [ "class Autobus(Vehiculo):\n", "\n", " nroPlazas = \"\"\n", " \n", " def __str__(self):\n", " return \"\"\"\n", " MATRICULA\\t{}\n", " MODELO\\t{}\n", " POTENCIA\\t{}\n", " NRO PLAZAS \\t {}\n", " \"\"\".format(self.matricula,self.modelo,self.potenciaCV,self.nroPlazas)\n", " \n", "vehiculo2 = Autobus(\"SDE312\",\"BMW\",\"500W\")\n", "vehiculo2.nroPlazas = \"31\"\n", "print(vehiculo2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Herencia múltiple\n", "\n", "Una subclase puede heredar de múltiples superclases.\n", "\n", "El problema aparece cuando las superclases tienen atributos o métodos comunes.\n", "\n", "En estos casos, Python dará prioridad a las clases más a la izquierda en el momento de la declaración de la subclase." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Soy de clase B\n" ] } ], "source": [ "class A:\n", " def __init__(self):\n", " print(\"Soy de clase A\")\n", " def a(self):\n", " print(\"Este método lo heredo de A\")\n", " \n", "class B:\n", " def __init__(self):\n", " print(\"Soy de clase B\")\n", " def b(self):\n", " print(\"Este método lo heredo de B\")\n", " \n", "class C(B,A):\n", " def c(self):\n", " print(\"Este método es de C\")\n", "\n", "c = C()" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Este método lo heredo de A\n" ] } ], "source": [ "c.a()" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Este método lo heredo de B\n" ] } ], "source": [ "c.b()" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Este método es de C\n" ] } ], "source": [ "c.c()" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "Estilo aplicado\n", "\n", "\n" ], "text/plain": [ "" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Esta celda da el estilo al notebook\n", "from IPython.core.display import HTML\n", "css_file = '../styles/StyleCursoPython.css'\n", "HTML(open(css_file, \"r\").read())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.5" } }, "nbformat": 4, "nbformat_minor": 1 }