Esperando 🐍

Datos de COLOR

Datos de COLOR 2

Datos de COLOR 2:

La Libreria Estandar

Antes de comenzar

Soy Josue

Figuro anotado en la carrera de Lic. en Informatica

Escucho mucha musica (y a gente que lo intenta)

Tomo mate hasta caminando (amargo e hirviendo, claramente)

Me gusta Python (pero hago web en JavaSript)

Me encontras como

Entonces, que es "Libreria Estandar"?

Entonces, que es "Libreria Estandar"?

Son los modulos/paquetes que vienen con el lenguaje al momento de instalarlo

Son los modulos/paquetes que vienen con el lenguaje al momento de instalarlo

Con el fin de solucionar problemas comunes

Con el fin de solucionar problemas comunes

Esos que podes importar sin un

pip install <libreria>

En Python, son muchos

En Python, son muchos

En esta charla, vamos a ver algunos

En Python, son muchos

En esta charla, vamos a ver algunos

Para aprender o recordar algunos datos de color

Pero, que decis con "dato de color"?

Pero, que decis con "dato de color"?

Son esas cosas/informacion que uno sabe, por curiosidad, por experiencia o que ni te acordas de donde pero lo sabes

Son esas cosas/informacion que uno sabe, por curiosidad, por experiencia o que ni te acordas de donde pero lo sabes

Y que en algun escenario hipotetico a alguien le sirve

Ahora si, comenzamos?

import pathlib
import pathlib

Interfaz orientada a objetos para manipular rutas de archivos y directorios

https://docs.python.org/3/_images/pathlib_inheritance.png

https://docs.python.org/3/_images/pathlib_inheritance.png

Que dice el grafico?

https://docs.python.org/3/_images/pathlib_inheritance.png

Que depende de donde se ejecute el codigo, Path instanciara el objeto para el SO subyacente

Entonces felizmente usamos Path y es cross-platform

import pathlib

path = pathlib.Path('.')

for p in path.iterdir():
    print(p)
.venv
presentation
sections
sys.html
test.py
xd.py

Solo para listar?

A ver la magia

import pathlib

path = pathlib.Path('c:/')

path = path / 'Windows' / 'System32'

print(*path.glob('m*o*d*u*l*o*'), sep="\n")
c:\Windows\System32\MediaFoundation.DefaultPerceptionProvider.dll

O algo mas simple

import pathlib

print(pathlib.Path.cwd())
C:\Users\suare\projects\personal\pyday

O algo comodo como

import pathlib

path = pathlib.Path('.')

with path.joinpath('.env').open() as f:
    print(f.read())
DB_URI=postgresql://por:quemeestas@localhost:5432/leyendo

OPENAPI_KEY=sk_test_4eC39HqLyjWDarjtT1zdp7dc

OAUTH_CLIENT_ID=1234567890-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com
OAUTH_CLIENT_SECRET=GOCSPX-abcdefgHIJKLMNopqrstuvwxyz12345
import inspect
import inspect

Inspeccion de objetos vivos como

clases, funciones, metodos, modulos, trazas de pila, marcos y codigo fuente

Ver las funciones de un modulo

import inspect
import secrets

print("nativas:", *inspect.getmembers(secrets, inspect.isbuiltin), sep="\n  ")
print("normal:", *inspect.getmembers(secrets, inspect.isfunction), sep="\n  ")
nativas:
  ('compare_digest', <built-in function compare_digest>)
normal:
  ('randbelow', <function randbelow at 0x000001C268038400>)
  ('token_bytes', <function token_bytes at 0x000001C2680398A0>)
  ('token_hex', <function token_hex at 0x000001C26803BEC0>)
  ('token_urlsafe', <function token_urlsafe at 0x000001C26803BF60>)

No falta la funcion secrets.choice?

No falta la funcion secrets.choice?

import inspect
import secrets

print("normal:", *inspect.getmembers(secrets, inspect.ismethod), sep="\n  ")
import inspect
import secrets

print("normal:", *inspect.getmembers(secrets, inspect.ismethod), sep="\n  ")
metodo:
  ('choice', <bound method Random.choice of <random.SystemRandom object at 0x000001EB6ED0BE60>>)
  ('randbits', <bound method SystemRandom.getrandbits of <random.SystemRandom object at 0x000001EB6ED0BE60>>)

Ver la documentacion de un objeto

import inspect

print(inspect.getdoc(inspect))
import inspect

print(inspect.getdoc(inspect))
Generate cryptographically strong pseudo-random numbers suitable for
managing secrets such as account authentication, tokens, and similar.

