summaryrefslogtreecommitdiff
path: root/src/03_estructura.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/03_estructura.md')
-rw-r--r--src/03_estructura.md550
1 files changed, 0 insertions, 550 deletions
diff --git a/src/03_estructura.md b/src/03_estructura.md
deleted file mode 100644
index 9d8cd5e..0000000
--- a/src/03_estructura.md
+++ /dev/null
@@ -1,550 +0,0 @@
-# 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 forma general. 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 no se cumplen todas las condiciones
- # previas
-```
-
-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,
-
-``` python
-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:
-
-``` python
->>> 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:
-
-``` python
->>> 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`.
-
-
-> TODO:
-> Mejorar este ejemplo, es demasiado simple
-
-``` python
->>> [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`.
-
-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.
-
-``` python
->>> (i**2 for i in range(0, 10))
-<generator object <genexpr> at 0x7f779d9b2d58>
-```
-
-[^set-notation]: <https://en.wikipedia.org/wiki/Set-builder_notation>
-
-### Excepciones
-
-Las excepciones o *exception* son errores del programa, python lanza
-excepciones cuando hay problemas. Por ejemplo, cuando intentas acceder a un
-índice inexistente en una lista.
-
-Las excepciones terminan la ejecución del programa a no ser que se gestionen.
-Se consideran fallos de los que el programa no puede arreglarse a no ser que se
-le indique cómo. Algunas funciones y librerías lanzan excepciones que nosotros
-debemos gestionar, por ejemplo: que un archivo no exista, o que no se tenga
-permisos de edición en el directorio, etc. Es nuestra responsabilidad como
-programadores tener un plan be o aceptar la excepción deportivamente a
-sabiendas que nuestro programa terminará indicando un error.
-
-Hay ocasiones en las que las excepciones pueden capturarse y otras no, por
-ejemplo, los fallos de sintaxis no pueden solventarse.
-
-Las excepciones se capturan con un `try-except` que, si programas en otros
-lenguajes como Java, probablemente conozcas como `try-catch`.
-
-```python
-try:
- # Bloque donde pueden ocurrir excepciones.
-except tipo1:
- # Bloque a ejecutar en caso de que se dé una excepción de tipo1.
- # Especificar el tipo también es opcional, si no se añade captura todos.
-except tipoN:
- # Bloques adicionales (opcionales) a ejecutar en caso de que se dé una
- # excepción de tipoN, que no haya sido capturada por los bloques
- # anteriores.
-finally:
- # Bloque (opcional) a ejecutar después de lo anterior, haya o no haya
- # habido excepción.
-```
-
-Además de capturarse, las excepciones pueden lanzarse con la sentencia `raise`.
-
-``` python
-if not input:
- raise ValueError("Invalid input")
-```
-
-Si el ejemplo anterior se diera dentro de una pieza de código que no podemos
-controlar, podríamos capturar el `ValueError` y evitar que la ejecución de
-nuestro programa terminara.
-
-``` python
-try:
- # Bloque que puede lanzar un ValueError
-except ValueError:
- print("Not value in input, using default")
- input = None
-```
-
-Aunque aún no hemos entrado en la programación orientada a objetos, te adelanto
-que las excepciones se controlan como tal. Hay excepciones que serán hijas de
-otras, por lo que usando la excepción genérica de la familia seremos capaces de
-capturarlas, o podremos crear nuevas excepciones como hijas de las que python
-ya dispone de serie. Por ahora recuerda que debes ordenar los bloques `except`
-de más concreto a más genérico, porque si lo haces al revés, los primeros
-bloques te capturarán todas las excepciones y los demás no tendrán ocasión de
-capturar ninguna, perdiendo así el detalle de los fallos.
-
-Cuando aprendas sobre programación orientada a objetos en el apartado
-correspondiente puedes volver a visitar este punto y leer la documentación de
-python[^exception] para entender cómo hacerlo. Te adelanto que python tiene una
-larga lista de excepciones y que está considerado una mala práctica crear
-nuevas si las excepciones por defecto cubren un caso similar al que se
-encuentra en nuestro programa.
-
-[^exception]: <https://docs.python.org/3/library/exceptions.html>
-
-### Funciones
-
-Las funciones sirven, sobre todo, para reutilizar código. Si una pieza de
-código se utiliza en más de una ocasión en tu programa, es una buena candidata
-para agruparse en una función y poder reutilizarla sin necesidad de duplicar
-el código fuente. Aunque sirven para más fines y tienen detalles que
-aclararemos en un capítulo propio, en este apartado adelantaremos cómo se
-definen y cómo lanzan y posteriormente las analizaremos en detalle.
-
-Las definición de funciones se realiza con una estructura similar a las
-anteriores, una línea descriptiva terminada en dos puntos (`:`) y después un
-bloque con mayor sangría para definir el cuerpo.
-
-``` python
-def nombre_de_funcion (argumentos):
- """
- docstring, un string multilínea que sirve como documentación
- de la función. Es opcional y no tiene efecto en el funcionamiento
- de la función.
- Es lo que se visualiza al ejecutar `help(nombre_de_función)`
- """
- # Cuerpo de la función
-```
-
-Para llamar a esta función que acabamos de crear:
-
-``` python
-nombre_de_función(argumentos)
-```
-
-El nombre de la función debe cumplir las mismas normas que los nombres de las
-referencias de las que ya hemos hablando anteriormente. Y esto debe ser así
-básicamente porque... ¡el nombre de la función también es una referencia a un
-valor de tipo función!
-
-Pronto ahondaremos más en este tema. De momento recuerda la declaración de las
-funciones. Dentro de ellas podrás incluir todas las estructuras definidas en
-este apartado, incluso podrás definir funciones.
-
-Aunque en el próximo capítulo tocará hablar de los argumentos de entrada, de
-momento te adelanto que cuando llamaste a la función `range` anteriormente, le
-introdujiste dos argumentos. Esos dos argumentos deben declararse como
-argumentos de entrada. Probablemente de una forma similar a esta:
-
-``` python
-def range (inicio, fin):
- contador = inicio
- salida = []
- while contador < fin:
- salida.append(contador)
- contador = contador + 1
- return salida
-```
-
-Lo que va a ocurrir al llamar a la función, por ejemplo, con esta llamada:
-`range(1, 10)` es que el argumento `inicio` tomará el valor `1` para esta
-ejecución y el argumento `fin` tomará el valor `10`, como si en el propio
-cuerpo de la función alguien hubiese hecho:
-
-``` python
-inicio = 1
-fin = 10
-```
-
-El contenido de la función se ejecutará, por tanto, con esas referencias
-asignadas a un valor. Con lo que sabes ya puedes intentar descifrar el
-comportamiento de la función `range` que hemos definido, que es similar, pero
-no igual, a la que define python.
-
-Sólo necesitas entender lo que hace la función `list.append` que puedes
-comprobar en la ayuda haciendo `help( list.append )` y la sentencia `return`,
-que se explica en el siguiente apartado.
-
-Prueba a leer ambas y a crear un archivo de python donde construyes la función
-y le lanzas unas llamadas. A ver si lo entiendes.
-
-### 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.
-
-``` python
->>> 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`.
-
-``` python
->>> 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.
-
-``` python
->>> 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.
-
-## Lo que has aprendido
-
-Es difícil resumir todo lo que has aprendido en este capítulo porque, la verdad
-es que es mucha información. Pero no pasa nada porque este capítulo se ha
-creado más como referencia que como otra cosa. No tengas miedo a volver a
-leerlo todas las veces que necesites. A todos se nos olvida cómo hay que
-declarar las funciones si llevamos mucho tiempo sin tocar python, o si era
-`try-catch` o `try-except`. Este capítulo pretende, por un lado, darte una
-pincelada de cómo se escribe en python y, por otro, servir como manual de
-consulta posterior.
-
-Pero, por hacer la labor de resumen, has aprendido el orden de ejecución de las
-órdenes y como alterarlo con bucles y condicionales. Para ello, has tenido que
-aprender lo que es un *bloque* de código, una pieza fundamental para entender
-la sintaxis. Tras ver varios ejemplos de bucles y condicionales, te has
-sumergido en la verdad y la mentira mediante los valores *truthy* y *falsey*,
-para después avanzar a las *list comprehensions*, cuyo nombre contiene *list*
-pero valen para cualquier dato complejo.
-
-Has cambiado un poco de tema después, saltando a las excepciones, que no has
-podido ver en detalle por no ser, aún, un experto en programación orientada a
-objetos. Pero tranquilo, pronto lo serás.
-
-Una pincelada sobre funciones ha sido suficiente para que no les tengas miedo
-nunca más y que podamos atacar el siguiente capítulo con energía, ya que ahora
-toca jugar con funciones hasta entenderlas por completo.
-
-Las sentencias útiles que hemos recopilado al final permiten juguetear con
-todas las estructuras que hemos definido en el capítulo de modo que puedas
-usarlas a tu antojo de forma cómoda. Algunas de ellas como `continue` y `break`
-no son realmente necesarias, puede programarse evitándolas y, de hecho, en
-algunos lugares enseñan a no usarlas, como si de una buena práctica se tratara,
-cambiando las condiciones de los bucles para que hagan esta labor. En este
-documento se muestran porque, en primer lugar, si lees código escrito por otras
-personas las encontrarás y tendrás que entender qué hacen y, en segundo, porque
-son sentencias que simplifican el código haciéndolo más legible o más sencillo
-por muy impuras que a algunos programadores les puedan parecer.