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# 30 Días de Python: Día 17 - Manejo de excepciones
- [Día 17](#-día-17)
- [Manejo de excepciones](#manejo-de-excepciones)
- [Empacar y desempacar parámetros en Python](#empacar-y-desempacar-parámetros-en-python)
- [Desempaquetado](#desempaquetado)
- [Desempaquetar listas](#desempaquetar-listas)
- [Desempaquetar diccionarios](#desempaquetar-diccionarios)
- [Empaquetado](#empaquetado)
- [Empaquetar listas](#empaquetar-listas)
- [Empaquetar diccionarios](#empaquetar-diccionarios)
- [Expandir en Python](#expandir-en-python)
- [Enumerar (enumerate)](#enumerar-enumerate)
- [Zip](#zip)
- [Ejercicios: Día 17](#ejercicios-día-17)
# 📘 Día 17
## Manejo de excepciones
Python utiliza _try_ y _except_ para manejar errores de forma elegante. Salir de forma controlada (o manejar errores con elegancia) es una buena práctica: el programa detecta una condición de error y la maneja adecuadamente, normalmente mostrando un mensaje descriptivo en la terminal o en un registro. Las excepciones suelen deberse a factores externos al programa (entrada errónea, nombre de archivo incorrecto, archivo no encontrado, fallos de I/O, etc.). El manejo adecuado de excepciones evita que las aplicaciones se bloqueen.
En la sección anterior hemos cubierto los distintos tipos de errores en Python. Si usamos _try_ y _except_ correctamente, podemos impedir que esos errores hagan que el programa falle.

```py
try:
# si todo va bien, se ejecuta el código en este bloque
except:
# si ocurre un error, se ejecuta el código en este bloque
```
**Ejemplo:**
```py
try:
print(10 + '5')
except:
print('Ocurrió un error')
```
En el ejemplo anterior, el segundo operando es una cadena. Podemos convertirlo a int o float para sumarlo a un número; si no lo hacemos, se ejecutará el bloque _except_.
**Ejemplo:**
```py
try:
name = input('Introduce tu nombre:')
year_born = input('¿En qué año naciste?:')
age = 2019 - year_born
print(f'Eres {name}. Tu edad es {age}.')
except:
print('Ocurrió un error')
```
```sh
Ocurrió un error
```
En el ejemplo anterior, se ejecuta el bloque de excepción, pero no sabemos exactamente qué pasó. Para identificar el problema podemos capturar tipos de excepción concretos.
En el siguiente ejemplo capturamos y mostramos el tipo de error:
```py
try:
name = input('Introduce tu nombre:')
year_born = input('¿En qué año naciste?:')
age = 2019 - year_born
print(f'Eres {name}. Tu edad es {age}.')
except TypeError:
print('Se produjo un error de tipo (TypeError)')
except ValueError:
print('Se produjo un ValueError')
except ZeroDivisionError:
print('Se produjo una división por cero (ZeroDivisionError)')
```
```sh
Introduce tu nombre:Asabeneh
¿En qué año naciste?:1920
Se produjo un error de tipo (TypeError)
```
En el ejemplo anterior la salida será _TypeError_. Ahora añadamos bloques adicionales:
```py
try:
name = input('Introduce tu nombre:')
year_born = input('¿En qué año naciste?:')
age = 2019 - int(year_born)
print(f'Eres {name}. Tu edad es {age}.')
except TypeError:
print('Se produjo un error de tipo (TypeError)')
except ValueError:
print('Se produjo un ValueError')
except ZeroDivisionError:
print('Se produjo una división por cero (ZeroDivisionError)')
else:
print('Este bloque se ejecuta normalmente después de try')
finally:
print('Este bloque siempre se ejecuta.')
```
```sh
Introduce tu nombre:Asabeneh
¿En qué año naciste?:1920
Eres Asabeneh. Tu edad es 99.
Este bloque se ejecuta normalmente después de try
Este bloque siempre se ejecuta.
```
También podemos simplificar el manejo de excepción así:
```py
try:
name = input('Introduce tu nombre:')
year_born = input('¿En qué año naciste?:')
age = 2019 - int(year_born)
print(f'Eres {name}. Tu edad es {age}.')
except Exception as e:
print(e)
```
## Empacar y desempacar parámetros en Python
Usamos dos operadores:
- * para tuplas/listas
- ** para diccionarios
Veamos un ejemplo. Supongamos que una función acepta parámetros separados, pero nosotros tenemos una lista. Podemos desempaquetarla y convertirla en argumentos.
### Desempaquetado
#### Desempaquetar listas
```py
def sum_of_five_nums(a, b, c, d, e):
return a + b + c + d + e
lst = [1, 2, 3, 4, 5]
print(sum_of_five_nums(lst)) # TypeError: sum_of_five_nums() missing 4 required positional arguments: 'b', 'c', 'd', and 'e'
```
Al ejecutar lo anterior ocurre un error porque la función espera números separados, no una lista. Desempaquetemos la lista:
```py
def sum_of_five_nums(a, b, c, d, e):
return a + b + c + d + e
lst = [1, 2, 3, 4, 5]
print(sum_of_five_nums(*lst)) # 15
```
También podemos usar desempaquetado con range(), que acepta inicio y fin:
```py
numbers = range(2, 7) # llamada normal con parámetros separados
print(list(numbers)) # [2, 3, 4, 5, 6]
args = [2, 7]
numbers = range(*args) # llamada usando los parámetros desempaquetados desde la lista
print(list(numbers)) # [2, 3, 4, 5, 6]
```
También podemos usar desempaquetado en asignaciones:
```py
countries = ['Finland', 'Sweden', 'Norway', 'Denmark', 'Iceland']
fin, sw, nor, *rest = countries
print(fin, sw, nor, rest) # Finland Sweden Norway ['Denmark', 'Iceland']
numbers = [1, 2, 3, 4, 5, 6, 7]
one, *middle, last = numbers
print(one, middle, last) # 1 [2, 3, 4, 5, 6] 7
```
#### Desempaquetar diccionarios
```py
def unpacking_person_info(name, country, city, age):
return f'{name} vive en {city}, {country}. Tiene {age} años.'
dct = {'name':'Asabeneh', 'country':'Finland', 'city':'Helsinki', 'age':250}
print(unpacking_person_info(**dct)) # Asabeneh vive en Helsinki, Finland. Tiene 250 años.
```
### Empaquetado
A veces no sabemos cuántos argumentos nos pasarán a una función. Podemos usar empaquetado para aceptar un número variable de argumentos.
### Empaquetar listas
```py
def sum_all(*args):
s = 0
for i in args:
s += i
return s
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5, 6, 7)) # 28
```
#### Empaquetar diccionarios
```py
def packing_person_info(**kwargs):
# comprobar el tipo de kwargs: es un dict
# print(type(kwargs))
# imprimir los pares clave-valor
for key in kwargs:
print(f"{key} = {kwargs[key]}")
return kwargs
print(packing_person_info(name="Asabeneh",
country="Finland", city="Helsinki", age=250))
```
```sh
name = Asabeneh
country = Finland
city = Helsinki
age = 250
{'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
```
## Expandir en Python
Al igual que en JavaScript, Python permite expandir listas usando el operador *. Veámoslo:
```py
lst_one = [1, 2, 3]
lst_two = [4, 5, 6, 7]
lst = [0, *lst_one, *lst_two]
print(lst) # [0, 1, 2, 3, 4, 5, 6, 7]
```
## Enumerar (enumerate)
Si necesitamos los índices de una lista, usamos la función integrada enumerate.
```py
for index, item in enumerate([20, 30, 40]):
print(index, item)
```
```py
for index, i in enumerate(countries):
print('hola')
if i == 'Finland':
print(f'El país {i} está en el índice {index}')
```
```sh
0 20
1 30
2 40
```
## Zip
A veces necesitamos combinar listas. Observa el ejemplo:
```py
fruits = ['banana', 'orange', 'mango', 'lemon', 'lime']
vegetables = ['Tomato', 'Potato', 'Cabbage','Onion', 'Carrot']
fruits_and_veges = []
for f, v in zip(fruits, vegetables):
fruits_and_veges.append({'fruit':f, 'veg':v})
print(fruits_and_veges)
```
```sh
[{'fruit': 'banana', 'veg': 'Tomato'}, {'fruit': 'orange', 'veg': 'Potato'}, {'fruit': 'mango', 'veg': 'Cabbage'}, {'fruit': 'lemon', 'veg': 'Onion'}, {'fruit': 'lime', 'veg': 'Carrot'}]
```
## Ejercicios: Día 17
1. Crea en _countries.py_ funciones que usen los datos de _countries_data.py_:
- una función para encontrar los 10 idiomas más usados
- una función para encontrar los 10 países más poblados
🎉 ¡Felicidades! 🎉
[<< Día 16](./16_python_datetime_sp.md) | [Día 18 >>](./18_regular_expressions_sp.md)