{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "mYUHfIa3Nd9L", "slideshow": { "slide_type": "slide" } }, "source": [ "# Python Avanzado\n", "El nombre mas pretencioso que escucharan hoy\n", "\n", "Juan-Pablo Silva
\n", "jpsilva@dcc.uchile.cl" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" }, "toc": true }, "source": [ "

Contenidos

\n", "
" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "bl-a8iBxNfeB", "slideshow": { "slide_type": "slide" } }, "source": [ "## Conceptos Generales" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "gcaAX0HMNfYf", "slideshow": { "slide_type": "subslide" } }, "source": [ "### \\*args y \\*\\*kwargs\n", "\n", "- Unpacking\n", "- Permiten un numero arbitrario de argumentos\n", "- Filtrar argumentos con \\*\\*kwargs" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Unpacking" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lista = [1, 2, 3, 4]\n", "\n", "a1, a2, a3, a4 = lista\n", "print(a2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "print(lista)\n", "print(*lista)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Mas general" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def f1(*args):\n", " print(args)\n", " print(*args)\n", "\n", "def f2(**kwargs):\n", " print(kwargs)\n", " print(*kwargs)\n", " print(\", \".join([\"{}={}\".format(k,v) for k,v in kwargs.items()]))\n", "\n", "def f3(*args, **kwargs):\n", " print(args, kwargs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"-----F1------\")\n", "f1(1,2,3,4,5)\n", "print(\"-----F2------\")\n", "f2(a=10, b=20, c=30)\n", "print(\"-----F3------\")\n", "f3(1,2,4, a=20, r=10, s=\"un String\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Unir diccionarios\n", "\n", "- usamos \\*\\*kwargs" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = {\n", " \"a\":10,\n", " \"b\":20\n", "}\n", "\n", "b = {\n", " \"b\":100,\n", " \"c\":200\n", "}\n", "\n", "print(a)\n", "print(b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "c = {**a, **b}\n", "print(c)\n", "d = {**b, **a}\n", "print(d)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "xaB5jH9YNfcU", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Forzar _keyword_\n", "\n", "- funciones/metodos con argumentos opcionales\n", "- prevenir equivocaciones" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Aceptamos de _todo_" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def f1(a1, a2, *args, k1=10, k2=20, **kwargs):\n", " print(f\"a1={a1}, a2={a2}\")\n", " print(f\"args: {args}\")\n", " print(f\"k1={k1}\")\n", " print(f\"k2={k2}\")\n", " print(f\"kwargs: {kwargs}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f1(1, 2, 3, k1=20, k2=30, a=100, b=200)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Ahora sin \\*args" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def f1(a1, a2, k1=10, k2=20, **kwargs):\n", " print(f\"a1={a1}, a2={a2}\")\n", " print(f\"k1={k1}\")\n", " print(f\"k2={k2}\")\n", " print(f\"kwargs: {kwargs}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f1(1, 2, 3, k1=20, k2=30, a=100, b=200)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Por que pasa esto" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f1(a1, a2, k1=10, k2=20):\n", " print(f\"a1={a1}, a2={a2}\")\n", " print(f\"k1={k1}\")\n", " print(f\"k2={k2}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f1(1, 2, 3, 4)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "La solucion: \\*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f1(a1, a2, *, k1=10, k2=20):\n", " print(f\"a1={a1}, a2={a2}\")\n", " print(f\"k1={k1}\")\n", " print(f\"k2={k2}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "try:\n", " f1(1,2,3,4)\n", "except TypeError as e:\n", " print(e)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "f1(1, 2, k1=3, k2=4)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "4YvJVuYjNfVr", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Switch-case\n", "\n", "- No existen\n", "- Hay que arreglarselas" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Usando un diccionario es lo mas simple" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def switcher(value):\n", " options = {\n", " \"val1\": 1,\n", " \"val2\": 2,\n", " \"val3\": 3,\n", " \"val4\": 4,\n", " }\n", " if value not in options:\n", " raise ValueError()\n", " return options[value]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(switcher(\"val3\"))\n", "print(switcher(\"val1\"))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Podemos guardar funciones adentro tambien" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f1(): return 1\n", "def f2(): return 2\n", "def f3(): return 3\n", "def f4(): return 4\n", "\n", "def switcher(value):\n", " options = {\n", " \"val1\": f1,\n", " \"val2\": f2,\n", " \"val3\": f3,\n", " \"val4\": f4,\n", " }\n", " if value not in options:\n", " raise ValueError()\n", " return options[value]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(switcher(\"val3\")()) # <-- notar el ()\n", "print(switcher(\"val1\")()) # <-- notar el ()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "y5B-R7sBNfS9", "slideshow": { "slide_type": "subslide" } }, "source": [ "### `global`\n", "\n", "- cuando algo que funcionaba ya no funciona" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Esto funciona lo mas bien" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f(a):\n", " print(a)\n", " print(b)\n", "\n", "f(10)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Era broma, ahora si" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = 20\n", "\n", "def f(a):\n", " print(a)\n", " print(b)\n", "\n", "f(10)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Peeero ahora ya no funciona" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = 20\n", "\n", "def f(a):\n", " print(a)\n", " print(b)\n", " b = 100\n", "\n", "f(10)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "??????????????????????" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Sucede que tenemos que definir que `b` es una variable global si vamos a asignarla" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = 20\n", "\n", "def f(a):\n", " global b\n", " print(a)\n", " print(b)\n", " b = 100\n", "\n", "f(10)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Pero por que?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f\n", "\n", "b = 20" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f(a):\n", " print(locals())\n", " \n", "f(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f(a):\n", " import __main__\n", " print(locals())\n", " print(\"b in __main__?\", \"b\" in vars(__main__))\n", " __main__.b = 100\n", " \n", "f(10)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "3dkKqmJtNfQh", "slideshow": { "slide_type": "subslide" } }, "source": [ "### `nonlocal`\n", "- cuando deberias estar usando una clase" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Calculemos el _\"running average\"_" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def average():\n", " lista = []\n", " def running_avg(value):\n", " lista.append(value)\n", " s = sum(lista)\n", " return float(s)/len(lista)\n", "\n", " return running_avg\n", "\n", "avg = average()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(avg(1))\n", "print(avg(5))\n", "print(avg(10))\n", "print(avg(3))\n", "print(avg(50))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Como funciona esto?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Como funciona esto?\n", "\n", "- Free variables" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(avg.__code__.co_freevars)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "print(avg.__closure__)\n", "print(avg.__closure__[0].cell_contents)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Igual es ineficiente guardar todo el rato la lista..." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def average():\n", " suma = 0.\n", " lista = 0\n", " def running_avg(value):\n", " lista += 1\n", " suma += value\n", " return suma/lista\n", "\n", " return running_avg\n", "\n", "avg = average()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "avg(10)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Nos lo echamos otra vez..." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Tenemos que usar `nonlocal`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def average():\n", " suma = 0.\n", " lista = 0\n", " def running_avg(value):\n", " nonlocal suma, lista\n", " lista += 1\n", " suma += value\n", " return suma/lista\n", "\n", " return running_avg\n", "\n", "avg = average()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(avg(1))\n", "print(avg(5))\n", "print(avg(10))\n", "print(avg(3))\n", "print(avg(50))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(avg.__code__.co_freevars)\n", "print(avg.__closure__)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "oS-bhwTXPDxA", "slideshow": { "slide_type": "subslide" } }, "source": [ "### `@classmethod`\n", "\n", "- Metodos asociados a una clase\n", "- Distinto a un metodo estatico" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "def m_clase(cls): pass\n", "def m_static(): pass\n", "def m_instance(self): pass" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "- Metodos de instancia: reciben `self` como argumento en la primera posicion. Reciben la instancia\n", "- Metodos de clase: reciben `cls` como argumento en la primera posicion. Reciben la clase\n", "- Metodos estaticos: no reciben algo obligados en la primera posicion. **NO** tienen acceso ni a la clase ni la instancia" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Un ejemplo" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " def __init__(self, var1, var2):\n", " self.var1 = var1\n", " self.var2 = var2\n", " \n", " def instance_method(self, *args):\n", " print(self)\n", " return self\n", "\n", " @classmethod\n", " def class_method(cls, *args):\n", " print(cls)\n", " return cls(*args)\n", "\n", " @staticmethod\n", " def static_method(*args):\n", " return A(*args)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A(1,2)\n", "\n", "a.instance_method(1, 2)\n", "print(a.class_method(1, 2))\n", "print(a.static_method(1, 2))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "La diferencia entonces" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class B(A): pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = B(1,2)\n", "\n", "b.instance_method(1, 2)\n", "print(b.class_method(1, 2))\n", "print(b.static_method(1, 2))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Usos reales\n", "\n", "- `dict.fromkeys(iterable, default_value)`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "d_1 = {\n", " \"a\": 0,\n", " \"b\": 0,\n", " \"c\": 0,\n", " \"d\": 0,\n", " \"e\": 0,\n", "}\n", "\n", "print(d_1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "d_2 = dict.fromkeys(\"abcde\", 0)\n", "\n", "print(d_2) " ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "2t4bJUBuNeyy", "slideshow": { "slide_type": "slide" } }, "source": [ "## Modificaciones en _Runtime_\n", "\n", "- Podemos agregar variables y metodos en tiempo de ejecucion\n", "- Todo es un bloque ejecutable en Python\n", "- Podemos acceder a virtualmente todo desde `__dict__`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "i7ynChWXO5A7", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Agregar variables" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " pass " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A()\n", "\n", "try:\n", " a.variable\n", "except AttributeError as e:\n", " print(e)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "a.variable = 150\n", "print(a.variable)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "bEhm0oEPO8AW", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Agregar funciones" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " pass\n", "\n", "def f():\n", " print(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A()\n", "\n", "try:\n", " a.f()\n", "except AttributeError as e:\n", " print(e)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "a.f = f\n", "a.f()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "p46XH6ilO96c", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Agregar metodos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " pass\n", "\n", "def f(self):\n", " print(self)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A()\n", "a.f = f\n", "\n", "try:\n", " a.f()\n", "except TypeError as e:\n", " print(e)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "a.f(100)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "La buena forma" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "import types\n", "a.f = types.MethodType(f, a)\n", "a.f()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "nVSYTbc0NfNs", "slideshow": { "slide_type": "slide" } }, "source": [ "## Decoradores\n", "\n", "- Azucar sintactica a aplicacion de funciones\n", "- Recordar que funciones en Python son de primer orden\n", "- Funciones recibiendo funcion de argumento y retornando funciones" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Motivacion" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def print_function_name(function):\n", " print(function.__name__)\n", " return function\n", "\n", "def f():\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f = print_function_name(f)\n", "f()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Funciona una pura vez" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def print_function_name(function):\n", " def wrapper():\n", " print(function.__name__)\n", " return function\n", " return wrapper\n", "\n", "def f():\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f = print_function_name(f)\n", "f()\n", "f()\n", "f()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "El decorador" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "@print_function_name\n", "def mi_super_funcion():\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mi_super_funcion()\n", "mi_super_funcion()\n", "mi_super_funcion()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "JaliFg4bNfK5", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Decoradores Simples\n", "\n", "- Como recibir argumentos\n", "- Como mantener documentacion\n", "- Decorador con argumentos\n", "- Soportar argumentos de decorador, funcion y flexibilidad" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- Como recibir argumentos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def print_args(func):\n", " def wrapper(a):\n", " print(func.__name__, a)\n", " return func(a)\n", " return wrapper\n", "\n", "@print_args\n", "def my_name(a):\n", " return a" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "my_name(100)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "La buena forma" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def print_args(func):\n", " def wrapper(*args, **kwargs):\n", " print(func.__name__, args, kwargs)\n", " return func(*args, **kwargs)\n", " return wrapper\n", "\n", "@print_args\n", "def my_name(a):\n", " return a\n", "\n", "my_name(100)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- Como mantener documentacion" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import functools" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def print_args(func):\n", " #################\n", " @functools.wraps(func)\n", " #################\n", " def wrapper(*args, **kwargs):\n", " print(func.__name__, args, kwargs)\n", " return func(*args, **kwargs)\n", " return wrapper" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- Decorador con argumentos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def caller(num=10):\n", " def inner_decorator(func):\n", " print(f\"Inside inner_decorator with func: {func.__name__}\")\n", " @functools.wraps(func)\n", " def decorator(*args, **kwargs):\n", " print(f\"Inside decorator with args: {args} {kwargs}\")\n", " return func(*args, **kwargs)\n", " return decorator\n", "\n", " print(f\"Inside caller with arg: {num}\")\n", " return inner_decorator\n", "\n", "@caller(num=100)\n", "def f(arg1, arg2):\n", " print(arg1, arg2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f(1,2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- Soportar argumentos de decorador, funcion y flexibilidad" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def caller(_func=None, *, num=10):\n", " def inner_decorator(func):\n", " print(f\"Inside inner_decorator with func: {func.__name__}\")\n", " @functools.wraps(func)\n", " def decorator(*args, **kwargs):\n", " print(f\"Inside decorator with args: {args} {kwargs}\")\n", " return func(*args, **kwargs)\n", " return decorator\n", " \n", " #########################\n", " if _func is None:\n", " print(f\"With arguments: {num}\")\n", " return inner_decorator\n", " else:\n", " print(f\"No arguments, falling to default decorator\")\n", " return inner_decorator(_func)\n", " \n", "print(\"F1------\")\n", "@caller(num=100)\n", "def f1(arg1, arg2):\n", " print(arg1, arg2)\n", "\n", "print(\"F2------\")\n", "@caller\n", "def f2(a,b,arg1=3, arg2=5):\n", " print(a, b, arg1, arg2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"F1------\")\n", "f1(1,2)\n", "print(\"F2------\")\n", "f2(10,20)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Guardar informacion en funciones\n", "\n", "- Como las funciones tambien son objetos, podemos agregarle variables" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def counter(func):\n", " def wrapper(*args, **kwargs):\n", " wrapper.calls += 1\n", " return func(*args, **kwargs)\n", " \n", " wrapper.calls = 0\n", " return wrapper\n", "\n", "@counter\n", "def fun(a):\n", " print(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(10):\n", " fun(i)\n", " \n", "fun(100)\n", "fun(150)\n", "\n", "print(f\"Num calls: {fun.calls}\")" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "oM5WqBM0NfIS", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Decoradores de clases\n", "\n", "- Tambien podemos decorar clases\n", "- No estamos obligados a retornar cosas distintas siempre\n", "- Podemos recibir la clase, modificarla, y devolverla" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def decorator(cls):\n", " print(cls)\n", " cls.variable1 = 10\n", " # podria ser una funcion con nombre tambien\n", " setattr(cls, \"funcion\", lambda self, x: self.variable1 + x)\n", " return cls\n", "\n", "@decorator\n", "class A: pass\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A()\n", "print(a.variable1)\n", "print(a.funcion(100))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "gZEF3fdYNfFu", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Decoradores como clases\n", "\n", "- Podemos simular una clase como una funcion" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Counter:\n", " def __init__(self, func):\n", " self.calls = 0\n", " self.func = func\n", " functools.update_wrapper(self, func)\n", " def __call__(self, *args, **kwargs):\n", " self.calls += 1\n", " return self.func(*args, **kwargs)\n", " \n", "@Counter\n", "def fun(a):\n", " print(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(10):\n", " fun(i)\n", " \n", "fun(100)\n", "fun(150)\n", "\n", "print(f\"Num calls: {fun.calls}\")" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "zsmDZk8pNe-W", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Ejemplos" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Singleton\n", "\n", "- Tener maximo una instancia de una clase" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def singleton(cls):\n", " @functools.wraps(cls)\n", " def wrapper(*args, **kwargs):\n", " if not wrapper.instance:\n", " wrapper.instance = cls(*args, **kwargs)\n", " return wrapper.instance\n", " wrapper.instance = None\n", " return wrapper\n", "\n", "class A:\n", " pass\n", " \n", "@singleton\n", "class B:\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a1 = A()\n", "a2 = A()\n", "\n", "b1 = B()\n", "b2 = B()\n", "\n", "print(a1 is a2)\n", "print(b1 is b2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Cache\n", "\n", "- Guardar ejecuciones anteriores para no recalcular" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@functools.lru_cache(maxsize=20)\n", "def recursive(num):\n", " print(num)\n", " if num <= 0:\n", " return num\n", " return recursive(num-1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(10):\n", " recursive(i)\n", "\n", "for _ in range(100):\n", " for i in range(4):\n", " recursive(i)\n", "\n", "print(recursive.cache_info())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Mas en https://wiki.python.org/moin/PythonDecoratorLibrary" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "74y00_hDNe7W", "slideshow": { "slide_type": "slide" } }, "source": [ "## Propiedades (`property`)\n", "\n", "- Crear accesores personalizados para variables\n", "- Accesores a composiciones de variables o funciones" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Usando una funcion" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Person:\n", " def __init__(self, name, surname):\n", " self.name = name\n", " self.surname = surname\n", "\n", " def get_full_name(self):\n", " return f\"{self.name} {self.surname}\"\n", "\n", " def set_full_name(self, full_name):\n", " self.name, self.surname = full_name.split()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "person = Person(\"JP\", \"Silva\")\n", "print(person.get_full_name())\n", "\n", "person.set_full_name(\"J-P Silva\")\n", "\n", "print(person.get_full_name())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Pero que lata poner todo el rato `getVAR`, `setVAR`..." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class Person:\n", " def __init__(self, name, surname):\n", " self.name = name\n", " self.surname = surname\n", "\n", " def get_full_name(self):\n", " return f\"{self.name} {self.surname}\"\n", "\n", " def set_full_name(self, full_name):\n", " self.name, self.surname = full_name.split()\n", " \n", " full_name = property(get_full_name, set_full_name)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "person = Person(\"JP\", \"Silva\")\n", "print(person.full_name)\n", "\n", "person.full_name = \"J-P Silva\"\n", "\n", "print(person.full_name)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "NtwSo99ENe4Z", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Como decorador" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "class Person:\n", " def __init__(self, name, surname):\n", " self.name = name\n", " self.surname = surname\n", "\n", " @property\n", " def full_name(self):\n", " return f\"{self.name} {self.surname}\"\n", "\n", " @full_name.setter\n", " def full_name(self, person_name):\n", " self.name, self.surname = person_name.split()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "person = Person(\"JP\", \"Silva\")\n", "print(person.full_name)\n", "\n", "person.full_name = \"J-P Silva\"\n", "\n", "print(person.full_name)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Fu8GrFVfNe1n", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Descriptores\n", "\n", "- Mas flexibles\n", "- Bajo nivel\n", "- Especificos cuando realmente necesitamos algo" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "Descriptores son parecidos, pero mas flexibles, mas a bajo nivel, pero mas dificiles de usar y mas especificos cuando realmente necesitamos algo" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class NumberProxy:\n", " def __init__(self, value):\n", " self.value = value\n", "\n", " def __get__(self, obj, objtype):\n", " return self.value\n", "\n", "class Container:\n", " a = NumberProxy(100)\n", "\n", "c = Container()\n", "c.a" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "e1J025z9Nevi", "slideshow": { "slide_type": "slide" } }, "source": [ "## Dunder methods / Magic Methods\n", "\n", "- _Operator overloading_ es otro nombre\n", "- Son bacanes\n", "- Son utiles\n", "- Usenlos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Implementemos una lista de Anime (such weeb)\n", "\n", "- Una clase `Anime`\n", "- Una clase `AnimeList`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Nivel 1" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Anime" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_id_count = 0\n", "\n", "class Anime:\n", " def __init__(self, name, ranking):\n", " global _id_count\n", " self.id = _id_count\n", " _id_count += 1\n", "\n", " self.name=name\n", " self.ranking = ranking\n", "\n", " def is_higher(self, other_anime):\n", " return self.ranking > other_anime.ranking" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_anime = []\n", "for rank, name in enumerate([\"FMA\", \"Steins;Gate\", \"HxH\", \"Kimi no Na Wa\"]):\n", " all_anime.append(Anime(name=name, ranking=rank))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- AnimeList" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AnimeList:\n", " def __init__(self, anime_list=None):\n", " if anime_list is not None:\n", " self.anime_list = anime_list\n", " else:\n", " self.anime_list = []\n", "\n", " def add_anime(self, anime):\n", " self.anime_list.append(anime)\n", "\n", " def get_all_anime(self):\n", " return self.anime_list\n", "\n", " def get_anime(self, indices):\n", " return self.anime_list[indices]\n", "\n", " def num_anime(self):\n", " return len(self.anime_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "anime_list = AnimeList()\n", "for anime in all_anime[1:]:\n", " anime_list.add_anime(anime)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "print(anime_list.get_all_anime())\n", "print(anime_list.get_anime(2))\n", "print(anime_list.num_anime())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Nivel 2" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Anime\n", " - Contador interno\n", " - Operator Overloading" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Anime:\n", " class Ids:\n", " counter = 0\n", " def __call__(self):\n", " self.counter += 1\n", " return self.counter\n", " id_generator = Ids()\n", "\n", " def __init__(self, name, ranking):\n", " self._id = self.id_generator()\n", " self.name=name\n", " self.ranking = ranking\n", "\n", " def __eq__(self, other_anime):\n", " return self.name == other_anime.name and self.ranking == other_anime.ranking\n", "\n", " def __repr__(self):\n", " return f\"(id={self._id}, name={self.name}, rank={self.ranking})\"\n", "\n", " def __str__(self):\n", " return self.name" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_anime = []\n", "for rank, name in enumerate([\"FMA\", \"Steins;Gate\", \"HxH\", \"Kimi no Na Wa\"]):\n", " all_anime.append(Anime(name=name, ranking=rank))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- AnimeList\n", " - Operator Overloading\n", " - Agregamos Anime al principio y final de la lista" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AnimeList:\n", " def __init__(self, anime_list=None):\n", " if anime_list is not None:\n", " self.anime_list = anime_list\n", " else:\n", " self.anime_list = []\n", "\n", " def __add__(self, anime):\n", " temp = self.anime_list.copy()\n", " temp.append(anime)\n", " return AnimeList(temp)\n", "\n", " def __radd__(self, anime):\n", " temp = self.anime_list.copy()\n", " temp.insert(0, anime)\n", " return AnimeList(temp)\n", "\n", " def __eq__(self, other_list):\n", " return self.anime_list == other_list.anime_list\n", "\n", " def __getitem__(self, indices):\n", " return self.anime_list[indices]\n", "\n", " def __len__(self):\n", " return len(self.anime_list)\n", "\n", " def __repr__(self):\n", " return str(self.anime_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "anime_list = AnimeList()\n", "for anime in all_anime[1:]:\n", " anime_list += anime" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "print(anime_list)\n", "print(anime_list[:-1])\n", "print(len(anime_list))\n", "\n", "anime_list += all_anime[0]\n", "anime_list = all_anime[0] + anime_list\n", "\n", "print(anime_list)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Overkill\n", "\n", "- MAS\n", "- iterador" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- Anime" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "total ordering\n", "count\n", "hash\n", "iter" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from functools import total_ordering\n", "import itertools\n", "\n", "@total_ordering\n", "class Anime:\n", " class NewId:\n", " gen = itertools.count()\n", " def __call__(self):\n", " return next(self.gen)\n", " new_id = NewId()\n", "\n", " def __init__(self, name, ranking):\n", " self._id = Anime.new_id()\n", " self.name=name\n", " self.ranking = ranking\n", "\n", " def __eq__(self, other_anime):\n", " return self.name == other_anime.name and self.ranking == other_anime.ranking\n", "\n", " def __hash__(self):\n", " return hash(str(self._id) + self.name)\n", "\n", " def __lt__(self, other_anime):\n", " return self.ranking < other_anime.ranking\n", "\n", " def __repr__(self):\n", " return f\"(id={self._id}, name={self.name}, rank={self.ranking})\"\n", "\n", " def __str__(self):\n", " return self.name\n", "\n", " def __iter__(self):\n", " return iter((self.name, self.ranking))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "all_anime = []\n", "for rank, name in enumerate([\"FMA\", \"Steins;Gate\", \"HxH\", \"Kimi no Na Wa\"]):\n", " all_anime.append(Anime(name=name, ranking=rank))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "- AnimeList" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ " contains\n", " iter" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AnimeList:\n", " def __init__(self, anime_list=None):\n", " if anime_list is not None:\n", " self.anime_list = anime_list\n", " else:\n", " self.anime_list = []\n", "\n", " def __add__(self, anime):\n", " temp = self.anime_list.copy()\n", " temp.append(anime)\n", " return AnimeList(temp)\n", "\n", " def __radd__(self, anime):\n", " temp = self.anime_list.copy()\n", " temp.insert(0, anime)\n", " return AnimeList(temp)\n", "\n", " def __eq__(self, other_list):\n", " return self.anime_list == other_list.anime_list\n", "\n", " def __getitem__(self, indices):\n", " return self.anime_list[indices]\n", "\n", " def __len__(self):\n", " return len(self.anime_list)\n", "\n", " def __repr__(self):\n", " return str(self.anime_list)\n", "\n", " def __contains__(self, anime):\n", " return anime in self.anime_list\n", "\n", " def __iter__(self):\n", " return iter(self.anime_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "anime_list = AnimeList()\n", "for anime in all_anime[1:]:\n", " anime_list += anime" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "print(anime_list)\n", "print(anime_list[:-1])\n", "print(len(anime_list))\n", "\n", "anime_list += all_anime[0]\n", "anime_list = all_anime[0] + anime_list\n", "\n", "print(anime_list)\n", "\n", "for anime_name, anime_ranking in anime_list:\n", " print(anime_name, anime_ranking)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "ioWlbaRpNepK", "slideshow": { "slide_type": "subslide" } }, "source": [ "### NotImplemented" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " def __init__(self, var):\n", " self.var=var\n", "\n", " def __eq__(self, other):\n", " print(\"__eq__ not implemented in A\")\n", " return NotImplemented\n", "\n", " def __lt__(self, other):\n", " print(\"__lt__ not implemented in A\")\n", " return NotImplemented\n", "\n", "class B:\n", " def __init__(self, var):\n", " self.var=var\n", "\n", " def __eq__(self, other):\n", " print(\"__eq__ is implemented in B\")\n", " return self.var == other.var\n", "\n", " def __gt__(self, other):\n", " print(\"__gt__ is implemented in B\")\n", " return self.var > other.var" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "a = A(10)\n", "b = B(1)\n", "print(a==b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "b = B(10)\n", "print(a==b)\n", "\n", "print(\"-\"*20)\n", "\n", "print(a < b)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "MWzjjXDyNefl", "slideshow": { "slide_type": "slide" } }, "source": [ "## Herencia Multiple\n", "\n", "- Miedos de problema del diamante\n", "- Confusion sobre orden de llamado\n", "- Quien es quien" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Qq5CbIM-Pn8_", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Normal\n", "\n", "- La herencia que todos hemos visto" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " def __init__(self, var):\n", " self.var = var\n", " def mA(self):\n", " print(\"Im in A\")\n", "\n", "class B(A):\n", " def __init__(self, var1, var2):\n", " super().__init__(var1)\n", " self.var2 = var2\n", "\n", " def mB(self):\n", " print(\"Im in B\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A(10)\n", "b = B(100, 200)\n", "\n", "print(\"a is A\", isinstance(a, A))\n", "print(\"a is B\", isinstance(a, B))\n", "\n", "print(\"b is A\", isinstance(b, A))\n", "print(\"b is B\", isinstance(b, B))\n", "\n", "print(\"Metodos\")\n", "b.mA()\n", "b.mB()\n", "\n", "print(\"b variables\", b.var, b.var2)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "vL67EhWXPn5g", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Eleccion de super\n", "\n", "- No lo usen\n", "- En serio\n", "- Bueno si, pero si lo usan mucho tienen un problema de abstraccion" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class A:\n", " def m(self):\n", " print(\"Im in A\")\n", "\n", "class B(A):\n", " def m(self):\n", " print(\"Im in B\")\n", "\n", "class C(B):\n", " def m(self):\n", " print(\"Im in C\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class D(C):\n", " def m(self):\n", " print(\"Im in D\")\n", "\n", " def callerD(self):\n", " self.m()\n", " def callerC(self):\n", " super(D, self).m()\n", " def callerB(self):\n", " super(C, self).m()\n", " def callerA(self):\n", " super(B, self).m()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d = D()\n", "d.callerD()\n", "d.callerC()\n", "d.callerB()\n", "d.callerA()" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Kk7E1em4Pn2D", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Problemas con herencia multiple" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Student:\n", " def __init__(self, student_id, school, *args, **kwargs):\n", " self.student_id = student_id\n", " self.school = school\n", "\n", " def identification(self):\n", " return f\"ID:{self.student_id}-{self.surname}-{self.school}\"\n", " \n", "class Human:\n", " def __init__(self, name, age, *args, **kwargs):\n", " self.name = name\n", " self.age = age\n", "\n", " def identification(self):\n", " return f\"{self.name}\"\n", "\n", "class Yo(Student, Human):\n", " pass\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "yo = Yo(0, \"JP Silva\", \"UChile\", 500)\n", "print(yo.identification())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Method Resolution Order (MRO)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Yo.__mro__" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class Yo(Human, Student):\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "yo = Yo(0, \"JP Silva\", \"UChile\", 500)\n", "print(yo.identification())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "???????????????????" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Probemos otra cosa" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Yo(Human, Student):\n", " def identification(self):\n", " return Human.identification(self)\n", "\n", " def school_identification(self):\n", " return Student.identification(self)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "yo = Yo(student_id=0, name=\"JP Silva\", school=\"UChile\", age=500)\n", "print(yo.identification())\n", "print(yo.school_identification())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "oof que pasa" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "La buena forma, inicializar a todos los padres manualmente" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Yo(Human, Student):\n", " def __init__(self, name, *args, **kwargs):\n", " Human.__init__(self, *args, name=name, **kwargs)\n", " Student.__init__(self, *args, name=name, **kwargs)\n", "\n", " self.surname = name.split()[1]\n", "\n", " def identification(self):\n", " return Human.identification(self)\n", "\n", " def school_identification(self):\n", " return Student.identification(self)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "yo = Yo(student_id=0, name=\"JP Silva\", school=\"UChile\", age=500)\n", "print(yo.identification())\n", "print(yo.school_identification())" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "zQjW0qegPny4", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Mixins\n", "\n", "- Clases pequeñas que definen funcionalidad\n", "- Como un template, para los que pasaron metodologias" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Mixin:\n", " def mixin(self, arg1, arg2):\n", " print(arg1, arg2)\n", " \n", " # Mixin no tiene `var`\n", " return self.var\n", "\n", "class SuperClass:\n", " def m(self):\n", " print(\"In SuperClass\")\n", "\n", "class Example(SuperClass, Mixin):\n", " def __init__(self, var):\n", " self.var = var\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "e = Example(5)\n", "print(e.mixin(1, 2))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Mixin vs Clases abstractas?\n", "\n", "- Mixin provee de funcionalidad pero no puede usarla directamente\n", "- Clase abstracta provee de una interfaz. **No** tiene funcionalidad, el usuario debe implementarla" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- `sklearn` esta ***lleno*** de Mixins: https://github.com/scikit-learn/scikit-learn/blob/1495f6924/sklearn/base.py#L328" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "H9N_hkBcPnsg", "slideshow": { "slide_type": "slide" } }, "source": [ "## Metaclases" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why)\\\n", "> -- Tim Peters\n", "\n", "- 99% del tiempo no necesitaran modificar la inicializacion de una clase. \n", "- Del 1% cuando si lo necesitas, hay otras formas como decoradores de clases y especificaciones en \\_\\_new__, esto es el 99% de las veces cuando si necesitas modificar una clase.\n", "- El 1% del 1% de las veces, necesitas metaclases. No es un _feature_ que sea usable para el publico general, pero si no sabes que existe, y no sabes para que sirve, nunca podras saber si en algun momento lo necesitas o no." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Objeto como instancia de una clase" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "clase = fabrica de objetos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A: \n", " def __init__(self, var):\n", " self.var = var\n", "\n", "a = A(\"hola\")\n", "\n", "print(a.var)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a.v1 = 10\n", "print(a.v1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def example(arg):\n", " print(arg)\n", "\n", "example(a)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Las clases tambien son objetos" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "

Hmmmmm...

" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Clases como objetos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A: \n", " def __init__(self, var):\n", " self.var = var" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(A)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A.something = 100\n", "\n", "print(A.something)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "otherA = A\n", "print(otherA.something)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(otherA(\"Otra clase\"))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Muy util" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class_list = []\n", "for i in range(5):\n", " ###### Clase dentro? ######\n", " class AClass:\n", " var = i\n", " def __init__(self, arg):\n", " print(arg)\n", " \n", " class_list.append(AClass)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(class_list)\n", "print([c.var for c in class_list])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class_instances = []\n", "for c, arg in zip(class_list, \"holaquetal\"):\n", " class_instances.append(c(arg))\n", "\n", "print(class_instances)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Quien eres?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A(\"holi\")\n", "print(a)\n", "print(a.__class__)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(A)\n", "print(A.__class__)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(a.__class__.__class__)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "6rxMhkAmPnpL", "slideshow": { "slide_type": "subslide" } }, "source": [ "### `type` como funcion y como clase?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Como funcion\n", "\n", "- Dame un objeto y te digo quien es" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(type(a))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(type(10))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(type(\"Hola\"))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(type(True))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(type(type(True)))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Como funcion v2\n", "\n", "- Dame varias cosas y te doy una clase" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- ???????????????" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "type(class, bases, dict)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "B = type(\"B\", (), {})" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(B)\n", "print(B())" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Con variables" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "C = type(\"C\", (B, A), {\"a\":1, \"b\":2})\n", "print(C)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c = C(100)\n", "print(c.__dict__)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "variables = []\n", "for member_name in dir(c):\n", " if \"__\" not in member_name:\n", " value = getattr(c, member_name)\n", " variables.append(f\"{member_name}={value}\")\n", "print(\", \".join(variables))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "usar `dir`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Con metodos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def m(self, var):\n", " print(self.a, var)\n", "D = type(\"D\", (), {\"a\":1, \"m\":m})" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d = D()\n", "d.m(100)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "u9G5xHgNQSo0", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Metaclases\n", "\n", "- Una clase es una fabrica de objetos\n", "- Una metaclase es una fabrica de clases\n", "- `type` es una metaclase\n", "- `type` es super clase de si mismo" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d = D()\n", "print(d.__class__)\n", "print(d.__class__.__class__)\n", "print(d.__class__.__class__.__class__)\n", "dir(d.__class__.__class__)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Mi primera metaclase\n", "\n", "- pero es una funcion (?)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def all_dunder(cls, bases, attrs):\n", " dunder_attrs = {}\n", " for name, val in attrs.items():\n", " if not name.startswith('__'):\n", " print(f\"Replacing {name} with __{name}__\")\n", " dunder_attrs[f\"__{name}__\"] = val\n", " else:\n", " dunder_attrs[name] = val\n", " return type(cls, bases, dunder_attrs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AllDunder(metaclass=all_dunder):\n", " def a(arg):\n", " return arg\n", "\n", " def b(arg):\n", " return arg\n", "\n", " def c(arg):\n", " return arg" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dunder = AllDunder()\n", "dir(dunder)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Como clase ahora" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AllDunder(type):\n", " def __new__(cls, clsname, bases, attrs, **kwargs):\n", " print(kwargs)\n", "\n", " dunder_attrs = {}\n", " for name, val in attrs.items():\n", " if not name.startswith('__'):\n", " print(f\"Replacing {name} with __{name}__\")\n", " dunder_attrs[f\"__{name}__\"] = val\n", " else:\n", " dunder_attrs[name] = val\n", " return super().__new__(cls, clsname, bases, dunder_attrs)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class AllDunder(metaclass=AllDunder, arg1=\"do this\", arg2=\"do that\"):\n", " def a(arg):\n", " return arg\n", "\n", " def b(arg):\n", " return arg\n", "\n", " def c(arg):\n", " return arg" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Como funciona Django\n", "\n", "- Con metaclases" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class IntContainer:\n", " ...\n", " pass\n", "\n", "class StrContainer:\n", " ...\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class FixFields(type):\n", " def fix_complicated_database_logic(new_class, var_name, var_value):\n", " ...\n", " def get_prop(self):\n", " return getattr(self, \"__\" + var_name)\n", " def set_prop(self, value):\n", " return setattr(self, \"__\" + var_name, value)\n", "\n", " # este None es la logica complicada de meterse a la BD\n", " setattr(new_class, \"__\" + var_name, None)\n", " setattr(new_class, var_name, property(get_prop, set_prop))\n", "\n", " def __new__(cls, clsname, bases, attrs, **kwargs):\n", " filter_prop = {}\n", " std_dict = {}\n", " for name, val in attrs.items():\n", " if not name.startswith('__'):\n", " filter_prop[name] = val\n", " else:\n", " std_dict[name] = val\n", "\n", " new_cls = super().__new__(cls, clsname, bases, std_dict)\n", " setattr(new_cls, \"attributes\", set())\n", "\n", " for name, val in filter_prop.items():\n", " if not name.startswith('__'):\n", " FixFields.fix_complicated_database_logic(new_cls, name, val)\n", "\n", " getattr(new_cls, \"attributes\").add(name)\n", "\n", " setattr(new_cls, \"attributes\", frozenset(getattr(new_cls, \"attributes\")))\n", " return new_cls" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class Model(metaclass=FixFields):\n", " def __init__(self, **kwargs):\n", " for arg, val in kwargs.items():\n", " setattr(self, arg, val)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class ComplicatedAttrs(Model):\n", " age = IntContainer()\n", " name = StrContainer()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "db = ComplicatedAttrs(age=10, name=\"Hola\")\n", "print(db.attributes)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f\"age = {db.age}\")\n", "print(f\"name = {db.name}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "db.age=100\n", "print(f\"age = {db.age}\")" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "r2O_Qw1_Pnvt", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Virtual Super Classes\n", "\n", "- Clases que nunca extendi, pero de alguna manera si lo hice\n", "- Padres no reconocidos" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from collections.abc import Sized" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " def __len__(self):\n", " return 10" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = A()\n", "print(isinstance(a, Sized))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "????????????????????????" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Abstract Meta Class\n", "\n", "- Como si no fuera suficientemente confuso" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "dir(Sized)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "print(Sized.__abstractmethods__)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import inspect\n", "print(inspect.getsource(Sized.__class__))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "WH1VcTIpQSgv", "slideshow": { "slide_type": "slide" } }, "source": [ "## Otros temas que no vimos\n", "\n", "- Context Managers\n", "- Generadores y corutinas\n", "- Async\n", "- Cython y GIL" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "HQ_ue6lPQkfX", "slideshow": { "slide_type": "skip" } }, "source": [ "### Context Managers" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "uYVBb9lWQnPe", "slideshow": { "slide_type": "skip" } }, "source": [ "### Generadores" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "IUKKV0_RQpQS", "slideshow": { "slide_type": "skip" } }, "source": [ "### Asyncio - corutinas" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "PamrkdDcQrwH", "slideshow": { "slide_type": "skip" } }, "source": [ "### Cython y GIL" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "tWotVRssQtlT", "slideshow": { "slide_type": "subslide" } }, "source": [ "### `__slots__`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A:\n", " __slots__ = \"a\", \"b\"\n", " def __init__(self, a, b):\n", " self.a = a\n", " self.b = b\n", "\n", "class B:\n", " def __init__(self, a, b):\n", " self.a = a\n", " self.b = b" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from sys import getsizeof\n", "\n", "v = A(10, 20)\n", "print(getsizeof(v.__slots__))\n", "\n", "vb = B(10, 20)\n", "print(getsizeof(vb.__dict__))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "vk0GzKyTQSlg", "slideshow": { "slide_type": "slide" } }, "source": [ "## WTF Python" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "YK7e2g6dQd-p", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Reemplazar `__class__`\n", "\n", "- Because why not" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "class Node:\n", " def __init__(self, function):\n", " assert hasattr(function, \"__call__\")\n", " self.operation = function\n", " self.num_arguments = function.__code__.co_argcount\n", " self.arguments = []\n", "\n", " def eval(self):\n", " return self.operation(*[node.eval() for node in self.arguments])\n", " \n", " def replace(self, otherNode):\n", " assert isinstance(otherNode, Node)\n", " self.__class__ = otherNode.__class__\n", " self.__dict__ = otherNode.__dict__ " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class AddNode(Node):\n", " num_args = 2\n", " def __init__(self, left, right):\n", " super(AddNode, self).__init__(lambda x,y: x+y)\n", " self.arguments.append(left)\n", " self.arguments.append(right)\n", " def __repr__(self):\n", " return \"({} + {})\".format(*self.arguments)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class TerminalNode(Node):\n", " num_args = 0\n", " def __init__(self, value):\n", " super(TerminalNode, self).__init__(lambda:None)\n", " self.value = value\n", " def __repr__(self):\n", " return str(self.value)\n", " def eval(self):\n", " return self.value" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "n = AddNode(TerminalNode(1), TerminalNode(2))\n", "\n", "print(f\"n: {n}=\", n.eval())\n", "print(isinstance(n, AddNode))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "n.replace(TerminalNode(200))\n", "\n", "print(f\"n: {n}=\", n.eval())\n", "print(isinstance(n, AddNode))\n", "print(isinstance(n, TerminalNode))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "_yF5aq8UQd0y", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Parametros mutables default" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El error" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f(value, a=[]):\n", " a.append(value)\n", " ...\n", " return sum(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "returns = []\n", "for i in range(10):\n", " returns.append(f(i))\n", " \n", "print(returns)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f.__defaults__)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "La solucion" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f(value, a=None):\n", " if a is None:\n", " a = []\n", " a.append(value)\n", " ...\n", " return sum(a)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "returns = []\n", "for i in range(10):\n", " returns.append(f(i))\n", " \n", "print(returns)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f.__defaults__)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "JOwen02_Qd70", "slideshow": { "slide_type": "subslide" } }, "source": [ "### `257` no es `257`?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%reset -f" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=1\n", "b=1\n", "print(a is b)\n", "\n", "a=257\n", "b=257\n", "print(a is b)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "notes" } }, "source": [ "Pre inicializacion de -5 a 256" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "hXCRAsuFQd4a", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Cuidado con las referencias" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "row = [\"\"]*3\n", "print(row)\n", "\n", "board = [row]*3\n", "print(board)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "board[0][1] = \"X\"\n", "print(board)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text", "id": "Brwk_srdQdxH", "slideshow": { "slide_type": "subslide" } }, "source": [ "### Function Closure" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def f(n):\n", " res = []\n", " for x in range(n):\n", " def aux():\n", " return x + 10\n", " res.append(aux)\n", " return res" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "partial_fns = f(10)\n", "print(partial_fns)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print([fn() for fn in partial_fns])" ] }, { "cell_type": "markdown", "metadata": { "colab": {}, "colab_type": "code", "id": "BBo5GnoXM3B3", "slideshow": { "slide_type": "fragment" } }, "source": [ "

...

" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "def f(n):\n", " res = []\n", " for x in range(n):\n", " ##########.###########\n", " def aux(x=x):\n", " return x + 10\n", " res.append(aux)\n", " return res\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "partial_fns = f(10)\n", "print(partial_fns)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print([fn() for fn in partial_fns])" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Contacto\n", "\n", "
\n", "

Gracias!

\n", "
\n", "\n", "
\n", "Juan-Pablo Silva
\n", "jpsilva@dcc.uchile.cl
\n", "jpsilva.cl\n", "
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Slideshow", "colab": { "collapsed_sections": [], "name": "Semana Computina Presentation.ipynb", "provenance": [] }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" }, "rise": { "auto_select": "code", "auto_select_fragment": true, "autolaunch": true, "controls": true, "controlsTutorial": true, "enable_chalkboard": true, "footer": "

Juan-Pablo Silva

", "header": "

@Jivens

", "scroll": true, "slideNumber": true, "theme": "solarized", "transition": "zoom" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": false, "skip_h1_title": true, "title_cell": "Contenidos", "title_sidebar": "Contents", "toc_cell": true, "toc_position": {}, "toc_section_display": false, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 1 }