Me topé con un problema muy particular en Python y en stackoverflow encontré un ejemplo muy interesante.
Veamos la siguiente función y los prints.
def f(value, key, di={}):
di[value] = key
return di
print(f('a', 1))
print(f('b', 2))
La función recibe como argumentos dos valores (value y key) y un diccionario di. Al diccionario se le define el valor por defecto {}.
La función sencillamente genera un diccionario entre key y value.
Uno pensaría que los dos prints resultan en:
{'a': 1}
{'b': 2}
El primero haría, piensa uno, un dict con 'a' y 1, y el segundo con 'b' y 2.
Peeero, pero, pero... El resultado es
{'a': 1}
{'a': 1, 'b': 2}
Resulta que modificar el argumento por defecto hace que, en la próxima llamada a la función, ese argumento quede modificado.
La mejor solución sería:
def f(value, key, di=None):
if di is None:
di = {}
di[value] = key
return di
Miremos qué pasa cuando imprimimos por pantalla los valores por defecto de la función. Me puse a investigar el f.__defaults__.
En el primer caso, cuando se usa di={} como default, miremos qué ocurre con los siguientes prints.
print("Valor default de 'di';", f.__defaults__)
print(f('a', 1))
print("Valor default de 'di';", f.__defaults__)
print(f('b', 2))
Imprimen
Valor default de 'di'; ({},)
{'a': 1}
Valor default de 'di'; ({'a': 1},)
{'a': 1, 'b': 2}
Mientras que el segundo caso, donde el default es un None, se tiene
Valor default de 'di'; (None,)
{'a': 1}
Valor default de 'di'; (None,)
{'b': 2}
¿Será un bug de python?, porque no veo cómo sería beneficioso un comportamiento así.
Entiendo que debe tener que ver con que las listas y diccionarios en python hacen mucho uso de los punteros. Ese __default__ del argumento tiene un diccionario, y ese diccionario apunta a un lugar de memoria de forma constante. Se cambia ese dict, se cambia ese lugar de memoria. __default__ nunca cambió en realidad, sigue almacenando la dirección de memoria del dict.
Si hacemos algo parecido pero, en vez de dict y list, un int, tendríamos
def suma(x: list, suma_inicial: int = 0) -> int:
suma_inicial += sum(x)
return suma_inicial
nums1 = [1, 2, 3, 4]
nums2 = [4, 5, 5, 8]
print(suma(nums1))
print(suma(nums2))
Devuelve 10 y 22.
Pero si cambiamos la función para que haga lo mismo, solo que, operando en el primer lugar de una lista, o sea
def suma(x: list, suma_inicial: list = [0]) -> int:
suma_inicial[0] += sum(x)
return suma_inicial[0]
Devuelve 10 y 32.
Es muy interesante de ver esto.
Para animar como 3Blue1Brown, él mismo creó su propio engine de animación en python, llamado Manim. Está orientado a la animación didáctica para la enseñanza de temas relacionados con la matemática y computación.
Existen dos Manim: el original (de 3Blue1Brown) y el de la comunidad. Yo descargué ambas, pero la instalación de las dependecias y todo es mucho más fácil si se utiliza el de la comunidad.
Página oficial de Manim Community:
https://www.manim.community/
La documentación sobre cómo instalar:
https://docs.manim.community/en/stable/installation/windows.html
Para que la librería funcione, es necesario que se tenga FFmpeg (como aclara la documentación) y LaTex.
Para la instalación de las dependecias, lo más sencillo y recomendable es hacer a través de la PowerShell por Scoop, un gestor de paquetes de código abierto para Windows.
Instalación de Scoop a través de PowerShell (muy sencillo):
https://scoop.sh/
Luego, hacer scoop install ffmpeg para la instalación de ffmpeg y será inmediato. Nada de descargar, descomprimir e instalar, y menos de andar tocando el PATH de Windows. Scoop lo hace facilísimo.
Para LaTex: scoop install latex
Con pip install manim ya es suficiente para tener manim.
Un buen tutorial sobre cómo utilizar Manim:
https://www.youtube.com/watch?v=MOv6yN7b2aI
Acá un tip interesante. Lo es porque culpa de esto estuve perdiendo mucho tiempo sin entender por qué andaba mal la animación.
Un tip sobre la animación de Transform en Manim:
https://www.reddit.com/r/manim/comments/bq5bk2/manim_tutorial_difference_between_transform_and/
Para renderizar el video se hace por consola. Digamos que nuestro archivo python se llama scene.py, entonces se escribe: manim -pqh .\scene.py. El -p es para visualizar el video, el qh es para hacer el renderizado en High Quality. También se puede escribir -pql para Low Quality.
Otros links interesantes:
Mi primera animación para probar:
https://www.youtube.com/watch?v=eqplAPBOCdE
Tutorial de Manim:
https://www.youtube.com/watch?v=d9nbtyO2YcU
Para Colab, seguir el siguiente ejemplo:
https://colab.research.google.com/drive/1JOI83wVrQl1xIiTJF706p6iJi4eMievN?authuser=1&hl=es#scrollTo=pJWxbqTAmf9N
Para las dependencias mencionadas anteriormente, se las instala desde la consola de Colab a la computadora de Google que utiliza Linux.