{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Ayudantia 1\n",
    "## Programación Orientada a Objetos 🤓"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Ayudantes de Cátedra!\n",
    "\n",
    "Nos verán todos los martes y durante las actividades :)\n",
    "- [Clemente Campos](https://github.com/mskdancers)\n",
    "- [Patricio Hinostroza](https://github.com/Dvckhv)\n",
    "- [Julio Huerta](https://github.com/julius)\n",
    "- [Carlos Olguin](https://github.com/CarlangaUC)\n",
    "- [Catalina Miranda](https://github.com/catalinamirandah)\n",
    "- [Felipe Vidal](https://github.com/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Objetos 💥 \n",
    "\n",
    "Un objeto en computación se define como una *colección* de datos que además posee un comportamiento asociado.\n",
    "\n",
    "En Python los definiremos utilizando Clases, y dentro de estas, métodos y atributos, donde estos últimos podemos encapsularlos para hacerlos mas difíciles de acceder.\n",
    "```python\n",
    "class NombreClase:\n",
    "    def __init__(self,arg_1, atr_2,etc):\n",
    "        self.atr_1 = arg_1\n",
    "        self._atributo_encapsulado = #algo\n",
    "        self.__atributo_ultra_encapsulado = atr_2\n",
    "        \n",
    "    def metodo_clase(self, arg_1, arg_2):\n",
    "        pass\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Properties 📣"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Las **properties** son similares (no iguales) a los atributos, con la excepción de que nos permiten modificar su comportamiento cada vez que son leídas (`get`), escritas (`set`) o eliminadas (`del`).\n",
    "\n",
    "```python\n",
    "class CuentaBase:\n",
    "\n",
    "    def __init__(self, monto):\n",
    "        self.monto = monto\n",
    "\n",
    "    @property\n",
    "    def monto(self):\n",
    "        return self.monto\n",
    "\n",
    "    @monto.setter(self):\n",
    "    def monto(self, nuevo_monto):\n",
    "        self.monto = max(0, nuevo_monto)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Herencia y Polimorfismo 🤖"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "La **herencia** es un concepto de suma importancia en el trabajo de clases, nos permite generar clases en base a otras ya establecidas, ahorrándonos código y permitiendo un nivel más de especialización y generalización. Un ejemplo básico de herencia es:\n",
    "\n",
    "```python\n",
    "class Maquina:\n",
    "\n",
    "    def __init__(self, material, motor):\n",
    "\n",
    "        self.material = material\n",
    "        self.motor = motor\n",
    "\n",
    "class Auto(Maquina):\n",
    "    # La clase Auto heredera de Maquina\n",
    "\n",
    "    def __init__(self):\n",
    "\n",
    "        Maquina.__init__(self, material, motor)\n",
    "        # Heredamos especificamente estos atributos de la clase Maquina\n",
    "        self.ventanas = 4\n",
    "```\n",
    "En este caso, tenemos la clase **Maquina** que luego es heredada por la clase **Auto** ,\n",
    " heredando tanto el atributo `material` como el `motor`, pero además se define el atributo `ventanas`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "El **overriding** es un fenómeno que permite sobreescribir tanto atributos como métodos de una clase superior al heredarla, esto es posible gracias a que estamos ocupando específicamente Python (Si quieres saber mas de este fenomeno revisar🚀: [Python]https://docs.python.org/3/tutorial/classes.html ). Un ejemplo de esto lo podemos encontrar en el siguiente código:\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "```python\n",
    "\n",
    "    class Fabrica:\n",
    "\n",
    "        def __init__(self, trabajadores, material):\n",
    "\n",
    "            self.trabajadores = 10\n",
    "            self.material = \"Todo\"\n",
    "            self.producido = 0\n",
    "\n",
    "        def producir(self):\n",
    "\n",
    "            print(f\" \")\n",
    "\n",
    "\n",
    "    class ProductoraTextil(Fabrica):\n",
    "        '''\n",
    "        Al no especificar un init, se copia el de la clase padre\n",
    "        '''\n",
    "        def producir(self):\n",
    "            # Se sobre escribió el metodo de Fabrica\n",
    "            print(f\"Se ha producido {self.producido} Telas\")\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "También podemos extender las clases que ya están en python (**built-in**), y muchas cosas más."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Multi Herencia 🤖 🤖 🤖"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "La **multiherencia** se refiere simplemente a cuando nuestra clase hereda de más de una clase a la vez. Veamos un ejemplo, definiendo primero algunos majors de Ingeniería:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [],
   "source": [
    "class MajorComputacion:\n",
    "\n",
    "    def __init__(self, ramos_compu: list):\n",
    "        self.ramos_compu = ramos_compu\n",
    "\n",
    "    def imprimir_carga(self):\n",
    "        for ramo in self.ramos_compu:\n",
    "            print(ramo)\n",
    "\n",
    "\n",
    "class MajorElectrica:\n",
    "\n",
    "    def __init__(self, ramos_electrica: list):\n",
    "        self.ramos_electrica = ramos_electrica\n",
    "\n",
    "    def imprimir_carga(self):\n",
    "        for ramo in self.ramos_electrica:\n",
    "            print(ramo)\n",
    "\n",
    "\n",
    "class MajorMecanica:\n",
    "\n",
    "    def __init__(self, ramos_mecanica: list):\n",
    "        self.ramos_mecanica = ramos_mecanica\n",
    "\n",
    "    def imprimir_carga(self):\n",
    "        for ramo in self.ramos_mecanica:\n",
    "            print(ramo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Ahora definamos el Major de Robotica, que combina los 3 majors anteriores. Además, creemos una instancia del major:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "MajorComputacion.__init__() takes 2 positional arguments but 4 were given",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[2], line 7\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m, ramos_compu, ramos_electrica, ramos_mecanica):\n\u001b[1;32m      4\u001b[0m         \u001b[38;5;28msuper\u001b[39m()\u001b[38;5;241m.\u001b[39m\u001b[38;5;21m__init__\u001b[39m(ramos_compu, ramos_electrica, ramos_mecanica)\n\u001b[0;32m----> 7\u001b[0m major_escogido \u001b[38;5;241m=\u001b[39m \u001b[43mMajorRobotica\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mIIC2233\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mIIC2413\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mIEE2713\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mIEE2103\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mICM2803\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mICM2503\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n",
      "Cell \u001b[0;32mIn[2], line 4\u001b[0m, in \u001b[0;36mMajorRobotica.__init__\u001b[0;34m(self, ramos_compu, ramos_electrica, ramos_mecanica)\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m, ramos_compu, ramos_electrica, ramos_mecanica):\n\u001b[0;32m----> 4\u001b[0m     \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mramos_compu\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mramos_electrica\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mramos_mecanica\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[0;31mTypeError\u001b[0m: MajorComputacion.__init__() takes 2 positional arguments but 4 were given"
     ]
    }
   ],
   "source": [
    "class MajorRobotica(MajorComputacion, MajorElectrica, MajorMecanica):\n",
    "    \n",
    "    def __init__(self, ramos_compu, ramos_electrica, ramos_mecanica):\n",
    "        super().__init__(ramos_compu, ramos_electrica, ramos_mecanica)\n",
    "\n",
    "\n",
    "major_escogido = MajorRobotica([\"IIC2233\", \"IIC2413\"], [\"IEE2713\", \"IEE2103\"], [\"ICM2803\", \"ICM2503\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### ¿Qué sucedió?\n",
    "\n",
    "Al heredar de múltiples clases, Python ejecuta el inicializador de la primera clase heredada, en este caso ```MajorComputacion```. Sin embargo, lo ejecuta con **todos** los argumentos entregados, incluyendo aquellos que estaban destinados al resto de las clases.\n",
    "\n",
    "### Solución: Uso de *args y **kwargs\n",
    "\n",
    "#### Abre paréntesis...\n",
    "\n",
    "- ```*args```: Secuencia de argumentos **posicionales** de largo variable. El operador * desempaqutea el contenido de los args y los entrega a la función según el **orden en el que son recibidos**.\n",
    "\n",
    "- ```**kwargs```: Secuencia de argumentos **con palabra clave** (*keyword arguments*) de largo variable. El operador ** mapea los elementos en la función según los *keywords* que esta espera.\n",
    " \n",
    "#### ...Cierra paréntesis\n",
    "\n",
    "#### Volviendo a multiherencia\n",
    "\n",
    "Utilizaremos **kwargs para explicitar los argumentos que entregamos, de forma que un inicializador pueda tomar solo aquellos que necesite y *pasar de largo* aquellos que corresponden a los demás inicalizadores:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [],
   "source": [
    "class MajorComputacion:\n",
    "\n",
    "    def __init__(self, ramos_compu: list, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        self.ramos_compu = ramos_compu\n",
    "\n",
    "\n",
    "class MajorElectrica:\n",
    "\n",
    "    def __init__(self, ramos_electrica: list, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        self.ramos_electrica = ramos_electrica\n",
    "\n",
    "\n",
    "class MajorMecanica:\n",
    "\n",
    "    def __init__(self, ramos_mecanica: list, **kwargs):\n",
    "        super().__init__(**kwargs)\n",
    "        self.ramos_mecanica = ramos_mecanica"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['IIC2233', 'IIC2413']\n",
      "['IEE2713', 'IEE2103']\n",
      "['ICM2803', 'ICM2503']\n"
     ]
    }
   ],
   "source": [
    "class MajorRobotica(MajorComputacion, MajorElectrica, MajorMecanica):\n",
    "    \n",
    "    def __init__(self, **kwargs):\n",
    "        # Se entregan todos los kwargs al resto de inicalizadores\n",
    "        super().__init__(**kwargs)\n",
    "\n",
    "    def imprimir_carga(self):\n",
    "        print(self.ramos_compu)\n",
    "        print(self.ramos_electrica)\n",
    "        print(self.ramos_mecanica)\n",
    "\n",
    "\n",
    "major_escogido = MajorRobotica(\n",
    "    ramos_compu=[\"IIC2233\", \"IIC2413\"], \n",
    "    ramos_electrica=[\"IEE2713\", \"IEE2103\"], \n",
    "    ramos_mecanica=[\"ICM2803\", \"ICM2503\"]\n",
    ")\n",
    "\n",
    "major_escogido.imprimir_carga()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Problema del Diamante 💎"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "El problema del diamante es una ambigüedad que surge cuando dos clases B y C heredan de A, y la clase D hereda de B y C. Si un método en D llama a un método definido en A ¿Por qué clase lo hereda, B o C?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "<img src=\"./img/Diamond.png\" style=\"height: 400px\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "### Solución: uso de * args y ** kwargs 🙌\n",
    "\n",
    "Al utilizar `*args` y `**kwargs` estamos heredando todos los atributos de la clase padre, incluyendo los de la clase superior."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Clases Abstractas 💽👁️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Las clases abstractas son una herramienta útil para modelar un problema, nos permiten generar un tipo de molde para futuras clases, o sea, su objetivo no es ser instanciadas propiamente. Un ejemplo de una clase abstracta con sus métodos (abstractos), sería lo siguiente:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [],
   "source": [
    "from abc import ABC, abstractmethod\n",
    "class Comida(ABC):\n",
    "    \n",
    "    def __init__(self, color, sabor):\n",
    "        self.nombre = \"\"\n",
    "        self.color = color\n",
    "        self.sabor = sabor\n",
    "        self.__satisfaccion = 0\n",
    "\n",
    "    @property \n",
    "    def satisfaccion(self): \n",
    "        return self.__satisfaccion\n",
    "\n",
    "    @satisfaccion.setter\n",
    "    def satisfaccion(self,valor):\n",
    "        self.__satisfaccion = max(valor,0)\n",
    "\n",
    "    @abstractmethod\n",
    "    def devorar(self):\n",
    "        print(f\"Me han devorado! Yo!? {self.nombre} de color {self.color}, \\\n",
    "sabor {self.sabor} y satisfaccion {self.satisfaccion}?\")\n",
    "\n",
    "class Completo(Comida): \n",
    "    '''Notar que una vez definimos estos metodos abstractos \n",
    "        su objetivo es hacer override de estos '''\n",
    "\n",
    "    def __init__(self,*args,**kwargs):\n",
    "        super().__init__(*args,**kwargs) # Heredamos los atributos\n",
    "        self.nombre = \"Completo\"\n",
    "        self.mojado = False # Añadimos otro atributo \n",
    "        self.satisfaccion = 1000\n",
    "        \n",
    "    def devorar(self):\n",
    "        super().devorar()\n",
    "\n",
    "completo = Completo(\"rojo\",\"exquisito\")\n",
    "completo.devorar()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Ejercicios!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DCCorredor de Propiedades\n",
    "\n",
    "Un dia, interesado por las propiedades(?) y la programación se te ocurre que es buena idea modelar el funcionamiento de un condominio un poco extraño, que tiene tanto edificios como casas, para así saber un poco más del lugar, como su valoración en el mercado y su capacidad.\n",
    "\n",
    "Para esto sabes que tanto casas como departamentos tienen:\n",
    "- Número\n",
    "- m2\n",
    "- baños\n",
    "- habitaciones\n",
    "\n",
    "y se diferencian en que las casas tienen atributos propios como Pariedad y Niveles; y los departamentos tienen atributos como Elevador y Piso.\n",
    "\n",
    "Para esto ya creaste un archivo base y debes completarlo considerando que el precio se maneja bajo la siguiente ecuación:\n",
    "\n",
    "- Casas:\n",
    "    \n",
    "    $1000* \\frac{baño* habitaciones*Niveles* m^2 }{10+10*Pariedad}$\n",
    "\n",
    "- Departamentos:\n",
    "\n",
    "    $1000* \\frac{baño* habitaciones*Niveles* m^2 }{(20-10*Elevador)*Piso}$\n",
    " \n",
    "\n",
    "y debe mostrar en un formato legible lo suigiente:\n",
    "- tipo propiedad acompañado del numero\n",
    "- propiedades de la casa\n",
    "- precio\n",
    "\n",
    "además, estos métodos no deben ser modificables."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from abc import ABC, abstractmethod\n",
    "\n",
    "class Inmueble:\n",
    "    def __init__(self,n,m,banios, habs,par,niv, *args,**kwargs) -> None:\n",
    "        pass\n",
    "\n",
    "    def precio(self):\n",
    "        pass\n",
    "    \n",
    "    def describir(self):\n",
    "        pass\n",
    "\n",
    "class Casa(Inmueble):\n",
    "    def __init__(self,n,m,banios, habs, *args,**kwargs) -> None:\n",
    "        #completar\n",
    "        pass\n",
    "\n",
    "class Depto:\n",
    "    def __init__(self,n,m,banios, habs,elev,piso, *args,**kwargs) -> None:\n",
    "        #completar\n",
    "        pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DC(A)Cademia\n",
    "\n",
    "En este ejercicio emplearemos clases abstractas, herencia y multiherencia junto a propiedades, todo esto para generar una clase Estudiante, EstudianteDCC y SeleccionadoDCC ! :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "object.__init__() takes exactly one argument (the instance to initialize)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[2], line 65\u001b[0m\n\u001b[1;32m     62\u001b[0m     \u001b[39mdef\u001b[39;00m \u001b[39mseleccionado\u001b[39m(\u001b[39mself\u001b[39m):\n\u001b[1;32m     63\u001b[0m         \u001b[39mprint\u001b[39m(\u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mLlegue al top, estoy compitiendo profesionalmente en la seleccion \u001b[39m\u001b[39m{\u001b[39;00m\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mseleccion\u001b[39m}\u001b[39;00m\u001b[39m!\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m---> 65\u001b[0m Juan \u001b[39m=\u001b[39m SeleccionadoDCC(nombre\u001b[39m=\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39mJuan\u001b[39;49m\u001b[39m\"\u001b[39;49m,numero_estudiante\u001b[39m=\u001b[39;49m\u001b[39m1232\u001b[39;49m,\n\u001b[1;32m     66\u001b[0m semestre_actual\u001b[39m=\u001b[39;49m\u001b[39m2\u001b[39;49m,sist_operativo\u001b[39m=\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39mpython\u001b[39;49m\u001b[39m\"\u001b[39;49m,\n\u001b[1;32m     67\u001b[0m version_python\u001b[39m=\u001b[39;49m\u001b[39m3.10\u001b[39;49m,seleccion\u001b[39m=\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39mChilena\u001b[39;49m\u001b[39m\"\u001b[39;49m)\n\u001b[1;32m     68\u001b[0m Juan\u001b[39m.\u001b[39mseleccionado()\n",
      "Cell \u001b[0;32mIn[2], line 60\u001b[0m, in \u001b[0;36mSeleccionadoDCC.__init__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m     59\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39m__init__\u001b[39m(\u001b[39mself\u001b[39m, \u001b[39m*\u001b[39margs, \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mkwargs):\n\u001b[0;32m---> 60\u001b[0m     \u001b[39msuper\u001b[39;49m()\u001b[39m.\u001b[39;49m\u001b[39m__init__\u001b[39;49m(\u001b[39m*\u001b[39;49margs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n",
      "\u001b[0;31mTypeError\u001b[0m: object.__init__() takes exactly one argument (the instance to initialize)"
     ]
    }
   ],
   "source": [
    "from abc import ABC, abstractmethod\n",
    "#Completar\n",
    "class EstudianteUc: \n",
    "    #Clase base\n",
    "\n",
    "    def __init__(self, nombre, numero_estudiante, semestre_actual):\n",
    "        self.nombre = nombre\n",
    "        self.numero_estudiante = numero_estudiante\n",
    "        self.semestre_actual = semestre_actual\n",
    "\n",
    "    def asistir_clase(self, clase):\n",
    "        print(f\"Asistiendo a la clase de {clase}\")\n",
    "\n",
    "    def procrastinar(self):\n",
    "        print(\"Zzzzzz...\")\n",
    "\n",
    "    #Completar\n",
    "    def ir_a_la_universidad(self):\n",
    "        pass\n",
    "\n",
    "    #Completar\n",
    "    def pasar_de_largo(self):\n",
    "        pass\n",
    "\n",
    "#Completar\n",
    "class EstudianteDCC: \n",
    "    # Heredamos de EstudianteUC\n",
    "\n",
    "    def __init__(self, sist_operativo, version_python, *args, **kwargs):\n",
    "        #Completar\n",
    "        #Heredamos los atributos necesarios (lo mismo para las otras clases que heredan)\n",
    "        self.sist_operativo = sist_operativo\n",
    "        self.version_python = version_python\n",
    "\n",
    "    def programar(self):\n",
    "        print(f\"Programando en python versión {self.version_python}\")\n",
    "\n",
    "    def pasar_de_largo(self):\n",
    "        print(\"No entiendo la multiherencia...\")\n",
    "\n",
    "    def ir_a_la_universidad(self):\n",
    "        print(\"Yendo al DCC...\")\n",
    "#Completar\n",
    "class SeleccionadoUC: \n",
    "\n",
    "    def __init__(self, seleccion, *args, **kwargs):\n",
    "        #Completar\n",
    "        self.seleccion = seleccion\n",
    "    \n",
    "    def juego(self, contrincante):\n",
    "        print(f\"Jugando contra {contrincante}\")\n",
    "\n",
    "    def ir_a_la_universidad(self):\n",
    "        print(\"Yendo a las canchas de deporte\")\n",
    "#Completar\n",
    "class SeleccionadoDCC: \n",
    "    # Hacemos multiherencia\n",
    "\n",
    "    def __init__(self, *args, **kwargs):\n",
    "        super().__init__(*args, **kwargs)\n",
    "\n",
    "    def seleccionado(self):\n",
    "        print(f\"Llegue al top, estoy compitiendo profesionalmente en la seleccion {self.seleccion}!\")\n",
    "            \n",
    "Juan = SeleccionadoDCC(nombre=\"Juan\",numero_estudiante=1232,\n",
    "semestre_actual=2,sist_operativo=\"python\",\n",
    "version_python=3.10,seleccion=\"Chilena\")\n",
    "Juan.seleccionado()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Listas 2: ¡Ahora con más métodos!\n",
    "\n",
    "En el DCC nos cansamos de los métodos tradicionales de las listas, y queremos más. Podríamos crear una clase nueva, pero tendríamos que programar todo desde cero 😕 y francamente nos da lata. Por suerte, nos acordamos de las clases de Programación Avanzada, y de un concepto en especial que nos va a servir mucho: ¡Herencia!\n",
    "\n",
    "Vamos a crear una nueva clase, Lista2, que herede de **list**, para conservar los métodos que ya conocemos, y añadirle 4 métodos mas: \n",
    "\n",
    "- repetidos: elimina los elementos repetidos de la lista\n",
    "- mediana: retorna la mediana de la lista (sólo para listas de números, en otro caso no retorna nada)\n",
    "- aleatorizar: reordena la lista de forma aleatoria\n",
    "- moda: retorna el elemento que se repite más veces en la lista\n",
    "\n",
    "Para esto, tenemos el siguiente código base:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Lista original: ['hola', 'mundo', 'mundo', 1, 1, 1, 2, 3, 7]\n",
      "Moda: None\n",
      "Lista sin repetidos: ['hola', 'mundo', 'mundo', 1, 1, 1, 2, 3, 7]\n",
      "\n",
      "Lista original: [1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
      "Lista aleatorizada: [1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
      "Mediana: None\n"
     ]
    }
   ],
   "source": [
    "from random import randint\n",
    "\n",
    "\n",
    "class Lista2(list):\n",
    "\n",
    "    def repetidos(self):\n",
    "        ## COMPLETAR\n",
    "        pass\n",
    "\n",
    "    def mediana(self):\n",
    "        ## hint: la función isinstance(a, B) retorna True si el objeto a es de la clase B,\n",
    "        ## y False en otro caso\n",
    "        ## COMPLETAR\n",
    "        pass\n",
    "\n",
    "    def aleatorizar(self):\n",
    "        ## hint: lista.copy crea una copia de lista la cual podemos modificar sin afectar\n",
    "        ## a la lista original\n",
    "        ## COMPLETAR\n",
    "        pass\n",
    "\n",
    "    def moda(self):\n",
    "        ## COMPLETAR\n",
    "        pass\n",
    "\n",
    "\n",
    "lista = Lista2([\"hola\", \"mundo\", \"mundo\", 1, 1, 1, 2, 3, 7])\n",
    "print(f\"Lista original: {lista}\")\n",
    "print(f\"Moda: {lista.moda()}\")\n",
    "lista.repetidos()\n",
    "print(f\"Lista sin repetidos: {lista}\")\n",
    "print()\n",
    "\n",
    "lista = Lista2([1, 2, 3, 4, 5, 6, 7, 8, 9])\n",
    "print(f\"Lista original: {lista}\")\n",
    "lista.aleatorizar()\n",
    "print(f\"Lista aleatorizada: {lista}\")\n",
    "print(f\"Mediana: {lista.mediana()}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DCCentral Zoo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En este zoo, nos encontraremos con animales carnívoros, herbívoros y omnívoros. Se te entregará una clase `Animal`, la cual no debes modificar. Además, encontrarás las clases `Carnivoro` y `Herbivoro`, la cuales debemos modificar para que hereden de la clase `Animal`.\n",
    "\n",
    "Finalmente, tendrás la clase `Omnivoro`, la cual debe heredar de `Carnivoro` y `Herbivoro`. En ésta también deberás heredar los métodos `exhibicion()` de todas las clases padre."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# No modificar\n",
    "class Animal():\n",
    "\n",
    "    def __init__(self, nombre, clasificacion):\n",
    "        self.nombre = nombre\n",
    "        self.clasificacion = clasificacion\n",
    "    \n",
    "    def exhibicion(self):\n",
    "        print(f\"El animal es un {self.nombre} y es un {self.clasificacion}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Completar\n",
    "class Carnivoro():\n",
    "    # Completar\n",
    "    def __init__(self, carne_consumida, hambre):\n",
    "        # Completar\n",
    "        self.carne_consumida = carne_consumida\n",
    "        self.hambre = hambre\n",
    "        \n",
    "    def exhibicion(self):\n",
    "        super().exhibicion()\n",
    "        print(f'Ha comido {self.carne_consumida}kg de carne y quedó con {self.hambre} hambre.')\n",
    "\n",
    "# Completar\n",
    "class Herbivoro():\n",
    "    # Completar\n",
    "    def __init__(self, verduras_consumidas):\n",
    "        # Completar\n",
    "        self.verduras_consumidas = verduras_consumidas\n",
    "    \n",
    "    def exhibicion(self):\n",
    "        super().exhibicion()\n",
    "        print(f'Ha comido {self.verduras_consumidas} verduras hoy.')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Completar\n",
    "class Omnivoro():\n",
    "    # Completar\n",
    "    def __init__(self):\n",
    "        # Completar\n",
    "\n",
    "    def exhibicion(self):\n",
    "        # Completar"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Código testeo\n",
    "Chanchito = Omnivoro(nombre=\"Chanchito\", clasificacion=\"Mamífero\", carne_consumida=2, \n",
    "                     hambre=\"mucha\", verduras_consumidas=5)\n",
    "\n",
    "Chanchito.exhibicion()"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.10.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