See PEP 506 for more information.
https://peps.python.org/pep-0506/

Ver el codigo fuente de un objeto

import inspect

print(inspect.getsource(inspect.SystemRandom))
class SystemRandom(Random):
    """Alternate random number generator using sources provided
    by the operating system (such as /dev/urandom on Unix or
    CryptGenRandom on Windows).

    Not available on all systems (see os.urandom() for details).
    """

    def random(self):
        """Get the next random number in the range 0.0 <= X < 1.0."""
        return (int.from_bytes(_urandom(7)) >> 3) * RECIP_BPF
    ...
    def seed(self, *args, **kwds):
        "Stub method.  Not used for a system random number generator."
        return None

    def _notimplemented(self, *args, **kwds):
        "Method should not be called for a system random number generator."
        raise NotImplementedError('System entropy source does not have state.')
    getstate = setstate = _notimplemented

Ver el codigo fuente de una funcion

import inspect

print(inspect.getsource(print))
Traceback (most recent call last):
  File "C:\Users\suare\projects\personal\pyday\xd.py", line 25, in <module>
    print(inspect.getsource(print))
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\suare\.pyenv\pyenv-win\versions\3.12.1\Lib\inspect.py",
  line 1282, in getsource
    lines, lnum = getsourcelines(object)
                  ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\suare\.pyenv\pyenv-win\versions\3.12.1\Lib\inspect.py",
  line 1264, in getsourcelines
    lines, lnum = findsource(object)
                  ^^^^^^^^^^^^^^^^^^
  File "C:\Users\suare\.pyenv\pyenv-win\versions\3.12.1\Lib\inspect.py",
  line 1075, in findsource
    file = getsourcefile(object)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\suare\.pyenv\pyenv-win\versions\3.12.1\Lib\inspect.py",
  line 952, in getsourcefile
    filename = getfile(object)
               ^^^^^^^^^^^^^^^
  File "C:\Users\suare\.pyenv\pyenv-win\versions\3.12.1\Lib\inspect.py",
  line 932, in getfile
    raise TypeError('module, class, method, function, traceback, frame, or '
TypeError: module, class, method, function, traceback, frame, or code object
was expected, got builtin_function_or_method

Cuidado con codigo nativo, hay cosas que no se pueden ver

Ver componentes de una funcion

import inspect

def BuenEjemplo(a, b: int, c: str = "algo", **kwargs) -> int:
    """Esta es un muy buen ejemplo."""
    return a + b + c

signature = inspect.signature(BuenEjemplo)
print(signature.parameters)
print(signature.return_annotation)
OrderedDict({
  'a': <Parameter "a">,
  'b': <Parameter "b: int">,
  'c': <Parameter "c: str = 'hola'">,
  'kwargs': <Parameter "**kwargs">
})
<class 'int'>
import atexit
import atexit

Registrar funciones de limpieza para ejecutar cuando el programa termina

import atexit

def chau():
    print("termine la ejecucion 👌")

atexit.register(chau)
import atexit

def chau():
    print("termine la ejecucion 👌")

atexit.register(chau)
termine la ejecucion 👌

De que es util?

De que es util?

Para guardar logs, cerrar conexiones, liberar recursos, etc

Si, pero no es lo mismo que un finally o usar un context manager?

Si, pero no es lo mismo que un finally o usar un context manager?

No, finally o context manager se ejecutan siempre, atexit solo si el interprete termina normalmente o se llama a exit() o sys.exit()

Se pueden registrar multiples funciones

Se pueden registrar multiples funciones

Se ejecutan en orden inverso al que se registraron

import atexit

primera = lambda: print("primera")
segunda = lambda: print("segunda")
otra = lambda x: print(x)

atexit.register(primera)
atexit.register(segunda)
atexit.register(otra, "tercera")
tercera
segunda
primera

Y si queremos des-registrar una funcion?

Y si queremos des-registrar una funcion?

atexit.unregister(<una_funcion>)
import atexit

desapareci = lambda name: print(f"{name} desapareci")

me_quede = lambda name: print(f"{name} me_quede")

atexit.register(desapareci, "primera")
atexit.register(me_quede, "segunda")
atexit.register(desapareci, name="tercera")
atexit.unregister(desapareci)
import atexit

desapareci = lambda name: print(f"{name} desapareci")

me_quede = lambda name: print(f"{name} me_quede")

atexit.register(desapareci, "primera")
atexit.register(me_quede, "segunda")
atexit.register(desapareci, name="tercera")
atexit.unregister(desapareci)
segunda me_quede
import doctest
import doctest

Validar ejemplos en las docstrings de un modulo, tal que representen la implementacion

def baskara(a, b, c):
    """
    Calcula las raices de una ecuacion cuadratica
    >>> baskara(1, 0, -1)
    (1.0, -1.0)
    >>> baskara(1, 0, 1)
    Traceback (most recent call last):
        ...
    ValueError: math domain error
    """
    from math import sqrt
    x1 = (-b + sqrt(b**2 - 4*a*c)) / (2*a)
    x2 = (-b - sqrt(b**2 - 4*a*c)) / (2*a)
    return x1, x2

if __name__ == "__main__":
    import doctest
    doctest.testmod()
python mi_modulo.py

Y el resultado?

Y el resultado?

Si el resultado esta bien, no se imprime nada

Y el resultado?

Si el resultado esta bien, no se imprime nada

Sino, se imprime el reporte de errores

Para ver que esta pasando, podemos usar el flag -v

Para ver que esta pasando, podemos usar el flag -v

python mi_modulo.py -v
python mi_modulo.py -v
Trying:
    baskara(1, 0, -1)
Expecting:
    (1.0, -1.0)
ok
Trying:
    baskara(1, 0, 1)
Expecting:
    Traceback (most recent call last):
        ...
    ValueError: math domain error
ok
1 items had no tests:
    __main__
1 items passed all tests:
   2 tests in __main__.baskara
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

O podemos correr los tests de un modulo

""">>> count_letters("me leiste")
{'m': 1, 'e': 3, 'l': 1, 'i': 1, 's': 1, 't': 1}
"""
import collections
import string

def count_letters(text: str):
    """>>> count_letters("hola")
    {'h': 1, 'o': 1, 'l': 1, 'a': 1}
    >>> count_letters(43)
    Traceback (most recent call last):
        ...
    ValueError: text must be a string
    """
    normalized_text = "".join(c for c in text.lower() if c in string.ascii_lowercase)
    return {**collections.Counter(normalized_text)}
python -m doctest counter.py
**********************************************************************
File "C:\Users\suare\projects\personal\pyday\counter.py", line 15, in counter.count_letters
Failed example:
    count_letters(43)
Expected:
    Traceback (most recent call last):
        ...
    ValueError: text must be a string
Got:
    Traceback (most recent call last):
      File "C:\Users\suare\.pyenv\pyenv-win\versions\3.12.1\Lib\doctest.py", line 1359, in __run
        exec(compile(example.source, filename, "single",
      File "<doctest counter.count_letters[1]>", line 1, in <module>
        count_letters(43)
      File "C:\Users\suare\projects\personal\pyday\counter.py", line 20, in count_letters
        normalized_text = "".join(c for c in text.lower() if c in string.ascii_lowercase)
                                             ^^^^^^^^^^
    AttributeError: 'int' object has no attribute 'lower'
**********************************************************************
1 items had failures:
   1 of   2 in counter.count_letters
***Test Failed*** 1 failures.

Uh, no paso el test

Uh, no paso el test

Falto validar que el argumento sea un string

""">>> count_letters("me leiste")
{'m': 1, 'e': 3, 'l': 1, 'i': 1, 's': 1, 't': 1}
"""
import collections
import string

def count_letters(text: str):
    """>>> count_letters("hola")
    {'h': 1, 'o': 1, 'l': 1, 'a': 1}
    >>> count_letters(43)
    Traceback (most recent call last):
        ...
    ValueError: text must be a string
    """
    if not isinstance(text, str):
        raise ValueError("text must be a string")

    normalized_text = "".join(c for c in text.lower() if c in string.ascii_lowercase)
    return {**collections.Counter(normalized_text)}
python -m doctest counter.py

doctest prima la exactitud

doctest prima la exactitud

Hay casos donde no es lo que queremos, ya que el resultado esta simplificado

doctest prima la exactitud

Hay casos donde no es lo que queremos, ya que el resultado esta simplificado

Para eso podemos usar flags

Para eso podemos usar flags

def numeros():
    """>>> numeros()
    [1, 2, ...,        10]
    """
    return list(range(1, 11))

if __name__ == "__main__":
    import doctest

    doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE)
python numeros.py

O como modulo

python -m doctest -o ELLIPSIS -o NORMALIZE_WHITESPACE numeros.py

Podemos extraer un script desde los ejemplos

Podemos extraer un script desde los ejemplos

import doctest

print(doctest.script_from_examples(r"""
    Este es un ejemplo sencillo
    >>> def suma(a, b):
    ...     return a + b
    >>> suma(1, 2)
    3

    o tambien se puede hacer con un lambda

    >>> resta = lambda a, b: a - b
    >>> resta(2, 1)
    1
"""))

Podemos extraer un script desde los ejemplos

# Este es un ejemplo sencillo
def suma(a, b):
    return a + b
suma(1, 2)
# Expected:
## 3
#
# o tambien se puede hacer con un lambda
#
resta = lambda a, b: a - b
resta(2, 1)
# Expected:
## 1
import shutil
import shutil

Utilidades simples para manipular archivos y directorios

Utilidades simples para manipular archivos y directorios

Mas comodas que usar os y os.path

Simples?

Simples?

Como?

Asi

import shutil

shutil.copy('test.py', 'test2.py')
import shutil

shutil.copy('test.py', 'test2.py')
ls
no_tengo_cosas tengo_cosas test.py

python test.py

ls
no_tengo_cosas tengo_cosas test.py test2.py

Ah, hay cosas ahi?

Ah, hay cosas ahi?

tree
.
├─test.py
├─test2.py
├─no_tengo_cosas
 ├─estoy_vacio
 └─no_estoy
   └─yo_tampoco.md
└─tengo_cosas

Arreglemos eso

Arreglemos eso

import shutil

shutil.copytree('no_tengo_cosas', 'tengo_cosas', dirs_exist_ok=True)
python test.py
tree
.
├─test.py
├─test2.py
├─no_tengo_cosas
 ├─estoy_vacio
 └─no_estoy
   └─yo_tampoco.md
└─tengo_cosas
  ├─estoy_vacio
  └─no_estoy
    └─yo_tampoco.md
python test.py
tree
.
├─test.py
├─test2.py
├─no_tengo_cosas
 ├─estoy_vacio
 └─no_estoy
   └─yo_tampoco.md
└─tengo_cosas
  ├─estoy_vacio
  └─no_estoy
    └─yo_tampoco.md

Uh lo duplicamos

Solucionado

import shutil

shutil.rmtree('no_tengo_cosas')
python test.py
tree
.
├─test.py
├─test2.py
└─tengo_cosas
  ├─estoy_vacio
  └─no_estoy
    └─yo_tampoco.md

Para para para, pero hay muchos archivos

Para para para, pero hay muchos archivos

import shutil

shutil.move('tengo_cosas', 'comprimido')
shutil.move('test.py', 'comprimido')
shutil.move('test2.py', 'comprimido')
shutil.make_archive('comprimido', 'zip', 'comprimido')
shutil.rmtree('comprimido')
import shutil

shutil.move('tengo_cosas', 'comprimido')
shutil.move('test.py', 'comprimido')
shutil.move('test2.py', 'comprimido')
shutil.make_archive('comprimido', 'zip', 'comprimido')
shutil.rmtree('comprimido')
python test.py
tree
.
└─comprimido.zip

Ahora si

Me pregunto donde esta el comando tree

Me pregunto donde esta el comando tree

import shutil

shutil.which('tree')
import shutil

shutil.which('tree')
python test.py
C:\Windows\system32\tree.COM
python test.py
C:\Windows\system32\tree.COM

Ah mira, esta en system32

Ah mira, esta en system32

Mejor dejemos de jugar

Ah mira, esta en system32

Mejor dejemos de jugar


siguiente modulo 🙃

import sqlite3
import sqlite3

Trabajar con bases de datos SQLite

Trabajar con bases de datos SQLite

locales

Simple, rapido, y facil de usar

Simple, rapido, y facil de usar

import sqlite3

con = sqlite3.connect('example.db')
cur = con.cursor()
cur.execute("CREATE TABLE chiki (nombre TEXT, edad INTEGER)")
print(cur.execute("SELECT name FROM sqlite_master").fetchall())
import sqlite3

con = sqlite3.connect('example.db')
cur = con.cursor()
cur.execute("CREATE TABLE chiki (nombre TEXT, edad INTEGER)")
print(cur.execute("SELECT name FROM sqlite_master").fetchall())
[('chiki',)]
chikis = [
    ('Guido van Rossum', 68),
    ('Raymond Hettinger', 50),
    ('Brett Cannon', 45)
]
cur.executemany("INSERT INTO chiki VALUES (?, ?)", chikis)
con.commit()
print(cur.execute("SELECT * FROM chiki WHERE edad >= 50").fetchall())
chikis = [
    ('Guido van Rossum', 68),
    ('Raymond Hettinger', 50),
    ('Brett Cannon', 45)
]
cur.executemany("INSERT INTO chiki VALUES (?, ?)", chikis)
con.commit()
print(cur.execute("SELECT * FROM chiki WHERE edad >= 50").fetchall())
[('Guido van Rossum', 68), ('Raymond Hettinger', 50)]

No te olvides de cerrar la conexion

No te olvides de cerrar la conexion

con.close()

No te olvides de cerrar la conexion

con.close()

Pero tampoco te olvides de usar commit

No te olvides de cerrar la conexion

con.commit()
con.close()

Pero tampoco te olvides de usar commit

Genial, ahora ya sabes como trabajar con SQLite en Python

Algo mas?

Algo mas?

import sqlite3

con = sqlite3.connect(':memory:')
cur = con.cursor()
cur.execute("CREATE TABLE temp (msg TEXT)")
cur.execute("INSERT INTO temp VALUES ('Solo en memoria')")
cur.execute("INSERT INTO temp VALUES (', en otros terminos, no persistente')")
print("".join(*cur.execute("SELECT * FROM temp").fetchall()))
import sqlite3

con = sqlite3.connect(':memory:')
cur = con.cursor()
cur.execute("CREATE TABLE temp (msg TEXT)")
cur.execute("INSERT INTO temp VALUES ('Solo en memoria')")
cur.execute("INSERT INTO temp VALUES (', en otros terminos, no persistente')")
print("".join(*cur.execute("SELECT * FROM temp").fetchall()))
Solo en memoria, en otros terminos, no persistente

Algo mas?

Algo mas?

import sqlite3

original = sqlite3.connect('example.db')
nueva = sqlite3.connect(':memory:')
original.backup(nueva)
original.close()
nueva.close()
import sqlite3

original = sqlite3.connect('example.db')
nueva = sqlite3.connect(':memory:')
original.backup(nueva)
original.close()
nueva.close()

Creanme que hace el backup bien

Un poco de error handling no vendria mal

Un poco de error handling no vendria mal

import sqlite3

con = sqlite3.connect(':memory:')
cur = con.cursor()
cur.execute("CREATE TABLE escribime_bien (msg TEXT)")
try:
    cur.execute("INSERT INTO escribime_mal VALUES ('no_quiero')")
except sqlite3.Error as e:
    print("capturamos un error, no se cual")
finally:
    con.close()
import sqlite3

con = sqlite3.connect(':memory:')
cur = con.cursor()
cur.execute("CREATE TABLE escribime_bien (msg TEXT)")
try:
    cur.execute("INSERT INTO escribime_mal VALUES ('no_quiero')")
except sqlite3.Error as e:
    print("capturamos un error, no se cual")
finally:
    con.close()
capturamos un error, no se cual
capturamos un error, no se cual

Tranquilos, hay mas especificos

Tranquilos, hay mas especificos

import sqlite3

print(*(
  "sqlite3" + name
  for name in dir(sqlite3)
  if "Error" in name
))
import sqlite3

print(*(
  "sqlite3" + name
  for name in dir(sqlite3)
  if "Error" in name
))
sqlite3.DataError sqlite3.DatabaseError sqlite3.Error sqlite3.IntegrityError
sqlite3.InterfaceError sqlite3.InternalError sqlite3.NotSupportedError
sqlite3.OperationalError sqlite3.ProgrammingErro
import sys
import sys

Acceso a variables usadas/mantenidas por el interprete y funciones para interactuar con este

Veamos algunas

Veamos algunas

import sys

print(sys.argv)

Veamos algunas

import sys

print(sys.argv)
python xd.py $HOME "argumento 2"
['xd.py', 'C:\\Users\\suare', 'argumento 2']

Veamos algunas

import sys

print(sys.orig_argv)

Veamos algunas

import sys

print(sys.orig_argv)
python xd.py $HOME "argumento 2"
[
  'C:\\Users\\suare\\.pyenv\\pyenv-win\\versions\\3.12.1\\python.exe',
  'xd.py', 'C:\\Users\\suare', 'argumento 2'
]

Veamos algunas

import sys

print(sys.byteorder)

Veamos algunas

import sys

print(sys.byteorder)
python xd.py
little

Endianess

Big Endian

Little Endian

Veamos algunas

import sys

print(len(sys.builtin_module_names))
print(len(sys.stdlib_module_names))
print(len(sys.modules))

Veamos algunas

import sys

print(len(sys.builtin_module_names))
print(len(sys.stdlib_module_names))
print(len(sys.modules))
67
300
35

Veamos algunas

import sys

print(sys.path)

Veamos algunas

import sys

print(sys.path)

Es la lista de directorios donde Python busca modulos, prepopulada con la variable de entorno PYTHONPATH y un por defecto que depende del sistema subyacente

Veamos algunas

import sys

print(sys.copyright)

Veamos algunas

import sys

print(sys.copyright)
Copyright (c) 2001-2023 Python Software Foundation.
All Rights Reserved.

Copyright (c) 2000 BeOpen.com.
All Rights Reserved.

Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.

Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved.

Veamos algunas

import sys

print(sys.implementation)
print(sys.platform)
print(sys.version)
print(sys.getrecursionlimit())

Veamos algunas

import sys

print(sys.implementation)
print(sys.platform)
print(sys.version)
print(sys.getrecursionlimit())
namespace(
  name='cpython', cache_tag='cpython-312',
  version=sys.version_info(major=3, minor=12, micro=1, releaselevel='final', serial=0),
  hexversion=51118576)
win32
3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)]
1000

