10. Breve recorrido por la Biblioteca Estándar
**********************************************


10.1. Interfaz del sistema operativo
====================================

El módulo "os" proporciona docenas de funciones para interactuar con
el sistema operativo:

   >>> import os
   >>> os.getcwd()      # Return the current working directory
   'C:\\Python312'
   >>> os.chdir('/server/accesslogs')   # Change current working directory
   >>> os.system('mkdir today')   # Run the command mkdir in the system shell
   0

Asegúrate de utilizar el estilo "import os" en lugar de "from os
import *". Esto evitará que "os.open()" oculte la función integrada
"open()", que funciona de manera muy diferente.

Las funciones integradas "dir()" y "help()" son útiles como ayudas
interactivas para trabajar con módulos grandes como "os":

   >>> import os
   >>> dir(os)
   <returns a list of all module functions>
   >>> help(os)
   <returns an extensive manual page created from the module's docstrings>

Para las tareas diarias de administración de archivos y directorios,
el módulo "shutil" proporciona una interfaz en un nivel superior que
es más fácil de usar:

   >>> import shutil
   >>> shutil.copyfile('data.db', 'archive.db')
   'archive.db'
   >>> shutil.move('/build/executables', 'installdir')
   'installdir'


10.2. Comodines de archivos
===========================

El módulo "glob" proporciona una función para hacer listas de archivos
a partir de búsquedas con comodines en directorios:

   >>> import glob
   >>> glob.glob('*.py')
   ['primes.py', 'random.py', 'quote.py']


10.3. Argumentos de Líneas de Comandos
======================================

Los programas frecuentemente necesitan procesar argumentos de linea de
comandos. Estos argumentos se almacenan en el atributo *argv* del
módulo "sys" como una lista.   Por ejemplo, consideremos el siguiente
archivo :file: 'demo.py':

   # File demo.py
   import sys
   print(sys.argv)

Este es el resultado de ejecutar "python demo.py one two three" en la
línea de comandos:

   ['demo.py', 'one', 'two', 'three']

El modulo "argparse" provee un mecanismo más sofisticado para procesar
argumentos recibidos vía línea de comandos. El siguiente *script*
extrae uno o más nombres de archivos y un número opcional de líneas
para mostrar:

   import argparse

   parser = argparse.ArgumentParser(
       prog='top',
       description='Show top lines from each file')
   parser.add_argument('filenames', nargs='+')
   parser.add_argument('-l', '--lines', type=int, default=10)
   args = parser.parse_args()
   print(args)

Cuando se ejecuta en la línea de comandos con "python top.py --lines=5
alpha.txt beta.txt", el *script* establece "args.lines" a "5" y
"args.filenames" a "['alpha.txt', 'beta.txt']".


10.4. Redirigir la salida de error y finalización del programa
==============================================================

El módulo "sys" también tiene sus atributos para *stdin*, *stdout*, y
*stderr*.  Este último es útil para emitir mensajes de alerta y error
para que se vean incluso cuando se haya redirigido *stdout*:

   >>> sys.stderr.write('Warning, log file not found starting a new one\n')
   Warning, log file not found starting a new one

La forma más directa de terminar un programa es usar "sys.exit()".


10.5. Coincidencia de patrones de cadena
========================================

El módulo "re" provee herramientas de expresiones regulares para un
procesamiento avanzado de cadenas.  Para manipulación y coincidencias
complejas, las expresiones regulares ofrecen soluciones concisas y
optimizadas:

   >>> import re
   >>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
   ['foot', 'fell', 'fastest']
   >>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
   'cat in the hat'

Cuando sólo se necesitan funciones sencillas, se prefieren los métodos
de cadenas porque son más fáciles de leer y depurar:

   >>> 'tea for too'.replace('too', 'two')
   'tea for two'


10.6. Matemáticas
=================

The "math" module gives access to the underlying C library functions
for floating-point math:

   >>> import math
   >>> math.cos(math.pi / 4)
   0.70710678118654757
   >>> math.log(1024, 2)
   10.0

El módulo "random" provee herramientas para realizar selecciones
aleatorias:

   >>> import random
   >>> random.choice(['apple', 'pear', 'banana'])
   'apple'
   >>> random.sample(range(100), 10)   # sampling without replacement
   [30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
   >>> random.random()    # random float
   0.17970987693706186
   >>> random.randrange(6)    # random integer chosen from range(6)
   4

El módulo "statistics" calcula propiedades de estadística básica (la
media, mediana, varianza, etc) de datos numéricos:

   >>> import statistics
   >>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
   >>> statistics.mean(data)
   1.6071428571428572
   >>> statistics.median(data)
   1.25
   >>> statistics.variance(data)
   1.3720238095238095

El proyecto SciPy <https://scipy.org> tiene muchos otros módulos para
cálculos numéricos.


10.7. Acceso a Internet
=======================

Hay varios módulos para acceder a Internet y procesar sus protocolos.
Dos de los más simples son "urllib.request" para traer data de URLs y
"smtplib" para enviar correos:

   >>> from urllib.request import urlopen
   >>> with urlopen('http://worldtimeapi.org/api/timezone/etc/UTC.txt') as response:
   ...     for line in response:
   ...         line = line.decode()             # Convert bytes to a str
   ...         if line.startswith('datetime'):
   ...             print(line.rstrip())         # Remove trailing newline
   ...
   datetime: 2022-01-01T01:36:47.689215+00:00

   >>> import smtplib
   >>> server = smtplib.SMTP('localhost')
   >>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
   ... """To: jcaesar@example.org
   ... From: soothsayer@example.org
   ...
   ... Beware the Ides of March.
   ... """)
   >>> server.quit()

