summaryrefslogtreecommitdiff
path: root/es/08_stdlib.md
blob: fbaa9740f64ae29b19c6463392ab6eb205ce1801 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# La librería estándar

La librería estándar se refiere a todas las utilidades que un lenguaje de
programación trae consigo. Los lenguajes de programación, a parte de aportar la
propia funcionalidad del lenguaje en sí mismo que simplemente sería la
ejecución del código fuente que se le indique, suelen incluir funcionalidades
que no están necesariamente relacionadas con ese proceso.

El motivo de esto es facilitar el uso del lenguaje para las labores más
comunes, incluyendo el código necesario para realizarlas sin necesitar añadidos
externos.

En lenguajes de programación de dominio específico la librería estándar suele
contemplar muchos casos de ese dominio concreto. Por ejemplo, el lenguaje de
programación Julia, aunque esté diseñado con el objetivo de ser un lenguaje
válido para cualquier uso, su área de trabajo se centra en el entorno
científico. Es por eso que incluye en su librería estándar paquetes de álgebra
lineal, estadística y otros.

Existen muchas diferentes aproximaciones a la librería estándar. Algunos
lenguajes las mantienen extremadamente reducidas con el fin de que la
implementación del lenguaje sea más liviana, con la contrapartida de forzar a
quien los use a tener que utilizar herramientas externas o a desarrollarlas.

Python es un lenguaje de propósito general con una extensísima librería
estándar. Esto dificulta la selección de apartados a mostrar en este capítulo,
pero facilita la programación de cualquier aplicación en éste lenguaje.

Los paquetes estándar de python facilitan la lectura de infinidad de tipos de
fichero, la conversión y el tratamiento de datos, el acceso a la red, la
ejecución concurrente, etc. por lo que librería estándar es más que suficiente
para muchas aplicaciones y no se requiere añadir módulos externos.

Conocer la librería estándar y ser capaz de buscar en ella los paquetes que
necesites te facilitará mucho la tarea, evitando, por un lado, que dediques
tiempo a desarrollar funcionalidades que el propio lenguaje ya aporta y, por
otro, que instales paquetes externos que no necesitas.

Todos los apartados aquí listados están extremadamente bien documentados en la
página oficial de la documentación de python y en la propia ayuda. Eso sí,
tendrás que importarlos para poder leer la ayuda, pero ya sabes cómo se hace.

A continuación se recogen los módulos más interesantes, aunque en función del
proyecto puede que necesites algún otro. Puedes acceder al listado completo en
la página oficial de la documentación[^stdlibdoc].

[^stdlibdoc]: <https://docs.python.org/3/library/index.html#library-index>


## Interfaz al sistema operativo: `os`

Ya definimos previamente el concepto *interfaz* como superficie de contacto
entre dos entidades. Esta librería facilita la interacción entre python y el
sistema operativo.

La comunicación con el sistema operativo es primordial para cualquier lenguaje
de programación de uso general, ya que es necesario tener la capacidad de hacer
peticiones directas al sistema operativo. Por ejemplo, cambiar de directorio
actual para facilitar la inclusión rutas relativas en el programa, resolver
rutas a directorios y un largo etc.