Veamos algunas

import sys

x = 1
y = [x, 2, 3]
z = {'x': x, 'y': y}

print(sys.getsizeof(x))
print(sys.getrefcount(x))

Veamos algunas

import sys

x = 1
y = [x, 2, 3]
z = {'x': x, 'y': y}

print(sys.getsizeof(x))
print(sys.getrefcount(x))
28
4294967295

Veamos algunas

import sys

x = 1
y = [x, 2, 3]
z = {'x': x, 'y': y}

print(sys.getrefcount(y))

Veamos algunas

import sys

x = 1
y = [x, 2, 3]
z = {'x': x, 'y': y}

print(sys.getrefcount(y))
3
import tempfile
import tempfile

Crear archivos y directorios temporales

Crear archivos y directorios temporales

De que nos sirve?

De que nos sirve?

Para trabajar con grandes volumenes de datos, haciendo transformaciones y otras operaciones que no necesitamos persistir en disco

Para trabajar con grandes volumenes de datos, haciendo transformaciones y otras operaciones que no necesitamos persistir en disco

Es ahi donde entra tempfile y nos simplifica la vida

Es ahi donde entra tempfile y nos simplifica la vida

import tempfile

with tempfile.TemporaryFile() as f:
    f.write(b'hello world')
    f.seek(0)
    print(f.read())
