summaryrefslogtreecommitdiff
path: root/src/03_estructura.md
blob: caadfb96b482ba1c3b7f0e8898782717bc920aca (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
# Estructura del lenguaje

Aunque ya sabes usar python de forma sencilla, aún no hemos tratado el
comportamiento del lenguaje y cómo se estructura su sintaxis más allá de varios
ejemplos sencillos y planos. En este apartado trataremos la estructura y las
diferentes formas de controlar el flujo del programa.

Como en la mayor parte de lenguajes de programación conocidos, python ejecuta
las órdenes de arriba a abajo, línea por línea.

Para demostrarlo, prueba a abrir un nuevo fichero, llenarlo con este contenido
y ejecutarlo (`F5`).

``` python
print("Esta línea va primero")
print("Esta línea va segundo")
print("Esta línea va tercero")
print("Esta línea va cuarto")
```

Verás que el resultado del programa es siempre el mismo para todas las veces
que lo ejecutes y siempre salen los resultados en el mismo orden.

Para poder alterar el orden de los comandos, o elegir en función de una
condición cuales se ejecutan, python dispone de unas estructuras. Pero, antes
de contarte cuales son, te adelanto su estructura. Normalmente se declaran en
una línea terminada en `:` y su cuerpo se sangra hacia dentro. La sangría o
(indentación si lo calcamos del inglés[^indent]) es lo que define dónde empieza
o termina un *bloque* en python. Las líneas consecutivas sangradas al mismo
nivel se consideran el mismo *bloque*.

#### Bloques

Los *bloques* de código son conjuntos de órdenes que pertenecen al mismo
contexto. Sirven para delimitar zonas del programa, cuerpos de sentencias, etc.

- Puedes comenzar nuevos bloques incrementando el nivel de sangría.
- Los bloques pueden contener otros bloques.
- Los bloques terminan cuando el sangrado disminuye.

Es **muy importante** sangrar los bloques correctamente, usando una sangría
coherente. Puedes usar dos espacios, el tabulador, cuatro espacios o lo que
desees, pero elijas lo que elijas debe ser coherente en todo el documento.
IDLE y los editores de código en general puede configurarse para usar una
anchura de indentación concreta, que se insertará cuando pulses la tecla
tabulador. El estándar de python es cuatro espacios.

[^indent]: <https://en.wikipedia.org/wiki/Indentation_(typesetting)>

## Sintaxis general

La sintaxis de python es sencilla en su concepción pero ha ido complicándose a
medida que el lenguaje ha ido creciendo. En este apartado únicamente se
mencionan los puntos más comunes de la sintaxis, dejando para futuros apartados
los detalles específicos de conceptos que aún no se han explicado.

### Comentarios

Los comentarios son *fundamentales* en el código fuente. El intérprete los
ignora pero son primordiales para explicar detalles de nuestro código a otros
programadores o a nosotros mismos en el futuro. Comentar bien el código fuente
es un arte en sí mismo.

Los comentarios en python se introducen con el símbolo `#`. Desde su aparición
hasta el final de la línea se considera un comentario y python lo descarta.
Pueden iniciarse a mitad de línea o en el inicio, tal y como se muestra a
continuación:

``` python
# En este ejemplo se muestran comentarios, como este mismo
print("Hola") # Esto es otro comentario
```

### Control de flujo

Como ya se ha adelantado, es posible cambiar el orden de ejecución del programa
en función de unas normas o evitar que el programa ejecute ciertas sentencias.
A esto se le conoce como *control de flujo*.

#### Condicionales

Las condicionales son herramientas de *control de flujo* que permiten separar
la ejecución en diferentes ramas en función de unas condiciones. En python sólo
existe el condicional `if` (si, en castellano), aunque existen otras
estructuras para conseguir el mismo efecto, no las trataremos aún.

Ésta es la sintaxis del `if`:

``` python
if condición:
    # Este bloque se ejecuta si la condición se cumple
elif condiciónN:
    # Este bloque (opcional) se ejecuta si las condiciones previas no se
    # cumplen y la condiciónN sí se cumple
else:
    # Este bloque (opcional) se ejecuta si todas las condiciones previas no
    # se cumplen
```

Tal y como se muestra en el ejemplo, los bloques `elif` y el bloque `else` son
opcionales. Es posible, y muy común además, hacer un `if` únicamente con el
apartado inicial.

Si te preguntas qué condiciones debes usar, es tan simple como usar sentencias
de python cuyo resultado sea `True` o `False`. Cuando la sentencia resulte en
un `True` la condición se cumplirá y el bloque interior se ejecutará.

En resumen, el *if* ejecuta el bloque *si* la condición se cumple.

#### Bucles

Existen dos tipos de sentencia para hacer repeticiones en python, ambas son
similares al `if`, pero en lugar de elegir si una pieza de código se ejecuta o
no, lo que deciden es si es necesario repetirla en función de una condición.

##### While

El `while` (mientras que) es la más sencilla de estas estructuras, y la menos
usada.

``` python 
while condición:
    # Este bloque se ejecutará siempre que la condición se considere verdadera
```

El `while` comprueba la condición en primer lugar, si resulta en `True` ejecuta
el bloque interno y vuelve a comprobar la condición. Si es `True`, ejecuta el
bloque de nuevo, y así sucesivamente.

Es decir, ejecuta el bloque *mientras que* la condición se cumple.

##### For

Los bucles *for* (para) son los más complejos y más usados,

```
for preparación:
    # Bloque a repetir si la preparación funciona con el contexto creado por la
    # preparación
else:
    # Bloque (opcional) a ejecutar si el bloque cuerpo no termina de forma
    # abrupta con un `break`
```

No te preocupes ahora mismo por el `else`, ya que se suele considerar python
avanzado y no suele usarse. Más adelante en este capítulo analizaremos un
ejemplo.

En lo que a la preparación se refiere, el `for` es relativamente peculiar,
sirve para ejecutar el primer bloque para un contexto concreto, el creado por
una sentencia de preparación. Si la preparación falla el bucle se rompe.

El uso más común del `for` es el de iterar en secuencias gracias al operador
`in` que mencionamos anteriormente pero que en este caso toma un uso distinto:

```
>>> for i in [0,1,2,3]:
...     i+2
... 
2
3
4
5
```

Como puedes ver, el bloque interno `i+2` se ejecuta en cuatro ocasiones,
cambiando el valor de `i` a los valores internos de la lista `[0,1,2,3]`.
Cuando la lista termina, la preparación falla porque no quedan elementos y el
bucle se rompe.

Este último ejemplo es una receta de amplio uso que te aconsejo memorizar.


#### Truthy and Falsey

En este tipo de sentencias donde se comprueba si una condición es verdadera o
falsa, python automáticamente trata de convertir el resultado a Boolean usando
la función `bool` que ya conoces del apartado sobre tipos. No es necesario que
conviertas a Boolean manualmente ya que estas sentencias disponen de una
conversión implícita a Boolean[^truthy].

Por tanto, cualquier resultado que tras pasar por la función `bool` dé como
resultado `True` será considerado verdadero y viceversa. A estos valores se les
conoce habitualmente como *truthy* y *falsey* porque no son `True` o `False`
pero se comportan como si lo fueran. Algunos ejemplos curiosos:

```
>>> bool([])
False
>>> bool(None)
False
>>> bool("")
False
>>> bool(" ")
True
>>> bool([None])
True
```

Es relativamente sencillo prever qué valores son *truthy* o *falsey*,
normalmente los valores que representan un vacío se consideran `False`.

[^truthy]:
  <https://docs.python.org/3/library/stdtypes.html#truth-value-testing>


### List comprehensions

Una de las excepciones sintácticas que sí que podemos explicar en este momento,
en el que ya sabes hacer bucles, son las *list comprehensions*. Python dispone
de un sistema para crear secuencias y transformarlas muy similar a la notación
de construcción de sets de las matemáticas[^set-notation].

Como mejor se entiende es con unos ejemplos, en este caso vamos usar la función
`range` para crear una lista de números del `0` (inclusive) al `10` (no
inclusive). Usando la ayuda puedes saber más sobre la función `range`.

```
>>> [i**2 for i in range(0, 10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> tuple(i**2 for i in range(0, 10))
(0, 1, 4, 9, 16, 25, 36, 49, 64, 81)
>>> { str(i): i**2 for i in range(0, 10)}
{'0': 0, '1': 1, '2': 4, '3': 9, '4': 16, '5': 25, '6': 36, '7': 49, '8': 64,
'9': 81}

>>> [i**2 for i in range(0, 10) if i > 5 ]
[36, 49, 64, 81]
```

Como ves, en el caso de los diccionarios es necesario crear las claves también.
En este caso las creamos convirtiendo el propio número a string con la función
`str`.

Como ves en los primeros ejemplos, de una secuencia de números hemos creado una
secuencia de números al cuadrado. Pero las *list comprehensions* son más
poderosas que eso, pudiendo a llegar a complicarse sobremanera añadiendo
condiciones, como en el último de los ejemplos, para filtrar algunos casos.

Te habrá mosqueado el uso de `tuple` para crear la tupla. Todo tiene una razón,
la tupla, al estar formada por paréntesis, python no tiene claro si son
paréntesis de precedencia o de creación de tupla, y considera que son los
primeros, dando como resultado un generador, un paso intermedio de nuestro
proceso que dejamos para el futuro.

```
>>> (i**2 for i in range(0, 10))
<generator object <genexpr> at 0x7f779d9b2d58>
```

[^set-notation]: <https://en.wikipedia.org/wiki/Set-builder_notation>

### Excepciones

TODO

### Funciones

TODO


### Sentencias útiles

Python dispone de un conjunto de sentencias que pueden facilitar y flexibilizar
mucho el uso de las estructuras que acabamos de visitar.

#### Pass

`pass` es una sentencia vacía, que no ejecuta nada. Es necesaria debido a las
normas de sangría de python. Si construyes un bloque y no quieres rellenarlo
por la razón que sea, debes usar `pass` en su interior porque, si no lo haces y
simplemente lo dejas vacío, la sintaxis será incorrecta y python lanzará una
excepción grave diciéndote que esperaba un bloque con sangría y no se lo diste.

```
>>> if True:
... 
  File "<stdin>", line 2
    
    ^
IndentationError: expected an indented block
>>> if True:
...     pass
... 
```

Suele utilizarse cuando no quiere tratarse una excepción o cuando se ha hecho
un boceto de una función que aún no quiere desarrollarse, para que el
intérprete no falle de forma inevitable.

> NOTA: Las excepciones de sintaxis son las más graves, implican que el
> intérprete no es capaz de entender lo que le pedimos así que la ejecución del
> programa no llega a realizarse. La sintaxis se comprueba en una etapa previa
> a la ejecución.

#### Continue

`continue` sirve para terminar el bucle actual y volver a comprobar la
condición para decidir si volver a ejecutarlo.

En el siguiente ejemplo salta la ejecución para el caso en el que `i` es `2`.

```
>>> for i in [0, 1, 2, 3]:
...     if i == 2:
...             continue
...     i
... 
0
1
3
```

#### Break

`break` rompe el bucle actual. A diferencia del `continue`, no se intenta
ejecutar la siguiente sentencia, simplemente se rompe el bucle completo. En el
siguiente ejemplo se rompe el bucle cuando `i` es `2` y no se recupera.

```
>>> for i in [0, 1, 2, 3]:
...     if i == 2:
...             break
...     i
... 
0
1
```

El `break` se usa mucho para romper bucles que son infinitos por definición. En
lugar de añadir una condición compleja a un bucle `while`, por ejemplo, puedes
usar un `True` en su condición e introducir un `if` más simple dentro de éste
con un `break` que termine el bucle en los casos que te interesen. O puedes
capturar una excepción y romper el bucle si ocurre.

Además, es muy usado en búsquedas y habilita el uso del `else` en las
sentencias `for`. Te propongo como ejercicio que trates de ejecutar y
comprender el funcionamiento de esta pieza de código de python avanzado antes
de seguir leyendo:

``` python
text = "texto de prueba"
pos  = 0

for i in text:
    if i == "b":
        print("Found b in position: " + str(pos))
        break
    pos = pos + 1
else:
    print("b not found :( ")
```

Si cambias el texto de la variable `text` por uno que no tenga letra `b` verás
que el bloque `else` se ejecuta. Esto se debe a que el `for` no termina de
forma abrupta, sino que itera por el string completo.

Si quieres, puedes memorizar esta estructura para cuando quieras hacer
búsquedas. Es elegante y te será útil.


#### Return

La sentencia `return` sólo tiene sentido dentro de las funciones. Sirve para
finalizar la ejecución de una función sustituyendo su llamada por el resultado
indicado en el `return`. Esta operación rompe todos los bucles por completo.

En el apartado de las funciones profundizaremos en el uso del `return` pero es
importante mencionarlo aquí porque su funcionalidad puede sustituir al `break`
en muchas ocasiones.