(Nota que el segundo ejemplo necesita un servidor de correo corriendo
en la máquina local)


10.8. Fechas y tiempos
======================

El módulo "datetime" ofrece clases para gestionar fechas y tiempos
tanto de manera simple como compleja.  Aunque soporta aritmética sobre
fechas y tiempos, la aplicación se centra en la extracción eficiente
de elementos para el formateo y la manipulación de los datos de
salida.  El módulo también admite objetos que tienen en cuenta la zona
horaria.

   >>> # dates are easily constructed and formatted
   >>> from datetime import date
   >>> now = date.today()
   >>> now
   datetime.date(2003, 12, 2)
   >>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
   '12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'

   >>> # dates support calendar arithmetic
   >>> birthday = date(1964, 7, 31)
   >>> age = now - birthday
   >>> age.days
   14368


10.9. Compresión de datos
=========================

Los módulos admiten directamente los formatos más comunes de archivo y
compresión de datos, entre ellos : "zlib", "gzip", "bz2", "lzma",
"zipfile" y "tarfile".

   >>> import zlib
   >>> s = b'witch which has which witches wrist watch'
   >>> len(s)
   41
   >>> t = zlib.compress(s)
   >>> len(t)
   37
   >>> zlib.decompress(t)
   b'witch which has which witches wrist watch'
   >>> zlib.crc32(s)
   226805979


10.10. Medición de rendimiento
==============================

Algunos usuarios de Python desarrollan un profundo interés en conocer
el rendimiento relativo de las diferentes soluciones al mismo
problema.  Python provee una herramienta de medición que responde
inmediatamente a esas preguntas.

Por ejemplo, puede ser tentador usar la característica de empaquetado
y desempaquetado de las tuplas en lugar de la solución tradicional
para intercambiar argumentos.  El módulo "timeit" muestra rápidamente
una ligera ventaja de rendimiento:

   >>> from timeit import Timer
   >>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
   0.57535828626024577
   >>> Timer('a,b = b,a', 'a=1; b=2').timeit()
   0.54962537085770791

En contraste con el fino nivel de medición del módulo "timeit", los
módulos "profile" y "pstats" proveen herramientas para identificar
secciones críticas de tiempo en bloques de código más grandes.


10.11. Control de calidad
=========================

Una forma para desarrollar software de alta calidad consiste en
escribir pruebas para cada función mientras se desarrolla y correr
esas pruebas frecuentemente durante el proceso de desarrollo.

El módulo "doctest" provee una herramienta para revisar un módulo y
validar las pruebas integradas en las cadenas de documentación (o
*docstring*) del programa.  La construcción de las pruebas es tan
sencillo como cortar y pegar una ejecución típica junto con sus
resultados en los docstrings.  Esto mejora la documentación al proveer
al usuario un ejemplo y permite que el módulo *doctest* se asegure que
el código permanece fiel a la documentación:

   def average(values):
       """Computes the arithmetic mean of a list of numbers.

       >>> print(average([20, 30, 70]))
       40.0
       """
       return sum(values) / len(values)

   import doctest
   doctest.testmod()   # automatically validate the embedded tests

El módulo "unittest" no es tan sencillo como el módulo "doctest", pero
permite mantener un conjunto más completo de pruebas en un archivo
independiente:

   import unittest

   class TestStatisticalFunctions(unittest.TestCase):

       def test_average(self):
           self.assertEqual(average([20, 30, 70]), 40.0)
           self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
           with self.assertRaises(ZeroDivisionError):
               average([])
           with self.assertRaises(TypeError):
               average(20, 30, 70)

   unittest.main()  # Calling from the command line invokes all tests


10.12. Pilas incluidas
======================

Python tiene una filosofía de "pilas incluidas".  Esto se ve mejor en
las capacidades robustas y sofisticadas de sus paquetes más grandes.
Por ejemplo:

* Los módulos "xmlrpc.client" y "xmlrpc.server" convierten la
  implementación de llamadas a procedimientos remotos en una tarea
  casi trivial.  A pesar de los nombres de los módulos, no se necesita
  ningún conocimiento o manejo directo de XML.

* El paquete "email" es una biblioteca para administrar mensajes de
  correo electrónico, incluidos MIME y otros documentos de mensajes
  basados en **RFC 2822**. A diferencia de "smtplib" y "poplib" que
  realmente envían y reciben mensajes, el paquete de correo
  electrónico tiene un conjunto de herramientas completo para crear o
  decodificar estructuras de mensajes complejas (incluidos los
  archivos adjuntos) y para implementar protocolos de codificación y
  encabezado de Internet.

* El paquete "json" proporciona un sólido soporte para analizar este
  popular formato de intercambio de datos.  El módulo "csv" permite la
  lectura y escritura directa de archivos en formato de valor separado
  por comas, comúnmente compatible con bases de datos y hojas de
  cálculo.  El procesamiento XML es compatible con los paquetes
  "xml.etree.ElementTree", "xml.dom" y "xml.sax". Juntos, estos
  módulos y paquetes simplifican en gran medida el intercambio de
  datos entre aplicaciones de Python y otras herramientas.

* El módulo "sqlite3" es un wrapper de la biblioteca de bases de datos
  SQLite, proporciona una base de datos constante que se puede
  actualizar y a la que se puede acceder utilizando una sintaxis SQL
  ligeramente no estándar.

* La internacionalización es compatible con una serie de módulos,
  incluyendo "gettext", "locale", y el paquete "codecs".