import tempfile

with tempfile.TemporaryFile() as f:
    f.write(b'hello world')
    f.seek(0)
    print(f.read())
b'hello world'

Por defecto, los archivos son abiertos en modo w+b

Por defecto, los archivos son abiertos en modo w+b

Con mode=<modo apertura> se puede cambiar

Con las funciones

tempfile.mkstemp se crea un archivo temporal

tempfile.mkdtemp se crea un directorio temporal

Con las funciones

tempfile.mkstemp se crea un archivo temporal

tempfile.mkdtemp se crea un directorio temporal

Pero hay que hacer la limpieza manualmente

Por lo que es mejor usar

tempfile.TemporaryFile, tempfile.NamedTemporaryFile y tempfile.TemporaryDirectory

Por lo que es mejor usar

tempfile.TemporaryFile, tempfile.NamedTemporaryFile y tempfile.TemporaryDirectory

Ya que al ser context managers, hacen el cierre y eliminacion del archivo/directorio automaticamente

import os
import tempfile

with tempfile.NamedTemporaryFile() as f:
    print(f.name)
    print(os.path.exists(f.name))

print(os.path.exists(f.name))
import os
import tempfile

with tempfile.NamedTemporaryFile() as f:
    print(f.name)
    print(os.path.exists(f.name))