En capítulos previos hemos hablado de las diferencias entre sistemas
operativos. Esta librería, además, facilita el trabajo para esos casos. Por
ejemplo, que el separador de directorios en UNIX es `/` y en Windows `\`, si
quisiéramos programar una aplicación multiplataforma, nos encontraríamos con
problemas. Sin embargo, el módulo `os.path` dispone de herramientas para
gestionar las rutas de los directorios por nosotros, por ejemplo, la variable
`os.path.sep` (copiada en `os.sep` por abreviar), guarda el valor del separador
del sistema en el que se esté ejecutando la aplicación: `/` en UNIX y `\` en
Windows.

Este paquete es muy interesante para desarrollar código portable entre las
diferentes plataformas.

## Funciones relacionadas con el intérprete: `sys`

Aunque el nombre de este módulo suene complicado, su uso principal es el de
acceder a funcionalidades que el propio python controla. Concretamente, se usa
sobre todo para la recepción de argumentos de entrada al programa principal,
la redirección de entradas y salidas del programa y la terminación del
programa.

### Salida forzada: `sys.exit()`

Para salir de forma abrupta del programa y terminar su ejecución, python
facilita la función `sys.exit()`. Al ejecutarla la 

### *Standard streams*: `sys.stdin`, `sys.stdout` y `sys.stderr`

Cuando se trabaja en programas que funcionan en la terminal se pueden describir
tres vías de comunicación con el usuario:

1. El teclado: de donde se obtiene lo que el usuario teclee mediante la función
   `input`.
2. La pantalla: a donde se escribe al ejecutar la función `print`.
3. Y la salida de errores: Una salida especial para los fallos, similar a la
   anterior, pero que se diferencia para poder hacer un tratamiento distinto y
   porque tiene ciertas peculiaridades distintas. Los mensajes de error de
   excepciones se envían aquí.

Estas tres vías se conocen comúnmente como entrada estándar (*standard input*),
`stdin`, salida estándar (*standard output*), `stdout`, y error estándar
(*standard error*), `stderr`. Este concepto responde al nombre de *standard
streams* y es una abstracción de los dispositivos físicos que antiguamente se
utilizaban para comunicarse con una computadora. Hoy en día, estos tres
*streams* son una abstracción de esa infraestructura y se comportan como
simples ficheros de lectura en el primer caso y de escritura en los otros dos.

Los diferentes sistemas operativos los implementan a su modo, pero desde el
interior de python son simplemente ficheros abiertos, como si se hubiese
ejecutado la función `open` en ellos y ellos se encargan de leer o escribir a
la vía de interacción con el usuario correspondiente. Es decir, en realidad
`print`, `input`, etc. son únicamente funciones que facilitan la labor de
escribir manualmente en estos *streams*:

``` python
>>> import sys
>>> chars = sys.stdout.write("Hola\n")
Hola
>>> chars     # Recoge el número de caracteres escritos
5
```

La realidad es que estos *streams* dan una flexibilidad adicional muy
interesante. Como son únicamente variables de ficheros abiertos pueden
cerrarse y sustituirse por otros, permitiéndote redireccionar la entrada o la
salida de un programa a un fichero.

El siguiente ejemplo redirecciona la salida de errores a un fichero llamado
`exceptions.txt` y trata de mostrar una variable que no está definida. Python
en lugar de mostrar el mensaje de una excepción, la escribe en el fichero al
que se ha redireccionado la salida:

``` python
>>> sys.stderr = open("exceptions.txt", "w")
>>> aasda   # No muestra el mensaje de error
>>>
>>> with open("exceptions.txt") as f:
...     f.read()    # Muestra el contenido del archivo
... 
'Traceback (most recent call last):\n  File "<stdin>", line 1, in \
<module>\nNameError: name \'aasda\' is not defined\n'
```


### Argumentos de entrada: `sys.argv`

Es posible añadir argumentos de entrada a la ejecución de los programas. Piensa
en el propio programa llamado python, al ejecutarlo en la shell de sistema se
le pueden mandar diferentes opciones que, por ejemplo, digan qué módulo debe
ejecutar:

``` bash
python test.py
```

Para la shell de sistema, todo lo que se escriba después de la primera palabra
es considerado un argumento de entrada.

Cuando se ejecutan nuestros programas escritos en python, es posible también
enviarles argumentos de entrada:

``` bash
python test.py argumento1 argumento2 ...
```

Lo que el python reciba después del nombre del módulo a ejecutar lo considerará
argumentos de entrada de nuestro módulo y nos lo ordenará y dejará disponible
en la variable `sys.argv`, una lista de todos los argumentos de entrada.

Si muestras el contenido de la variable en la REPL, te responderá `['']` ya que
la REPL se ejecuta sin argumentos. Sin embargo, si creas un módulo y le añades
este contenido:

``` python
import sys
print(sys.argv)
```

Verás que se imprime una lista con el nombre del archivo en su primer elemento.

Si ejecutas el módulo desde la shell de sistema añadiéndole argumentos de
entrada:

``` bash
python modulo.py arg1 arg2 arg3
```

La lista `sys.argv` recibirá todos, siempre a modo de string.

Los argumentos de entrada son extremadamente interesantes para permitir que los
programas sean configurables por quien los use sin necesidad de tener que
editar el código fuente, cosa que nunca debería ser necesaria a menos que
exista un error en éste o quiera añadirse una funcionalidad.

## Procesamiento de argumentos de entrada: `argparse`

Como la variable `sys.argv` entrega los argumentos de entrada tal y como los
recibe y no comprueba si son coherentes, python dispone de una librería
adicional para estas labores. El módulo `argparse` permite definir qué tipo de
argumentos de entrada y opciones tiene tu programa y qué reglas deben seguir.
Además, facilita la creación de ayudas como la que se muestra cuando ejecutas
`python -h` o `pip -h` en la shell de tu sistema.

Es una librería bastante compleja con infinidad de opciones que es mejor que
leas en la propia documentación cuando necesites utilizarla.

## Expresiones regulares: `re`

Las expresiones regulares (*regular expression*, también conocidas como
*regexp* y *regex*) son secuencias de caracteres que describen un patrón de
búsqueda.

En python se soportan mediante el módulo `re` de la librería estándar.

## Matemáticas y estadística: `math` y `statistics`

El módulo `math` soporta gran cantidad de operaciones matemáticas avanzadas
para coma flotante. En él puedes encontrar logaritmos, raíces, etc.

El módulo `statistics` soporta estadística básica como medias, medianas,
desviación típica, etc.

Ambos módulos tienen mucho interés ya que python se usa extensivamente en el
análisis de datos. Aunque tiene librerías de terceros mucho más adecuadas para
esta labor, para proyectos pequeños puede que sea suficiente con estos módulos.

## Protocolos de internet: `urllib`

`urllib` es un conjunto de paquetes que permiten seguir URLs o enlaces,
principalmente para HTTP y su versión segura HTTPs. Soporta cookies,
redirecciones, autenticación básica, etc.

El siguiente ejemplo te muestra cómo descargar el primer boceto del estándar
del protocolo HTTP de la página web del IETF. Recordando los apartados previos,
fíjate en el uso de la sentencia `with` y en el uso de los corchetes para
obtener un número limitado de caracteres de la recién decodificada respuesta.

``` python
>>> from urllib.request import urlopen
>>> with urlopen("https://tools.ietf.org/rfc/rfc2068.txt") as resp:
...     print( resp.read().decode("utf-8")[:1750] )
... 
'





