{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "view-in-github" }, "source": [ "\"Open" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Clases" ] }, { "cell_type": "markdown", "metadata": { "id": "Y6JhrcAwKDy2" }, "source": [ "En Python, todo es un objeto, es decir, una instancia o realización de un clase. Cada objeto tiene unos _métodos_:\n", "```python\n", "objeto.metodo(...)\n", "que corresponde a funciónes internas del objeto, y también puede tener _atributos_:\n", "```\n", "```python\n", "objeto.atributo\n", "```\n", "que son variables internas dentro del objeto: `self.atributo=....`.\n", "\n", "Algunos objetos en Python también pueden recibir parámetros de entrada a modo de claves de un diccionario interno del objeto\n", "```python\n", "objeto['key']='value'\n", "```\n", "entro otras muchas propiedades\n", "\n", "Ejemplos de objetos son:\n", "* `int`: Enteros\n", "* `float`: Números punto flotante (floating point numbers)\n", "* `str`: Cadenas de caracteres\n", "* `list`: Listas \n", "* `dict`: Diccionarios.\n", "\n", "Si el tipo de objeto es conocido, uno pude comprobar si un objeto determinado corresponde a ese tipo con `isinstance`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "VL4_IkdUch2X", "outputId": "b248af0d-a1e8-4212-827c-df438d36cca6" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Is `s` an string?: True\n", "Is `s` a float?: False\n" ] } ], "source": [ "s='hola mundo'\n", "print('Is `s` an string?: {}'.format( isinstance(s,str)) )\n", "print('Is `s` a float?: {}'.format( isinstance(s,float)) )" ] }, { "cell_type": "markdown", "metadata": { "id": "mKFFMHWNch2Z" }, "source": [ "Dentro del paradigma de objetos es posible agrupar diferentes conjuntos de variables de modo que el nombre de un atributo a método adquiere dos partes, una parte principal, que en el análogo con el _nombre completo_ de una persona podríamos asimilar a su _apellido_, y el método o atributo, que sería como el primer _nombre_, separados por un punto:\n", "* Método: `last_name.first_name()`\n", "* Atributo: `last_name.first_name`.\n", "\n", "Esto nos permite tener objetos dentro de un programa con igual _nombre_, pero diferente _appellido_. Como por ejemplo, los diferentes $\\cos(x)$ que vienen en los diferentes módulos matématicos implementados en Python. Por eso es recomendado cargar los módulos manteniendo el espacio de nombres (que en nuestra analogía sería el espacio de _apellidos_). Cuando el modulo tenga un nombre muy largo (más de cuatro caracteres), se puede usar una abreviatura lo suficientemente original para evitar que pueda ser sobreescrita por un nuevo objeto:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "xrpdksxpch2a", "outputId": "b7c72bbd-9e7f-40e9-bb45-7a8fddf73d0b" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x(t)=-2.31 m\n", "x(t)=-2.31 m\n" ] } ], "source": [ "import math as math\n", "import numpy as np\n", "k=3 #N/m\n", "m=2 #Kg\n", "A=3 #m\n", "t=2 #s\n", "ω=np.sqrt(k/m) #rad/s\n", "#ver https://pyformat.info/\n", "print('x(t)={:.2f} m'.format( \n", " A*np.cos( ω*t )\n", " ))\n", "print('x(t)={:.2f} m'.format( \n", " A*math.cos( ω*t )\n", " ))" ] }, { "cell_type": "markdown", "metadata": { "id": "D8a0Ytbtch2b" }, "source": [ "Note que `import math as m` entraría en conflicto con la definición de `m` en `m=2`" ] }, { "cell_type": "markdown", "metadata": { "id": "5-euuXoZch2b" }, "source": [ "La forma recomendada de importar los diferentes módulos y el uso de sus métodos y atributos suele resumirse en _Cheat Sheets_. Para Python científico recomendamos las elaboradas por [Data Camp](https://learn.datacamp.com/), que pueden consultarse [aquí](https://drive.google.com/drive/folders/11ReN5mXiYGsBjNfdj3zEj2Z1E3bZ7TRk?usp=sharing) " ] }, { "cell_type": "markdown", "metadata": { "id": "5-ilzJUuch2c" }, "source": [ "Para programación de Python en general se recomienda el estándar [PEP 8](https://www.python.org/dev/peps/pep-0008/) de Python" ] }, { "cell_type": "markdown", "metadata": { "id": "EElmSBoHch2d" }, "source": [ "Antes de comenzar con las clases, es conveniente resumir el paradigma de _programación funcional_:" ] }, { "cell_type": "markdown", "metadata": { "id": "YiIs6z25LOiN" }, "source": [ "## Programación funcional\n", "En cálculo científico el paradigma funcional, en el cual el programa se escribe en términos de funciones, suele ser suficiente.\n", "\n", "El esqueleto de un programa funcional es típicamente del siguiente tipo\n", "```python\n", "#!/usr/bin/env python3\n", "import somemodule as sm\n", "def func1(...):\n", " '''\n", " Ayuda func1\n", " '''\n", " .....\n", "\n", "def func2(...):\n", " '''\n", " Ayuda func2\n", " '''\n", " .....\n", " \n", " \n", "def main(...):\n", " '''\n", " Ayuda función principal\n", " '''\n", " x=func1(...)\n", " y=func2(x)\n", " \n", "if __name__=='__main__':\n", " z=main(...)\n", " print('El resultado final es: {}'.format(z))\n", "\n", "```\n", "\n", "Para su diseño, el programa se debe separar sus partes independientes y para cada una de ellas se debe definir una función. \n", "\n", "_La función ideal es una que se pueda reutilizar facilamente en otro contexto._\n", "\n", "La última función, `main(...)` combina todas las anteriores para entregar el resultado final del programa. \n", "\n", "La instrucción \n", "```python\n", "if __name__=='__main__'\n", "```\n", "permite que el programa pueda ser usado también como un módulo de Python, es decir que se pueda cargar desde otro programa con el `import`. En tal caso, la variable \n", "interna de Python `__name__` es diferente a la cadena de caracteres `'__main__'` y esa parte del programa no se ejecuta. Dentro de Jupyter:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "4hPNCRcoPLim", "outputId": "dd9f0b2c-1d87-4ff3-fc7a-d3d09552c0ac" }, "outputs": [ { "data": { "text/plain": [ "'__main__'" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "__name__" ] }, { "cell_type": "markdown", "metadata": { "id": "WC3Mm-fYjnT_" }, "source": [ "Ejemplo módulo" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "GuE_ERSyjqXc", "outputId": "8178b893-0303-4361-d930-74b4435123e8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting example.py\n" ] } ], "source": [ "%%writefile example.py\n", "#!/usr/bin/env python3\n", "print( f'check: {__name__}')\n", "\n", "def hola():\n", " print( f'check {__name__} como módulo:')\n", " print('mundo')\n", " \n", "if __name__=='__main__':\n", " hola()" ] }, { "cell_type": "markdown", "metadata": { "id": "M_jJDcm-lfAY" }, "source": [ "`ls` funciona" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 70 }, "id": "U3DfHFmWkUNa", "outputId": "bd6c9847-5d59-43a3-bbf6-57d8db102a49" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-rwxr-xr-x 1 restrepo restrepo 171 Mar 31 14:11 \u001b[0m\u001b[01;32mexample.py\u001b[0m*\n" ] } ], "source": [ "ls -l example.py" ] }, { "cell_type": "markdown", "metadata": { "id": "B7jkUAFKlho4" }, "source": [ "`cat` funciona" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 158 }, "id": "F1cmyMlFj3RC", "outputId": "c8ff021f-59b4-46e6-8004-5c456de602c0" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#!/usr/bin/env python3\n", "print( f'check: {__name__}')\n", "\n", "def hola():\n", " print( f'check {__name__} como módulo:')\n", " print('mundo')\n", " \n", "if __name__=='__main__':\n", " hola()\n" ] } ], "source": [ "cat example.py " ] }, { "cell_type": "markdown", "metadata": { "id": "HBmG35Rhlpk3" }, "source": [ "Cambia los permisos a ejecución" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "a_R1GXDlkZZ6" }, "outputs": [], "source": [ "! chmod a+x example.py" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 70 }, "id": "KB3f-x2NkwIZ", "outputId": "e43d1921-cc69-4b83-800a-0107c83ab03e" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-rwxr-xr-x 1 restrepo restrepo 171 Mar 31 14:11 \u001b[0m\u001b[01;32mexample.py\u001b[0m*\n" ] } ], "source": [ "ls -l example.py" ] }, { "cell_type": "markdown", "metadata": { "id": "DLHOmcEJlt5_" }, "source": [ "Corre el programa desde la consola" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 52 }, "id": "6-KSDo18k3HQ", "outputId": "510e7649-d958-454c-c877-e541f182403c" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "check: __main__\n", "check __main__ como módulo:\n", "mundo\n" ] } ], "source": [ "!./example.py" ] }, { "cell_type": "markdown", "metadata": { "id": "XBz-Kvq1mMo2" }, "source": [ "Uso como módulo" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "mgBWS5egmPFe", "outputId": "bc00463f-24d9-4232-96e0-befe6547a5b3" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "check: example\n" ] } ], "source": [ "import example" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "6nFatG0wmg8e", "outputId": "f4a13459-8364-4ad0-fb90-6817003be442" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "check example como módulo:\n", "mundo\n" ] } ], "source": [ "example.hola()" ] }, { "cell_type": "markdown", "metadata": { "id": "1pMrHnnsmxPO" }, "source": [ "Ejecutarlo desde una celda de Jupyter es equivalente a ejecutarlo desde la consola" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 52 }, "id": "WPU62rAJm39l", "outputId": "8b5ce17b-f2cc-4757-9189-42d54bc5ffa8" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "check __name__: __main__\n", "mundo\n" ] } ], "source": [ "#!/usr/bin/env python3\n", "print( 'check __name__: {}'.format(__name__))\n", "\n", "def hola():\n", " print('mundo')\n", " \n", "if __name__=='__main__':\n", " hola()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "BJuBYKwqch2m", "outputId": "c46d7683-2b70-447a-d548-24809a86514c" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Overwriting example.py\n" ] } ], "source": [ "%%writefile example.py\n", "#!/usr/bin/env python3\n", "import sys\n", "if __name__=='__main__':\n", " print(sys.argv)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qeolpQWpch2m", "outputId": "b4f2e433-06ff-47aa-a56f-c0e41e78a9e9" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['./example.py', 'df', 'll', '1', '3']\n" ] } ], "source": [ "!./example.py df ll 1 3" ] }, { "cell_type": "markdown", "metadata": { "id": "bu-T7xMbch2m" }, "source": [ "## Clases" ] }, { "cell_type": "markdown", "metadata": { "id": "JPW8SLdmch2m" }, "source": [ "Aunque en Python se puede trabajar directamente con objetos, en general un objeto es una instancia de un clase. Es decir, debe incializarse a partir de una Clase. Esto típicamente involucra ejecutar varios métodos e inicializar varios atributos bajo el espacio de nombres del objeto incializado. Por ejemplo, para inicializar las clases 'int', 'float', 'str', 'list','dict'" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "YtwqDd7xch2n", "outputId": "3aa09439-6b29-4801-c849-a12662c2d5d6" }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n=int() ## ⬄ to n=0\n", "n" ] }, { "cell_type": "markdown", "metadata": { "id": "IjXM_D9Dch2n" }, "source": [ "* `int` es la clase\n", "* `int()` es la instancia de la clase\n", "* `n=int()` es el objeto asociado a la clase: `n.→` contiene todos los atributos y los métodos de la clase `int`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "PpaghYNrch2n", "outputId": "41742134-83f0-411a-c77e-9205d13b30d8" }, "outputs": [ { "data": { "text/plain": [ "6.0" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x=float(6) ## ⬄ x=3.\n", "x" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "EiMFVU31ch2n", "outputId": "c8009866-ca8f-46be-b817-c3ea80727788" }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l=list() ## ⬄ l=[]\n", "l" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "TPphjkn_ch2o", "outputId": "092b66fd-53af-4694-bd74-7546549152ad" }, "outputs": [ { "data": { "text/plain": [ "{}" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d=dict() ## ⬄ d={}\n", "d" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qHNP7wMtch2o" }, "outputs": [], "source": [ "#tupla vacía\n", "A=set()" ] }, { "cell_type": "markdown", "metadata": { "id": "6VBaBTsfch2o" }, "source": [ "La principal motivación para escribir una clase en lugar de una función, es que la clase puede ser la base para generar nuevas clases que hereden los métodos y atributos de la clase original." ] }, { "cell_type": "markdown", "metadata": { "id": "e6E4zuVXch2p" }, "source": [ "Por ejemplo el DataFrame de Pandas es una clase que puede ser inicializada de múltiples formas. Además, está diseñada para que pueda ser extendida facilmente: https://pandas.pydata.org/pandas-docs/stable/development/extending.html" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "hvBKPIKHch2p" }, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": { "id": "t7mRnLqCch2p" }, "source": [ "```python\n", "In[1]: pd.DataFrame??\n", "...\n", "class DataFrame(NDFrame):\n", " ...\n", " ## ----------------------------------------------------------------------\n", " ## Constructors\n", "\n", " def __init__(self, data=None, index=None, columns=None, dtype=None,\n", " copy=False):\n", " if data is None:\n", " ...\n", "```" ] }, { "cell_type": "markdown", "metadata": { "id": "xTbXI-lMch2p" }, "source": [ "Como puede verse, un `DataFrame` es una subclase (es decir, un caso especial) de `NDFrame`." ] }, { "cell_type": "markdown", "metadata": { "id": "8zpfP7tBch2p" }, "source": [ "Una _instancia_ u objeto de la clase `DataFrame`, `df` a continuación, se puede inicializar de diferentes maneras" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "yfBCClJBch2q", "outputId": "d3cd1b1e-de51-41ce-9f00-513ec015e6e2" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", "
" ], "text/plain": [ "Empty DataFrame\n", "Columns: []\n", "Index: []" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df=pd.DataFrame()\n", "df" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "MrVMec2_ch2q", "outputId": "40dba0fb-6418-4062-e471-ff66b099aa23" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
AB
012
\n", "
" ], "text/plain": [ " A B\n", "0 1 2" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df=pd.DataFrame([{'A':1,'B':2}])\n", "df" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "frkENBdLch2q", "outputId": "e8fb5578-d454-4656-985e-c1b704f11de9" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
AB
012
\n", "
" ], "text/plain": [ " A B\n", "0 1 2" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df=pd.DataFrame({'A':[1],'B':[2]})\n", "df" ] }, { "cell_type": "markdown", "metadata": { "id": "yMv7DnahY-Iz" }, "source": [ "### Programación por clases" ] }, { "cell_type": "markdown", "metadata": { "id": "Rw3fn_2DZBbT" }, "source": [ "Una clase se puede pensar como un conjuto de funciones y atributos que comparten algo en común.\n", "\n", "Algunas veces, cuando la complejidad del problema se puede descomponer en una estructura de capas, donde la capa interna es la mas simple y las capas más externas van aumentando la complejidad, pude ser conveniente pensar en una estructura de clases.\n", "\n", "De hecho, la clase básica puede heredar todas sus propiedades a subclases basadas en ella.\n", "\n", "El espacio de nombres asociado a la clase se define con el nombre génerico de `self` el cual toma el nombre de las instancia (objeto) asociada a la inicialización de la clase. \n", "Las variables globales de la clase pasán a ser automáticamente atributos del objeto, y nuevo atributos de pueden definir dentro del espacio de nombres `self` dentro de cada función de la clase.\n", "\n", "Esqueleto:\n", "```python\n", "class clasenueva:\n", " '''\n", " Ayuda de la clase\n", " '''\n", "\n", " var1='valor' #variable global → atributo de la clase\n", " def func1(self,...): #método de la clase\n", " '''\n", " Ayuda del método\n", " '''\n", " self.var2='hola mundo' #atributo de la clase\n", " ....\n", " def func2(self,....):\n", " '''\n", " Ayuda del método\n", " ''' \n", " print(self.var1)\n", " print(self.var2)\n", " ....\n", " \n", " def main(self,....):\n", " ....\n", "```" ] }, { "cell_type": "markdown", "metadata": { "id": "b_QUWbnTch2r" }, "source": [ "Cada una de las funciones pasan a ser métodos de la clase, mientras que cada una de la variables globales y con espacio de nombre `self` pasan a ser atributos de la clase.\n", "\n", "__Ejemplo__:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qqfKH0_lch2r" }, "outputs": [], "source": [ "class clasenueva:\n", " var='hola'\n", " var2=[]\n", " def main(self):\n", " self.var=self.var+' mundo'\n", " self.var3=self.var2+[3]\n", " print(self.var)" ] }, { "cell_type": "markdown", "metadata": { "id": "LQTLuyKkch2r" }, "source": [ "Creación del objeto `c`, de manera que `self` → `c`. `c` es una instancia de la clase `clasenueva` a continuación:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ADt9DQLoch2s" }, "outputs": [], "source": [ "c=clasenueva()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "mQwQp-NMch2s", "outputId": "d270a811-465e-473b-cf0f-3ad6068f8273" }, "outputs": [ { "data": { "text/plain": [ "'hola'" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.var" ] }, { "cell_type": "markdown", "metadata": { "id": "e6uOd1Each2s" }, "source": [ "`main` es un método de la clase" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "wrOs-XjJch2s", "outputId": "f7942beb-2d5b-44b1-a0ab-46bf0713d944" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "hola mundo\n" ] } ], "source": [ "c.main()" ] }, { "cell_type": "markdown", "metadata": { "id": "Q9o-UrEpch2t" }, "source": [ "`var` es un atributo de la clase" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "VNpU3dLBch2t", "outputId": "65534e4f-6466-4a13-b5dc-2a0e131c3a56" }, "outputs": [ { "data": { "text/plain": [ "'hola mundo'" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.var" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "BUW1_ejxch2t", "outputId": "ba3f246e-15aa-4241-b779-2a11c1237022" }, "outputs": [ { "data": { "text/plain": [ "[3]" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.var3" ] }, { "cell_type": "markdown", "metadata": { "id": "KV_26T0Ach2t" }, "source": [ "Para la creación de clases disponemos de métodos especiales, constructores, que podemos definir para adicionar \"magia\" a nuestras clases. Estas están simpre rodeadas de un doble guión bajo, por ejemplo: `__init__` o `__lt__`. Una lista completa de ellos con su explicación de uso se puede encontrar en [1](#References).\n", "\n", "Resaltamos a continuación algunos de ellos\n", "\n", "* `__init__`: Se ejecuta automáticamente al inicializar la clase\n", "* `__add__`: Sobrecarga el operador suma, `+` → self + other" ] }, { "cell_type": "markdown", "metadata": { "id": "POC6K83Rch2t", "tags": [] }, "source": [ "For example, with `__init__`, the previous class is" ] }, { "cell_type": "code", "execution_count": 156, "metadata": { "id": "zJ-lwibdch2u" }, "outputs": [], "source": [ "class clasenueva:\n", " def __init__(self):\n", " self.var='hola'\n", " self.var2=[]\n", " def main(self):\n", " self.var=self.var+' mundo'\n", " self.var3=self.var2+[3]\n", " print(self.var)" ] }, { "cell_type": "code", "execution_count": 157, "metadata": { "id": "N2OH80pBch2u", "outputId": "788f3788-3972-4da6-c7a6-c5e58ca2a642" }, "outputs": [ { "data": { "text/plain": [ "'hola'" ] }, "execution_count": 157, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c=clasenueva()\n", "c.var" ] }, { "cell_type": "markdown", "metadata": { "id": "udotZC4Ich2u" }, "source": [ "### Herencia\n", "Los métodos especiales se pueden heredar automáticamente desde la clase inicial, que llamaremos `superclass`. Para ello inicializamos la clase con la `superclass` como argumento, es decir, en forma genérica como:\n", "```python\n", "class subclass(superclass):\n", " ...\n", "```" ] }, { "cell_type": "code", "execution_count": 161, "metadata": { "id": "cCR6nXUgch2u" }, "outputs": [], "source": [ "import copy\n", "import random\n", "\n", "class animal:\n", " stage='baby' #or kid or adult\n", " sex='male'\n", " eyes=2\n", " live=True\n", " def __add__(self,other):\n", " if (type(self)==type(other) and \n", " self.stage=='adult' and \n", " other.stage=='adult' and \n", " self.sex!=other.sex):\n", " baby=copy.copy(self)\n", " baby.stage='baby'\n", " baby.sex=random.choice(['female','male'])\n", " if isinstance(self,insect):\n", " baby.stage=='larvae' \n", " return baby\n", " else:\n", " return None\n", "\n", "class insect(animal):\n", " def __init__(self,stage='larvae',sex='male',wings=0,\n", " legs=0,anntenaes=0,eyes=0,stings=0):\n", " self.stage=stage\n", " self.sex=sex\n", " self.wings=wings\n", " self.legs=legs\n", " self.anntenaes=anntenaes\n", " self.eyes=eyes\n", " self.stings=stings \n", " if self.stage=='baby':\n", " self.stage=='larvae'\n", " self.bones=False\n", "\n", "class vertebrate(animal):\n", " bones=True\n", "\n", "class bird(vertebrate):\n", " def __init__(self,stage='baby',sex='male'):\n", " self.stage=stage\n", " self.sex=sex\n", " self.wings=2\n", " self.legs=2\n", " self.eyes=2\n", " self.feathers=True\n", " " ] }, { "cell_type": "code", "execution_count": 162, "metadata": { "id": "0wIibPaGch2v" }, "outputs": [], "source": [ "butterfly=insect(stage='adult',wings=2,legs=6,anntenaes=2,eyes=1700)\n", "pigeon = bird(stage='adult',sex='female')\n", "other_pigeon=bird(stage='adult',sex='male')" ] }, { "cell_type": "code", "execution_count": 163, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "3JyrjTYPl8o2", "outputId": "d58f0792-d5a1-425d-e500-e5a6774a5e48" }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 163, "metadata": {}, "output_type": "execute_result" } ], "source": [ "butterfly.live" ] }, { "cell_type": "code", "execution_count": 165, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "ayfaY0BLch2v", "outputId": "48ef317e-cd92-4161-8afe-5965e37390c1" }, "outputs": [ { "data": { "text/plain": [ "('baby', 'male')" ] }, "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#__add__( self , other ) \n", "squab = pigeon + other_pigeon\n", "squab.stage,squab.sex" ] }, { "cell_type": "code", "execution_count": 166, "metadata": { "id": "ZHWL7Iwhch2v" }, "outputs": [], "source": [ "pigeon+pigeon" ] }, { "cell_type": "code", "execution_count": 167, "metadata": { "id": "gcb017amch2v" }, "outputs": [], "source": [ "butterfly+pigeon" ] }, { "cell_type": "markdown", "metadata": { "id": "iyp1GRTYch2w" }, "source": [ "Cree una clase `mamal` o una clase `fish`" ] }, { "cell_type": "markdown", "metadata": { "id": "IM9gxUyXQrg4" }, "source": [ "### Reescribir método de `superclass`" ] }, { "cell_type": "code", "execution_count": 168, "metadata": { "id": "8yK6QoIWQnSR" }, "outputs": [], "source": [ "class animal:\n", " def __init__(self):\n", " self.stage='baby' #or kid or adult\n", " self.sex='male'\n", " self.eyes=2\n", " self.live=True\n", " def __add__(self,other):\n", " if (type(self)==type(other) and \n", " self.stage=='adult' and \n", " other.stage=='adult' and \n", " self.sex!=other.sex):\n", " baby=copy.copy(self)\n", " baby.stage='baby'\n", " baby.sex=random.choice(['female','male'])\n", " if isinstance(self,insect):\n", " baby.stage=='larvae' \n", " return baby\n", " else:\n", " return None\n", "\n", "class insect(animal):\n", " def __init__(self,stage='larvae',sex='male',wings=0,\n", " legs=0,anntenaes=0,eyes=0,stings=0):\n", " self.stage=stage\n", " self.sex=sex\n", " self.wings=wings\n", " self.legs=legs\n", " self.anntenaes=anntenaes\n", " self.eyes=eyes\n", " self.stings=stings \n", " if self.stage=='baby':\n", " self.stage=='larvae'\n", " self.bones=False " ] }, { "cell_type": "code", "execution_count": 169, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 183 }, "id": "RiX73y4wmJHN", "outputId": "880ae63b-c118-4525-9163-9680a59bf35d" }, "outputs": [ { "ename": "AttributeError", "evalue": "'insect' object has no attribute 'live'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn [169], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m butterfly\u001b[38;5;241m=\u001b[39minsect(stage\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124madult\u001b[39m\u001b[38;5;124m'\u001b[39m,wings\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m,legs\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m6\u001b[39m,anntenaes\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m2\u001b[39m,eyes\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1700\u001b[39m)\n\u001b[0;32m----> 2\u001b[0m butterfly\u001b[38;5;241m.\u001b[39mlive\n", "\u001b[0;31mAttributeError\u001b[0m: 'insect' object has no attribute 'live'" ] } ], "source": [ "butterfly=insect(stage='adult',wings=2,legs=6,anntenaes=2,eyes=1700)\n", "butterfly.live" ] }, { "cell_type": "markdown", "metadata": { "id": "6MnnPiCsQHYi" }, "source": [ "### Use un método de la `superclass` con `super`\n", "Si lo que queremos es _modificar_ el comportomiento de un método de una superclase entonces debemos usar la función `super`.\n", "\n", "Para mantener la herencia el comportamiento de los métodos de una clase inicial, ls _super_ clase, se usa la función `super` que mantiene la __herencia__. Ver:\n", "* https://realpython.com/python-super/ ([Backup](https://web.archive.org/web/20190922043302/https://realpython.com/python-super/))\n", "* https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ ([Backup](https://web.archive.org/web/20191129114558/https://rhettinger.wordpress.com/2011/05/26/super-considered-super/))\n", "\n", "> `super()` gives you access to methods in a superclass from the subclass that inherits from it.\n", "\n", "> `super()` is the same as `super(__class__, )`: the first is the subclass, and the second parameter is an object that is an instance of that subclass.\n", "\n", "La estructura general es como la siguiente, basada en [Inherited class variable modification in Python](http://stackoverflow.com/questions/13404476/inherited-class-variable-modification-in-python):\n", "```python\n", "class subclass(superclass):\n", " def __special__(self,*args, **kwargs):\n", " #Modifications to __especial__ here\n", " ...\n", " super(subclass, self).__special__(*args, **kwargs)\n", " ...\n", "```" ] }, { "cell_type": "markdown", "metadata": { "id": "DdlXLnEdQ_1j" }, "source": [ "Modificar la clase `animal` con un `__init__` y generar las subclases apropiadamente" ] }, { "cell_type": "code", "execution_count": 171, "metadata": { "id": "J_8-_6jQk-6z" }, "outputs": [], "source": [ "class animal:\n", " def __init__(self):\n", " self.stage='baby' #or kid or adult\n", " self.sex='male'\n", " self.eyes=2\n", " self.live=True\n", " def __add__(self,other):\n", " if (type(self)==type(other) and \n", " self.stage=='adult' and \n", " other.stage=='adult' and \n", " self.sex!=other.sex):\n", " baby=copy.copy(self)\n", " baby.stage='baby'\n", " baby.sex=random.choice(['female','male'])\n", " if isinstance(self,insect):\n", " baby.stage=='larvae' \n", " return baby\n", " else:\n", " return None\n", "\n", "class insect(animal):\n", " '''\n", " The pointers `*args` and `**kwargs` are not really necessary\n", " because the `__init__` in superclass does not have any\n", " '''\n", " def __init__(self,*args,stage='larvae',sex='male',wings=0,\n", " legs=0,anntenaes=0,eyes=0,stings=0,**kwargs):\n", " '''\n", " stage='larvae',sex='male',wings=0,\n", " legs=0,anntenaes=0,eyes=0,stings=0 \n", " '''\n", " super(insect, self).__init__(*args,**kwargs) \n", " \n", " self.stage=stage\n", " self.sex=sex\n", " self.wings=wings\n", " self.legs=legs\n", " self.anntenaes=anntenaes\n", " self.eyes=eyes\n", " self.stings=stings \n", " if self.stage=='baby':\n", " self.stage=='larvae'\n", " self.bones=False" ] }, { "cell_type": "code", "execution_count": 172, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "ebUgYMvYROh2", "outputId": "e83d2934-76c0-41c9-d810-43749ef42180" }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 172, "metadata": {}, "output_type": "execute_result" } ], "source": [ "butterfly=insect(stage='adult',wings=2,legs=6,anntenaes=2,eyes=1700)\n", "butterfly.live" ] }, { "cell_type": "code", "execution_count": 174, "metadata": { "id": "y1w9nE-QSFCK" }, "outputs": [], "source": [ "class animal:\n", " def __init__(self,live=True):\n", " self.stage='baby' #or kid or adult\n", " self.sex='male'\n", " self.eyes=2\n", " self.live=live\n", " def __add__(self,other):\n", " if (type(self)==type(other) and \n", " self.stage=='adult' and \n", " other.stage=='adult' and \n", " self.sex!=other.sex):\n", " baby=copy.copy(self)\n", " baby.stage='baby'\n", " baby.sex=random.choice(['female','male'])\n", " if isinstance(self,insect):\n", " baby.stage=='larvae' \n", " return baby\n", " else:\n", " return None\n", "\n", "class insect(animal):\n", " '''\n", " The pointers `*args` and `**kwargs` are necessary\n", " to access to the `**kwargs` of the `__init__` in superclass\n", " ''' \n", " def __init__(self,*args,stage='larvae',sex='male',wings=0,\n", " legs=0,anntenaes=0,eyes=0,stings=0,**kwargs):\n", " '''\n", " stage='larvae',sex='male',wings=0,\n", " legs=0,anntenaes=0,eyes=0,stings=0 \n", " '''\n", " super(insect, self).__init__(*args,**kwargs) \n", " \n", " self.stage=stage\n", " self.sex=sex\n", " self.wings=wings\n", " self.legs=legs\n", " self.anntenaes=anntenaes\n", " self.eyes=eyes\n", " self.stings=stings \n", " if self.stage=='baby':\n", " self.stage=='larvae'\n", " self.bones=False" ] }, { "cell_type": "code", "execution_count": 175, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "a_6mdr-mSUs3", "outputId": "492d28e1-8bd5-417d-8ec7-d0d64472d4a2" }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 175, "metadata": {}, "output_type": "execute_result" } ], "source": [ "butterfly=insect(stage='adult',wings=2,legs=6,anntenaes=2,eyes=1700,live=False)\n", "butterfly.live" ] }, { "cell_type": "markdown", "metadata": { "id": "wuJtCiN1ch2w" }, "source": [ "## Clase vector" ] }, { "cell_type": "markdown", "metadata": { "id": "HRoWDgwfch2w" }, "source": [ "Comenzaremos definiendo un alias de clase `list` que llameremos vector y que funcione exactamente igual que la clase lista. Todas los métodos especiales se heredan automáticamente" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "e9uHzANXch2w" }, "outputs": [], "source": [ "class vector(list):\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "i3NMM9Ckch2w" }, "outputs": [], "source": [ "l=list()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "0_NkK_Kych2x" }, "outputs": [], "source": [ "v=vector()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "9a34g3fich2x", "outputId": "9c359215-0aae-4374-f0a6-f29d0b7a7298" }, "outputs": [ { "data": { "text/plain": [ "[1]" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.append(1)\n", "v" ] }, { "cell_type": "code", "execution_count": 178, "metadata": { "id": "-DzkjlH_ch2x", "outputId": "79959638-7e8c-40f8-8a06-587096f5b41f" }, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4]" ] }, "execution_count": 178, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l1=[1,2]\n", "l2=[3,4]\n", "l1+l2" ] }, { "cell_type": "markdown", "metadata": { "id": "V-C2H9arch2x" }, "source": [ "Vamos a inicializar dos instancias de la clase `vector` y comprobar que suman como listas" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "CUSqRti7ch2x", "outputId": "c43b98f0-5fb1-40ef-8af3-bde417bd50ee" }, "outputs": [ { "data": { "text/plain": [ "[1, 2, 3, 4]" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1=vector(l1)\n", "v2=vector(l2)\n", "v1+v2" ] }, { "cell_type": "markdown", "metadata": { "id": "G1VFNFGqch2y" }, "source": [ "Ahora _reemplazaremos_ el método mágico `__add__` de la lista para que el operador `+` realice la suma vectorial:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "LhRNhG_tch2y", "outputId": "6e4a6146-2e6d-4582-d040-57992022ac54" }, "outputs": [ { "data": { "text/plain": [ "([1, 2], [3, 4])" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "l1,l2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "4KDkXwktch2y", "outputId": "4904a451-2345-433c-c33f-bfebe90b9a27" }, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mInit signature:\u001b[0m \u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m/\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m \n", "map(func, *iterables) --> map object\n", "\n", "Make an iterator that computes the function using arguments from\n", "each of the iterables. Stops when the shortest iterable is exhausted.\n", "\u001b[0;31mType:\u001b[0m type\n", "\u001b[0;31mSubclasses:\u001b[0m \n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "map?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "jQEO0NdUch22", "outputId": "1c08184b-db25-41d0-ded7-a05f1056d716" }, "outputs": [ { "data": { "text/plain": [ "[4, 6]" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(map(lambda x,y:x+y,l1,l2))" ] }, { "cell_type": "code", "execution_count": 179, "metadata": { "id": "1X4mou9tch22" }, "outputs": [], "source": [ "class vector(list):\n", " def __add__(self, other):\n", " '''\n", " __add__ asocia la operación del símbolo '+'\n", " '''\n", " return vector(map(lambda x,y: x+y, self, other)) " ] }, { "cell_type": "code", "execution_count": 180, "metadata": { "id": "vr8XYXDOch23" }, "outputs": [], "source": [ "v1=vector(l1)\n", "v2=vector(l2)" ] }, { "cell_type": "code", "execution_count": 181, "metadata": { "id": "ZLJEGICOch23", "outputId": "b9253fcc-a726-4b5a-9898-52744ee69c2b" }, "outputs": [ { "data": { "text/plain": [ "[4, 6]" ] }, "execution_count": 181, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1+v2" ] }, { "cell_type": "code", "execution_count": 182, "metadata": { "id": "Bec9hb61ch23", "outputId": "2cf38b1a-981c-499b-bac5-f87bb16201e8" }, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for -: 'vector' and 'vector'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn [182], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m v1\u001b[38;5;241m-\u001b[39mv2\n", "\u001b[0;31mTypeError\u001b[0m: unsupported operand type(s) for -: 'vector' and 'vector'" ] } ], "source": [ "v1-v2" ] }, { "cell_type": "code", "execution_count": 183, "metadata": { "id": "E9_AuTuYch23" }, "outputs": [], "source": [ "class vector(list):\n", " def __add__(self, other):\n", " '''\n", " __add__ asocia la operación del símbolo '+'\n", " '''\n", " return vector(map(lambda x,y: x+y, self, other))\n", " def __sub__(self, other):\n", " '''\n", " __sub__ asocia la operación del símbolo '-'\n", " '''\n", " return vector(map(lambda x,y: x-y, self, other)) " ] }, { "cell_type": "markdown", "metadata": { "id": "qm1_ULwYch24" }, "source": [ "Reiniciando el kernel de jupyter" ] }, { "cell_type": "code", "execution_count": 184, "metadata": { "id": "sIovjdbmch24" }, "outputs": [], "source": [ "v1=vector([5,8])\n", "v2=vector([3,6])" ] }, { "cell_type": "code", "execution_count": 185, "metadata": { "id": "EzzYTJmXch24", "outputId": "e27476b7-2d0f-41cd-b254-1c34fde50c00" }, "outputs": [ { "data": { "text/plain": [ "[8, 14]" ] }, "execution_count": 185, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1+v2" ] }, { "cell_type": "code", "execution_count": 186, "metadata": { "id": "1el6Uuv_ch24", "outputId": "05a68204-934b-4341-e5b5-78f2400f3f74" }, "outputs": [ { "data": { "text/plain": [ "[2, 2]" ] }, "execution_count": 186, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1-v2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "uUo7JYTxt_3l" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "_dpLO5UPvVSD" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "NAtt_0x7vVjw" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "-73wlkMfubhA", "outputId": "53922d8f-1de3-4bb4-ce67-ab2494afa503" }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "butterfly=insect(stage='adult',wings=2,legs=6,anntenaes=2,eyes=1700)\n", "butterfly.live" ] }, { "cell_type": "markdown", "metadata": { "id": "mJD2lllGch25" }, "source": [ "Como ejemplo, vamos a implemetar el atributo `modulus` a la clase `vector` dentro del método especial `__init__`:" ] }, { "cell_type": "code", "execution_count": 187, "metadata": { "id": "vxlXw0MSch25" }, "outputs": [], "source": [ "import math\n", "class vector(list):\n", " def __init__(self,*args, **kwargs):\n", " '''\n", " Add the modulus of a vector at initialization \n", " '''\n", " try:\n", " l=args[0]\n", " self.modulus=math.sqrt( sum( map( lambda l: l*l,l )) )\n", " except:\n", " self.modulus=0\n", " super(vector, self).__init__(*args, **kwargs)\n", " def __add__(self, other):\n", " '''\n", " __add__ asocia la operación del símbolo \"+\"\n", " '''\n", " return vector(map(lambda x,y: x+y, self, other))\n", " def __sub__(self, other):\n", " '''\n", " __sub__ asocia la operación del símbolo \"-\"\n", " '''\n", " return vector(map(lambda x,y: x-y, self, other)) " ] }, { "cell_type": "code", "execution_count": 188, "metadata": { "id": "r3FSF8Edch25", "outputId": "2b589365-ebbb-437f-b6b8-1ecda6db80a0" }, "outputs": [ { "data": { "text/plain": [ "[3, 2]" ] }, "execution_count": 188, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1=vector( [3,2] )\n", "v1" ] }, { "cell_type": "code", "execution_count": 189, "metadata": { "id": "8DTu2Thzch26", "outputId": "783c28a7-e25f-4adf-bf82-96d3bf38a0f0" }, "outputs": [ { "data": { "text/plain": [ "3.605551275463989" ] }, "execution_count": 189, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1.modulus" ] }, { "cell_type": "code", "execution_count": 190, "metadata": { "id": "S1zpJhMpch26", "outputId": "072a4bb1-de23-47f3-fc16-4b111a45a5df" }, "outputs": [ { "data": { "text/plain": [ "__main__.vector" ] }, "execution_count": 190, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(v1)" ] }, { "cell_type": "code", "execution_count": 193, "metadata": { "id": "ng9BSJODch26" }, "outputs": [ { "data": { "text/plain": [ "['append',\n", " 'clear',\n", " 'copy',\n", " 'count',\n", " 'extend',\n", " 'index',\n", " 'insert',\n", " 'modulus',\n", " 'pop',\n", " 'remove',\n", " 'reverse',\n", " 'sort']" ] }, "execution_count": 193, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[d for d in dir(v1) if d.find('__')==-1] " ] }, { "cell_type": "code", "execution_count": 195, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['anntenaes',\n", " 'bones',\n", " 'eyes',\n", " 'legs',\n", " 'live',\n", " 'sex',\n", " 'stage',\n", " 'stings',\n", " 'wings']" ] }, "execution_count": 195, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[d for d in dir(butterfly) if d.find('__')==-1] " ] }, { "cell_type": "markdown", "metadata": { "id": "WxQursOZch26" }, "source": [ "Una implementación completa de la clase vector, adapta de [vector: a list based vector class supporting elementwise operations (python recipe)](http://code.activestate.com/recipes/52272-vector-a-list-based-vector-class-supporting-elemen/), se puede encontrar [aquí](./vector.ipynb)" ] }, { "cell_type": "markdown", "metadata": { "id": "9h2u_9W6ch26" }, "source": [ "## Otro ejemplo" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "oD3cLkTHKDy4" }, "outputs": [], "source": [ "class veterinaria:\n", " def __init__(self,x):\n", " self.tipo={'perro':'guau','gato':'miau'}\n", " self.sonido=self.tipo.get(x)\n", " def __call__(self,nombre):\n", " if nombre=='greco':\n", " print(self.sonido)\n", " else:\n", " print(\"grrr!!\")\n", " def color(self,nombre):\n", " if nombre=='greco':\n", " print('blanco')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "UqLCY9R3s7ye" }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "id": "HRrOPyBwqkHc" }, "source": [ "* Cundo se inicializa la clase la función llamada `__init__`, se ejecuta automáticamente.\n", "* La función `__call__` permite usar el objeto directamente como función, sin hacer referencia al método, que por supuesto es `__call__`\n", "\n", "Hay muchos otros métodos especiales, que comienzan con un `__`.... Usar `` a continuación para ver algunos" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "hn9gQUX1biqt", "outputId": "6cd28c8a-3347-401e-f690-2ebbd097e116" }, "outputs": [ { "ename": "AttributeError", "evalue": "type object 'veterinaria' has no attribute '__'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_664677/3273899342.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mveterinaria\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: type object 'veterinaria' has no attribute '__'" ] } ], "source": [ "veterinaria.__" ] }, { "cell_type": "markdown", "metadata": { "id": "u2c3srDbsH5B" }, "source": [ "Para utilizar la clase, primero se debe incializar como un objeto. Crear la instancia de la clase. \n", "\n", "__Ejemplo__: Crea la instancia `mascotafeliz`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "mTv7uV_JsdfA" }, "outputs": [], "source": [ "mascotafeliz=veterinaria('perro')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "bAibu-Zqch28", "outputId": "2bf3d9d9-8e05-4adf-f671-e95ecbe5c521" }, "outputs": [ { "data": { "text/plain": [ "'guau'" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mascotafeliz.sonido" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "IMabkap3KDy6", "outputId": "765c6eb9-ad11-4426-b06a-4d4c17b12f9d" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "guau\n" ] } ], "source": [ "mascotafeliz('greco')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "fI050nt2KDy8", "outputId": "7ae2a431-2c8e-46e9-e893-10b666807400" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "blanco\n" ] } ], "source": [ "mascotafeliz.color('greco')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "bv6hxO6ZKDy_" }, "outputs": [], "source": [ "mascotafeliz.tipo.get('vaca')" ] }, { "cell_type": "markdown", "metadata": { "id": "jdDzkn7xtym3" }, "source": [ "## Herencia" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "SKRtANy3KDzB" }, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "G-ZiUnyhKDzD" }, "outputs": [], "source": [ "class finanzas(pd.DataFrame):\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "mKLdQljeKDzF" }, "outputs": [], "source": [ "f=finanzas()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "NLCKASi_KDzH", "outputId": "325a1f23-b84e-4f5c-dc12-4f632321b022" }, "outputs": [ { "data": { "text/plain": [ "__main__.finanzas" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(f)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 169 }, "id": "jh5uAuzsuF7E", "outputId": "106dd6fa-b6ba-4252-abae-1b06e894e932" }, "outputs": [ { "ename": "TypeError", "evalue": "'finanzas' object is not callable", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_664677/2358335894.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m{\u001b[0m\u001b[0;34m'A'\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'finanzas' object is not callable" ] } ], "source": [ "f([{'A':1}])" ] }, { "cell_type": "markdown", "metadata": { "id": "5tQgeF-JuM90" }, "source": [ "Para realmente heradar hay que inicializarlo de forma especial con la función `super`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "skIsHdKTKDzK" }, "outputs": [], "source": [ "class hkdict(dict):\n", " def __init__(self,*args, **kwargs):\n", " super(hkdict, self).__init__(*args, **kwargs)\n", " def has_key(self,k):\n", " return k in self" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "aQoUY0uVch2-" }, "outputs": [], "source": [ "d=dict()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "D9_Hhryuch2-" }, "outputs": [], "source": [ "d['perro']='guau'\n", "d['gato']='miau'" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "sHbqFYR4ch2_" }, "outputs": [], "source": [ "d.get('vaca')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 169 }, "id": "eZiyNKC5ugl0", "outputId": "e5b2a0a8-e1ea-4f53-8321-8638534e9e3b" }, "outputs": [ { "ename": "AttributeError", "evalue": "'dict' object has no attribute 'has_key'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_664677/1012315857.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0md\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhas_key\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'gato'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mAttributeError\u001b[0m: 'dict' object has no attribute 'has_key'" ] } ], "source": [ "d.has_key('gato')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "cGARhEXQKDzO" }, "outputs": [], "source": [ "dd=hkdict()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "UE1GRz_ach2_" }, "outputs": [], "source": [ "dd['perro']='guau'\n", "dd['gato']='miau'" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 34 }, "id": "CsQkLGMBKDzP", "outputId": "c31fec66-096e-4ee8-8338-d0db8235234a" }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 132, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dd.has_key('vaca')" ] }, { "cell_type": "markdown", "metadata": { "id": "-hmU3is6ch3A" }, "source": [ "## Implementation of [arXiv:1905.13729](https://arxiv.org/abs/1905.13729) \n", "See also: DOI: [10.1103/PhysRevD.101.095032](http://doi.org/10.1103/PhysRevD.101.095032)\n", "\n", "Repo: https://github.com/restrepo/anomalies\n", "### General solution to the U(1) anomaly equations\n", "Let a vector $\\boldsymbol{z}$ with $N$ integer entries such that\n", "$$ \\sum_{i=1}^N z_i=0\\,,\\qquad \\sum_{i=1}^N z_i^3=0\\,.$$\n", "We like to build this set of of $N$ from two subsets $\\boldsymbol{\\ell}$ and $\\boldsymbol{k}$ with sizes\n", "\n", "\\begin{align}\n", "\\operatorname{dim}(\\boldsymbol{\\ell})=&\n", "\\begin{cases}\n", "\\alpha=\\frac{N}{2}-1\\,, & \\text{ if $N$ even } \\\\\n", "\\beta=\\frac{N-3}{2}\\,, & \\text{ if $N$ odd }\\\\\n", "\\end{cases};&\n", "\\operatorname{dim}(\\boldsymbol{k})=&\n", "\\begin{cases}\n", "\\alpha=\\frac{N}{2}-1\\,, & \\text{ if $N$ even } \\\\\n", "\\beta+1=\\frac{N-1}{2}\\,, & \\text{ if $N$ odd }\\\\\n", "\\end{cases};\n", "\\end{align}\n", "\n", "* $N$ even: Consider the following two examples of $\\boldsymbol{z}$ with vector-like solutions, i.e, with opposite integeres which automatically satisfy the equations \n", "\\begin{align}\n", "\\boldsymbol{x}=&\\left(\\ell_{1}, {k}_{1}, \\ldots, k_{\\alpha},-\\ell_{1},-k_{1}, \\ldots,-k_{\\alpha}\\right)\\\\\n", "\\boldsymbol{y}=&\\left(0,0,\\ell_{1}, \\ldots, \\ell_{\\alpha},-\\ell_1, \\ldots,-\\ell_{\\alpha}\\right)\\,.\n", "\\end{align}\n", "* $N$ odd: Consider the two vector-like solutions\n", "\\begin{align}\n", "\\begin{array}\n", "\\boldsymbol{x}=&\\left(0, k_{1}, \\ldots, k_{\\beta+1},-k_{1}, \\ldots,-k_{\\beta+1}\\right) \\\\\n", "\\boldsymbol{y}=&\\left(\\ell_{1}, \\ldots, \\ell_{\\beta}, k_{1}, 0,-\\ell_{1}, \\ldots,-\\ell_{\\beta},-k_{1}\\right)\n", "\\end{array}\n", "\\end{align}\n", "\n", "From any of this, we can build a final $\\boldsymbol{z}$ which can includes _chiral_ solutions, i.e, non vector-like solutions\n", "\n", "$$\n", "\\boldsymbol{x} \\oplus \\boldsymbol{y} \\equiv\\left(\\sum_{i=1}^{N} x_{i} y_{i}^{2}\\right)\\boldsymbol{x}-\\left(\\sum_{i=1}^{N} x_{i}^{2} y_{i}\\right)\\boldsymbol{y}\\,.\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "QZcu6wNkch3A" }, "outputs": [], "source": [ "import numpy as np\n", "class free(list):\n", " def __init__(self,*args, **kwargs):\n", " '''\n", " Convert list to anomaly free solution\n", " '''\n", " assert np.array(args).sum()==0\n", " assert (np.array(args)**3).sum()==0 \n", " super(free, self).__init__(*args, **kwargs)\n", " def __add__(self, other):\n", " '''\n", " Add to anomaly free solutions to obtain \n", " a new anomaly free solutions which is not\n", " necessarily vector-like\n", " '''\n", " x=np.array(self)\n", " y=np.array(other)\n", " return free((x*y**2).sum()*x-(x**2*y).sum()*y)\n", " \n", "def _z(l,k,sort=True,reverse=False):\n", " '''\n", " Implementation of arXiv:1905.13729\n", " For l,k two set of same dimensions (or k with an extra dimension)\n", " return a builded array z, such that\n", " sum( z )=0\n", " sum( z**3)=0\n", " '''\n", " l=list(l)\n", " k=list(k)\n", " #Build vector-like solutions x,y\n", " if len(l)==len(k) :\n", " x=free( [l[0]]+k+[-l[0]]+[-i for i in k ] )\n", " y=free( [0,0] +l +[-i for i in l ] )\n", " else:\n", " x=free( [0]+k+[-i for i in k ] )\n", " y=free( l+[k[0]]+[0]+[-i for i in l ]+[-k[0]])\n", " xfac=0\n", " yfac=0\n", " ## Build not trivial solution\n", " zz=x+y\n", " if sort:\n", " zz=sorted( zz ,key=abs, reverse=reverse ) \n", " return zz\n", "class solution(free):\n", " def __init__(self,l,k,sort=True,reverse=False,**kwargs):\n", " zz=_z(l,k,sort=sort,reverse=reverse)\n", " self.gcd=np.gcd.reduce(zz)\n", " self.simplified=free((zz/self.gcd).astype(int))\n", " super(solution, self).__init__(zz, **kwargs)\n", " def asarray(self):\n", " self.simplified=np.asarray(self.simplified)\n", " return np.asarray(self)\n", " def to_list(self):\n", " self.simplified=list(self.simplified)\n", " return list(self)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qkn7YBsech3A", "outputId": "6359309b-5bea-4719-c17a-e771d2f603b3" }, "outputs": [ { "data": { "text/plain": [ "[-1, 4, -2, 1, -4, 2]" ] }, "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ "free([-1, 4, -2, 1, -4, 2])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "sKQRQQ1qch3B", "outputId": "df87962d-3453-47a4-9b67-20ff0e7ea5ed" }, "outputs": [ { "data": { "text/plain": [ "__main__.solution" ] }, "execution_count": 141, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x=solution([-1,1],[4,-2])\n", "type(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "_RCKh8qych3B", "outputId": "25cf1f30-64f0-4864-ec54-d9edfcc37f30" }, "outputs": [ { "data": { "text/plain": [ "[3, 3, 3, -12, -12, 15]" ] }, "execution_count": 143, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "B9s5rO3pch3B", "outputId": "00071fb0-7112-46f4-a23b-b65e61b6d6ff" }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 144, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.gcd" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "I3FnfiJQch3B", "outputId": "415bb51c-255e-4192-fbf0-04fbcce4bb98" }, "outputs": [ { "data": { "text/plain": [ "[1, 1, 1, -4, -4, 5]" ] }, "execution_count": 145, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.simplified" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "NlPzmg-Hch3C", "outputId": "6ad20f8e-abcb-47ee-bfbb-af8c52409e99" }, "outputs": [ { "data": { "text/plain": [ "__main__.free" ] }, "execution_count": 140, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(x.simplified)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "LDPYO9Juch3C", "outputId": "0234f844-0464-4b66-8d7d-0191c20f49cb" }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 149, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(np.asarray(x.simplified)**3).sum()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "55sPmbQYch3C", "outputId": "0151db50-87a9-4b54-e06e-d53b3a0783cc" }, "outputs": [ { "data": { "text/plain": [ "array([ 3, 3, 3, -12, -12, 15])" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.asarray()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "udLnbDKlch3C", "outputId": "c42b493e-e02c-4d81-e59d-8b4f8dab8ba1" }, "outputs": [ { "data": { "text/plain": [ "[3, 3, 3, -12, -12, 15]" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x.to_list()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "H-mjB6obch3C", "outputId": "7522c80b-6547-4689-b74c-c3b44f19eeeb" }, "outputs": [ { "data": { "text/plain": [ "[-5, 5, -20, 20, 25, -25]" ] }, "execution_count": 130, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y=solution([1,1],[4,-2])\n", "y" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ODJAqaIich3D", "outputId": "7c291639-8b85-49a8-e764-0b46042a480f" }, "outputs": [ { "data": { "text/plain": [ "[1, 1, 1, -4, -4, 5, -1, 1, -4, 4, 5, -5]" ] }, "execution_count": 131, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z=x.simplified+y.simplified\n", "z" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "paIJHJDEch3D", "outputId": "3a4eaac1-19a0-40ca-aa33-04e54d0437bb" }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 132, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.asarray(z).sum()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "nPUIB8HGch3D", "outputId": "4d823eb1-4b74-4e8f-d7b6-a862c18a9524" }, "outputs": [ { "data": { "text/plain": [ "0" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(np.asarray(z)**3).sum()" ] }, { "cell_type": "markdown", "metadata": { "id": "UxNY3JWNch3D" }, "source": [ "### Python implmentation\n", "Obtain a numpy array `z` of `N` integers which satisfy the Diophantine equations\n", "```python\n", ">>> z.sum()\n", "0\n", ">>> (z**3).sum()\n", "0\n", "```\n", "The input is two lists `l` and `k` with any `(N-3)/2` and `(N-1)/2` integers for `N` odd, or `N/2-1` and `N/2-1` for `N` even (`N>4`).\n", "The function is implemented below under the name: `free(l,k)`\n", "\n", "\"Open" ] }, { "cell_type": "markdown", "metadata": { "id": "hRBjvZ8Zch3E" }, "source": [ "https://stackoverflow.com/a/43793179/2268280" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "8TdO91Dxch3E" }, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "from astropy.table import Table\n", "import itertools\n", "import sys\n", "import os\n", "from functools import reduce\n", "import warnings\n", "warnings.filterwarnings(\"ignore\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "y1Yx2EPCch3E" }, "outputs": [], "source": [ "!pip install anomalies 2>/dev/null > /dev/null" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "BKLnjEUGch3E" }, "outputs": [], "source": [ "from anomalies import anomaly" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "zGVjp00zch3E", "outputId": "496bc573-8fbc-4734-89a8-6ac0b4fa24fe" }, "outputs": [ { "data": { "text/plain": [ "array([ 3, 3, 3, -12, -12, 15])" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "anomaly.free([-1,1],[4,-2])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "W-hq1leZch3F", "outputId": "d00d9280-1b8f-47e4-e8eb-00ad99f45d42" }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "anomaly.free.gcd" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "VHqjx4Ftch3F", "outputId": "5fc8a9bf-e2d5-4a8e-e1b0-58461a563120" }, "outputs": [ { "data": { "text/plain": [ "array([ 1, 1, 1, -4, -4, 5])" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "anomaly.free.simplified" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "uhmP7fzjch3F" }, "outputs": [], "source": [ "z=anomaly.free" ] }, { "cell_type": "markdown", "metadata": { "id": "Ch88lXOsch3F" }, "source": [ "### Analysis\n", "`solutions` class → Initialize the object to obtain anomaly free solutions for any set of `N` integers" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "zocMw7K_ch3F" }, "outputs": [], "source": [ "#TODO: inherit from free class\n", "import sys\n", "def _get_chiral(q,q_max=np.inf):\n", " #Normalize to positive minimum\n", " if q[0]<0 or (q[0]==0 and q[1]<0):\n", " q=-q\n", " #Divide by GCD\n", " GCD=np.gcd.reduce(q)\n", " q=(q/GCD).astype(int)\n", " if ( #not 0 in z and \n", " 0 not in [ sum(p) for p in itertools.permutations(q, 2) ] and #avoid vector-like and multiple 0's\n", " #q.size > np.unique(q).size and ## check for at least a duplicated entry\n", " np.abs(q).max()<=q_max\n", " ):\n", " return q,GCD\n", " else:\n", " return None,None\n", "class solutions(object):\n", " '''\n", " Obtain anomaly free solutions with N chiral fields\n", " \n", " Call the initialize object with N and get the solutions:\n", " Example:\n", " >>> s=solutions()\n", " >>> s(6) ## N = 6\n", " \n", " Redefine the self.chiral function to implement further restrictions:\n", " inherit from this class and define the new chiral function\n", " '''\n", " def __init__(self,nmin=-2,nmax=2,zmax=np.inf):\n", " self.nmin=nmin\n", " self.nmax=nmax\n", " self.zmax=zmax\n", " self.CALL=False\n", "\n", " def __call__(self,N,*args,**kwargs):\n", " self.CALL=True\n", " if N%2!=0: #odd\n", " N_l=(N-3)//2\n", " N_k=(N-1)//2\n", " else: #even\n", " N_l=N//2-1\n", " N_k=N_l\n", " r=range(self.nmin,self.nmax+1)\n", " self.ls=list(itertools.product( *(r for i in range(N_l)) ))\n", " self.ks=list(itertools.product( *(r for i in range(N_k)) ))\n", " return self.chiral(*args,**kwargs)\n", " \n", " \n", " def chiral(self,*args,**kwargs):\n", " if not self.CALL:\n", " sys.exit('Call the initialized object first:\\n>>> s=solutions()\\n>>> self(5)')\n", " self.list=[]\n", " solt=[]\n", " for l in self.ls:\n", " for k in self.ks:\n", " l=list(l)\n", " k=list(k)\n", " q,gcd=_get_chiral( z(l,k) )\n", " #print(z(l,k))\n", " if q is not None and list(q) not in self.list and list(-q) not in self.list:\n", " self.list.append(list(q))\n", " solt.append({'l':l,'k':k,'z':list(q),'gcd':gcd})\n", " return solt" ] }, { "cell_type": "markdown", "metadata": { "id": "K97-EAo1ch3G" }, "source": [ "Chiral solutions for l and k in the range [-2,2]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "gJ_SAj4sch3G" }, "outputs": [], "source": [ "s=solutions()" ] }, { "cell_type": "markdown", "metadata": { "id": "ujIPOtIKch3G" }, "source": [ "solutions for $N=5$ integers" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "EKxL5HdGch3G", "outputId": "7de9d5d4-71c1-479e-a8c8-85f656cae972" }, "outputs": [ { "data": { "text/plain": [ "[{'l': [-2], 'k': [-1, 2], 'z': [2, 4, -7, -9, 10], 'gcd': 1},\n", " {'l': [-2], 'k': [2, -1], 'z': [1, 5, -7, -8, 9], 'gcd': 4}]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s(5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ECQ4HBdKch3H", "outputId": "11a542e5-e4f1-41f5-b7e0-9f19f6f9dc5f" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
lkzgcd
0[-2][-1, 2][2, 4, -7, -9, 10]1
1[-2][2, -1][1, 5, -7, -8, 9]4
\n", "
" ], "text/plain": [ " l k z gcd\n", "0 [-2] [-1, 2] [2, 4, -7, -9, 10] 1\n", "1 [-2] [2, -1] [1, 5, -7, -8, 9] 4" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame( s(5) )" ] }, { "cell_type": "markdown", "metadata": { "id": "65RBFTr4ch3H" }, "source": [ "To filter solutions with duplicate or triplicate integers, let us create a class `dark` that inherits from `solutions`. Therefore, in the argument of the new class is the old class instead of just `object`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "utbx-MXLch3H" }, "outputs": [], "source": [ "class dark(solutions):\n", " '''\n", " Modify the self.chiral function to obtain solutions\n", " with either duplicate or triplicate integers\n", " '''\n", " def chiral(self,X=False,verbose=False,print_step=100000):\n", " m=2\n", " if X:\n", " m=3\n", " self.list=[]\n", " solt=[]\n", " tot=len(self.ls)*len(self.ks)\n", " i=0\n", " for l in self.ls:\n", " for k in self.ks:\n", " if verbose:\n", " i=i+1\n", " if i%print_step==0:\n", " print('{}/{}'.format(i,tot))\n", " l=list(l)\n", " k=list(k)\n", " q,gcd=_get_chiral( z(l,k) )\n", " #print(z(l,k))\n", " if (q is not None and \n", " list(q) not in self.list and list(-q) not in self.list and\n", " 1 in [ len(set(p)) for p in itertools.permutations(q, m) ] and\n", " #q.size-np.unique(q).size>m\n", " np.abs(q).max()<=self.zmax\n", " ):\n", " self.list.append(list(q))\n", " solt.append({'l':l,'k':k,'z':list(q),'gcd':gcd})\n", " return solt " ] }, { "cell_type": "markdown", "metadata": { "id": "xl6ub9uCch3H" }, "source": [ "Chiral solutions with repeated integers" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ozq0Ielnch3H" }, "outputs": [], "source": [ "s=dark()" ] }, { "cell_type": "markdown", "metadata": { "id": "2PbDZpkPch3I" }, "source": [ "Example: Force solutions with triplicate integers" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "haV-qxm9ch3I", "outputId": "8e92d111-99cd-464f-b538-99f454c3ec4b" }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s(5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "nz_jH29Sch3I", "outputId": "a83ce898-4fa1-4d01-c83d-dc70169d0247" }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
lkzgcd
0[-2, 2][-2, -1][1, 1, 1, -4, -4, 5]8
\n", "
" ], "text/plain": [ " l k z gcd\n", "0 [-2, 2] [-2, -1] [1, 1, 1, -4, -4, 5] 8" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame( s(6,X=True) )" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ZNe0VM7sch3I", "outputId": "92482d26-e1e5-4f2e-8ad2-6750378cf0c3" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 16.5 s, sys: 7.15 ms, total: 16.5 s\n", "Wall time: 16.6 s\n" ] }, { "data": { "text/plain": [ "[]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "s=dark(nmin=-30,nmax=30)\n", "s(5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "2_CjjOKZch3J", "outputId": "b662922a-5c9c-45d8-b534-828cecb39675" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "100000/194481\n", "CPU times: user 19.9 s, sys: 0 ns, total: 19.9 s\n", "Wall time: 19.9 s\n" ] }, { "data": { "text/plain": [ "[{'l': [-10, 5], 'k': [-2, 4], 'z': [1, 1, 1, -4, -4, 5], 'gcd': 1500},\n", " {'l': [-10, 5], 'k': [3, 4], 'z': [3, 3, 3, -10, -17, 18], 'gcd': 250}]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "s=dark(nmin=-10,nmax=10,zmax=32)\n", "s(6,X=True,verbose=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "2bwAZhcuch3J", "outputId": "bbbdc1da-3d77-417d-a416-f0901cfc38b4" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "500000/3418801\n", "1000000/3418801\n", "1500000/3418801\n", "2000000/3418801\n", "2500000/3418801\n", "3000000/3418801\n", "CPU times: user 4min 20s, sys: 27.1 ms, total: 4min 20s\n", "Wall time: 4min 20s\n" ] } ], "source": [ "%%time\n", "s=dark(nmin=-21,nmax=21,zmax=32)\n", "slt=s(6,verbose=True,print_step=500000)" ] }, { "cell_type": "markdown", "metadata": { "id": "o0M5XpiEch3J" }, "source": [ "### Example\n", "Simple csv to json converter" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "RCnv0lOKch3J" }, "outputs": [], "source": [ "import csv as CSV\n", "class read_csv:\n", " def __init__(self,f):\n", " self.data=[]\n", " f=open(f,'r')\n", " dt=CSV.reader(f)\n", " for row in dt:\n", " self.data.append(row)\n", " f.close()\n", " def to_json(self):\n", " return [dict(zip(data[0],d)) for d in self.data[1:]]" ] }, { "cell_type": "markdown", "metadata": { "id": "kmL4fx8fch3J" }, "source": [ "## Decorating classes\n", "From https://realpython.com/primer-on-python-decorators/#decorating-classes\n", "> Some commonly used decorators that are even built-ins in Python are `@classmethod`, `@staticmethod`, and `@property`. The `@classmethod` and `@staticmethod` decorators are used to define methods inside a class namespace that are not connected to a particular instance of that class. The `@property` decorator is used to customize getters and setters for class attributes." ] }, { "cell_type": "markdown", "metadata": { "id": "RqyqrVmhKDza" }, "source": [ "## References\n", "[1] [A Guide to Python's Magic Methods](https://rszalski.github.io/magicmethods/)\n", "\n", "[2] https://realpython.com/python3-object-oriented-programming/\n", "\n", "[3] [Building Skills in Object-Oriented Design](https://drive.google.com/file/d/0BxoOXsn2EUNIWkt5Ni1vV2E4QlU/view?usp=sharing)\n", "\n", "[4] Ver también: https://gist.github.com/mcleonard/5351452\n", "\n", "[5] Bhasin, Harsh. Python Basics: A Self-teaching Introduction. Stylus Publishing, LLC, 2018. [[PDF]](https://drive.google.com/file/d/1DNXeb5UmcL_rNl6lHFbmmRT5jodtNoc0/view?usp=sharing) [[Google Scholar]](https://scholar.google.co.in/scholar_lookup?title=Python+Basics:+A+Self-teaching-Introduction&auhtor=H+Bhasin)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "IDTxbjE4ch3K" }, "outputs": [], "source": [] } ], "metadata": { "colab": { "include_colab_link": true, "name": "Intro_clases.ipynb", "provenance": [] }, "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.9.2" } }, "nbformat": 4, "nbformat_minor": 4 }