print(os.path.exists(f.name))
C:\Users\suare\AppData\Local\Temp\tmpkjh2rj8i
True
False

Algo totalmente innecesario

Algo totalmente innecesario

import os
import tempfile

with tempfile.TemporaryDirectory() as d:
    for i in range(100):
        with open(f'{d}/file_{_}.txt', 'w') as f:
            f.write(f'Hola soy el archivo {i}')

    print(sum(
        os.path.getsize(f)
        for f in os.listdir(d)
        if os.path.isfile(f)
    ))
import os
import tempfile

with tempfile.TemporaryDirectory() as d:
    for i in range(100):
        with open(f'{d}/file_{_}.txt', 'w') as f:
            f.write(f'Hola soy el archivo {i}')

    print(sum(
        os.path.getsize(f)
        for f in os.listdir(d)
        if os.path.isfile(f)
    ))
0
import os
import tempfile

with tempfile.TemporaryDirectory() as d:
    for i in range(100):
        with open(f'{d}/file_{_}.txt', 'w') as f:
            f.write(f'Hola soy el archivo {i}')

    print(sum(
        os.path.getsize(f)
        for f in os.listdir(d)
        if os.path.isfile(f)
    ))

Como que pesa 0?

import os
import tempfile

with tempfile.TemporaryDirectory() as d:
    for i in range(100):
        with open(f'{d}/file_{_}.txt', 'w') as f:
            f.write(f'Hola soy el archivo {i}')

    print(sum(
        os.path.getsize(f)
        for f in os.listdir(d)
        if os.path.isfile(f)
    ))