Network Working Group                                      R. Fielding
Request for Comments: 2068                                   UC Irvine
Category: Standards Track                                    J. Gettys
                                                              J. Mogul
                                                                   DEC
                                                            H. Frystyk
                                                        T. Berners-Lee
                                                               MIT/LCS
                                                          January 1997


                Hypertext Transfer Protocol -- HTTP/1.1

Status of this Memo

   This document specifies an Internet standards track protocol for the
   Internet community, and requests discussion and suggestions for
   improvements.  Please refer to the current edition of the "Internet
   Official Protocol Standards" (STD 1) for the standardization state
   and status of this protocol.  Distribution of this memo is unlimited.

Abstract

   The Hypertext Transfer Protocol (HTTP) is an application-level
   protocol for distributed, collaborative, hypermedia information
   systems. It is a generic, stateless, object-oriented protocol which
   can be used for many tasks, such as name servers and distributed
   object management systems, through extension of its request methods.
   A feature of HTTP is the typing and negotiation of data
   representation, allowing systems to be built independently of the
   data being transferred.

   HTTP has been in use by the World-Wide Web global information
   initiative since 1990. This specification defines the protocol
   referred to as "HTTP/1.1".

'
>>>
```

## Fechas y horas: `datetime`

`datetime`, que ya ha aparecido anteriormente, es un módulo para gestión de
fecha y hora. `datetime` soporta gran cantidad de operaciones y tipos de dato.
Entre ellos los `timedeltas`, diferencias temporales que te permiten sumar y
restar fechas con facilidad con los operadores habituales.

Con las facilidades de `datetime`, es poco probable que necesites importar una
librería de gestión de fecha y hora independiente.

## Procesamiento de ficheros: `json` y `sqlite3`

Python habilita gran cantidad de procesadores de formatos de fichero, los dos
que se lista en este apartado tienen especial interés.

El primer módulo, `json`, sirve para manipular datos en formato JSON. Sus dos
funciones principales `dumps` y `loads` vuelcan o cargan datos de JSON a
diccionarios o listas en una sola orden debido que la propia estructura de JSON
está formada por parejas clave valor o listas de valores ordenadas por índices.
Esta es la razón por la que en muchas ocasiones se utilizan ficheros de formato
JSON para intercambiar información entre aplicaciones de python: su lectura y
escritura es extremadamente sencilla.

El segundo módulo, `sqlite3`, facilita el acceso a ficheros en formato SQLite3,
un formato binario con una interfaz de acceso que permite consultas SQL. El
módulo `sqlite3` es capaz de convertir las tablas que SQLite3 retorna a
estructuras de python de forma transparente y cómoda por lo que es un aliado
interesante para aplicaciones que requieren una base de datos pequeña y
resiliente.

## Aritmética de coma flotante decimal: `decimal`

En el apartado sobre datos tratamos la complejidad de los números de coma
flotante y que su representación binaria puede dar lugar a problemas. Este
módulo de aritmética decimal aporta una solución rigurosa a este problema con
el fin de facilitar el uso de python en entornos que requieren precisión
estricta que incluso puede requerir cumplir con normativas, como puede ser la
banca.

La documentación del módulo muestra un par de ejemplos muy interesantes usando
la clase `Decimal` aportada por este. Se adjuntan a continuación para que los
estudies y los disecciones en busca de las diferencias con el uso de los
números de coma flotante normales:

``` python
>>> from decimal import *
>>> round(Decimal('0.70') * Decimal('1.05'), 2)
Decimal('0.74')
>>> round(.70 * 1.05, 2)
0.73

>>> Decimal('1.00') % Decimal('.10')
Decimal('0.00')
>>> 1.00 % 0.10
0.09999999999999995

>>> sum([Decimal('0.1')]*10) == Decimal('1.0')
True
>>> sum([0.1]*10) == 1.0
False
```

## Lo que has aprendido

Más que aprender, en este apartado has sobrevolado la librería estándar de
python desde la distancia y te has parado a observar qué problemas comunes ya
están resueltos en python.

La realidad es que la librería estándar es mucho más extensa que lo listado en
este apartado, pero aquí se han mencionado los módulos que más frecuentemente
se suelen usar en entornos normales y algunos otros que tienen interés a la
hora de afianzar conocimiento que has obtenido en capítulos previos, como es el
caso del módulo `decimal`.

Este capítulo empieza a mostrarte el interés de programar en python y las
posibilidades que tienes con él, únicamente con la librería estándar. En el
próximo verás la cantidad de funcionalidad adicional que le puedes añadir con
un par de librerías escritas por terceros.

Sirva también este capítulo como recordatorio de lo extensa que es la librería
estándar de python. En el futuro, cuando tengas intención de buscar una
librería para resolver un problema que te despista de trabajar en la
funcionalidad principal de tu aplicación, empieza por la librería estándar.