Me falto el d/ en el os.path.getsize(f) e if os.path.isfile(f)

import os
import tempfile

with tempfile.TemporaryDirectory() as d:
    for i in range(100):
        with open(f'{d}/file_{_}.txt', 'w') as f:
            f.write(f'Hola soy el archivo {i}')

    print(sum(
        os.path.getsize(f"{d}/{f}")
        for f in os.listdir(d)
        if os.path.isfile(f"{d}/{f}")
    ))

Ahora si

import os
import tempfile

with tempfile.TemporaryDirectory() as d:
    for i in range(100):
        with open(f'{d}/file_{_}.txt', 'w') as f:
            f.write(f'Hola soy el archivo {i}')

    print(sum(
        os.path.getsize(f"{d}/{f}")
        for f in os.listdir(d)
        if os.path.isfile(f"{d}/{f}")
    ))
2190
import timeit
import timeit

Medir tiempo de ejecucion de pequeños fragmentos de codigo, de forma simple

import timeit

print(timeit.timeit('8 / 2 * (2 + 2)'), "segundos")
import timeit

print(timeit.timeit('8 / 2 * (2 + 2)'), "segundos")
0.014247099999920465 segundos
import timeit

print(timeit.timeit('8 / 2 * (2 + 2)'), "segundos")
0.014247099999920465 segundos

resultado

Esta bien, que mas?

Permite definir el número de muestras

timeit.timeit(number=<default 1_000_000>)

Permite definir la funcion de tiempo

timeit.timeit(timer=<default time.perf_counter>)

Permite definir la funcion de tiempo

timeit.timeit(timer=<default time.perf_counter>)

Algunas opciones

time.perf_counter

time.perf_counter_ns

time.process_time

Permite repetir la medicion

timeit.repeat(repeat=<default 5>)

Permite repetir la medicion

timeit.repeat(repeat=<default 5>)

Util para acercarnos al lower bound

Si lo juntamos todo

Si lo juntamos todo

import time
import timeit

medidas = timeit.repeat(
    "pow(2, 200)",
    number=1_000,
    repeat=100,
    timer=time.perf_counter_ns
)
print(len(medidas), "mediciones")
print(min(medidas), "ns")
import time
import timeit

medidas = timeit.repeat(
    "pow(2, 200)",
    number=1_000,
    repeat=100,
    timer=time.perf_counter_ns
)
print(len(medidas), "mediciones")
print(min(medidas), "ns")
100 mediciones
240900 ns

Para casos mas complejos, estan los parametros setup o globals

Para casos mas complejos, estan los parametros setup o globals

setup se ejecuta una vez antes de cada medicion

Para casos mas complejos, estan los parametros setup o globals

setup se ejecuta una vez antes de cada medicion

globals se usa para pasar el contexto de ejecucion

globals se usa para pasar el contexto de ejecucion

import timeit

msj = 'un caso de prueba' * 100
s1 = 'sum(map(ord, msj))'
s2 = '''x = 0
for c in msj:
    x += ord(c)
'''
s3 = 'sum(msj.encode("utf-8"))'

print(timeit.timeit(s1, globals=globals()))
print(timeit.timeit(s2, globals=globals()))
print(timeit.timeit(s3, globals=globals()))
import timeit

msj = 'un caso de prueba' * 100
s1 = 'sum(map(ord, msj))'
s2 = '''x = 0
for c in msj:
    x += ord(c)
'''
s3 = 'sum(msj.encode("utf-8"))'

print(timeit.timeit(s1, globals=globals()))
print(timeit.timeit(s2, globals=globals()))
print(timeit.timeit(s3, globals=globals()))
36.25424589999966
90.68637050000143
8.36053659999925

Hay una mas rapida?

Hay una mas rapida?

Mirando bien el escenario a medir

Mirando bien el escenario a medir

import timeit

msj = 'un caso de prueba' * 100
s4 = """\
slice_len = len(msj) // 100
slice = msj[:slice_len].encode('utf-8')
sum(slice) * 100
"""

print(timeit.timeit(s4, globals=globals()))
import timeit

msj = 'un caso de prueba' * 100
s4 = """\
slice_len = len(msj) // 100
slice = msj[:slice_len].encode('utf-8')
sum(slice) * 100
"""

print(timeit.timeit(s4, globals=globals()))
0.42981549999967683

Casi me olvido

Casi me olvido

Tambien puede ser usado desde la terminal

Tambien puede ser usado desde la terminal

python -m timeit -s "import math; x=48; y=-1.9" "math.copysign(x, y)"

Tambien puede ser usado desde la terminal

python -m timeit -s "import math; x=48; y=-1.9" "math.copysign(x, y)"
2000000 loops, best of 5: 114 nsec per loop

Tambien puede ser usado desde la terminal

python -m timeit -s "import math; x=48; y=-1.9" "math.copysign(x, y)"
2000000 loops, best of 5: 114 nsec per loop

python -m timeit "x = 48; y = -1.9" "x * 1.0 if y > 0 else -1.0 * x"

Tambien puede ser usado desde la terminal

python -m timeit -s "import math; x = 48; y = -1.9" "math.copysign(x, y)"
2000000 loops, best of 5: 114 nsec per loop

python -m timeit "x = 48; y = -1.9" "x * 1.0 if y > 0 else -1.0 * x"
5000000 loops, best of 5: 91.8 nsec per loop

Esos fueron algunos modulos

Esos fueron algunos modulos

de 201 modulos listados en la documentacion de Python 3.12.6

Para que se den una idea

Solo vimos 9

import atexitimport doctestimport inspect
import pathlibimport shutilimport sqlite3
import sysimport tempfileimport timeit

Faltaron 65

import __future__import __main__import _threadimport _tkinterimport abc
import aifcimport argparseimport arrayimport astimport asyncio
import audioopimport base64import bdbimport binasciiimport bisect
import builtinsimport bz2import calendarimport cgiimport cgitb
import chunkimport cmathimport cmdimport codeimport codecs
import codeopimport collectionsimport colorsysimport compileallimport concurrent
import configparserimport contextlibimport contextvarsimport copyimport copyreg
import cryptimport csvimport ctypesimport cursesimport dataclasses
import datetimeimport dbmimport decimalimport difflibimport dis
import emailimport encodingsimport ensurepipimport enumimport errno
import faulthandlerimport fcntlimport filecmpimport fileinputimport fnmatch
import fractionsimport ftplibimport functoolsimport gcimport getopt
import getpassimport gettextimport globimport graphlibimport grp

Y otros 65

import gzipimport hashlibimport heapqimport hmacimport html
import httpimport idlelibimport imaplibimport imghdrimport importlib
import ioimport ipaddressimport itertoolsimport jsonimport keyword
import lib2to3import linecacheimport localeimport loggingimport lzma
import mailboximport mailcapimport marshalimport mathimport mimetypes
import mmapimport modulefinderimport msilibimport msvcrtimport multiprocessing
import netrcimport nisimport nntplibimport numbersimport operator
import optparseimport osimport ossaudiodevimport pdbimport pickle
import pickletoolsimport pipesimport pkgutilimport platformimport plistlib
import poplibimport posiximport pprintimport profileimport pty
import pwdimport py_compileimport pyclbrimport pydocimport queue
import quopriimport randomimport reimport readlineimport reprlib
import resourceimport rlcompleterimport runpyimport schedimport secrets

Y otros 61 mas

import selectimport selectorsimport shelveimport shleximport signal
import siteimport smtplibimport sndhdrimport socketimport socketserver
import spwdimport sslimport statimport statisticsimport string
import stringprepimport structimport subprocessimport sunauimport symtable
import sysconfigimport syslogimport tabnannyimport tarfileimport telnetlib
import termiosimport testimport textwrapimport threadingimport time
import tkinterimport tokenimport tokenizeimport tomllibimport trace
import tracebackimport tracemallocimport ttyimport turtleimport types
import typingimport unicodedataimport unittestimport urllibimport uu
import uuidimport venvimport warningsimport waveimport weakref
import webbrowserimport winregimport winsoundimport wsgirefimport xdrlib
import xmlimport zipzappimport zipfileimport zipimportimport zlib
import zoneinfo

Les quedo tarea

Les quedo tarea

191 modulos para investigar

Les quedo tarea

191 modulos para investigar

https://docs.python.org/3/py-modindex.html

Espero haber despertado su curiosidad

y que se animen a explorar la Libreria Estandar

O al menos

que vaya a saber dios la api que tiene...

O al menos

que se tomen un momento antes de buscar una libreria de terceros

que vaya a saber dios la api que tiene...

O al menos

que se tomen un momento antes de buscar una libreria de terceros

que vaya a saber dios la api que tiene...

Gracias por el espacio

Presentacion

Codigo QR al codigo fuente

Repositorio

Codigo QR al codigo fuente