Programar en Python

Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 102

Programar en Python

Introducción a la programación y al lenguaje

«CC-BY-SA Ekaitz Zárraga


2 Ekaitz Zárraga
Programar en Python

Índice general

1 Introducción 7
1.1 Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.1.1 Instalación en distribuciones de Linux . . . . . . . . . . . . . . . . . . . 7
1.1.2 Instalación en otros sistemas . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2 Admira el paisaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.2.1 Tu primer archivo de código fuente . . . . . . . . . . . . . . . . . . . . 9
1.2.2 La vida real . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2 Trabajando con datos 11


2.1 Nombrando datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.1.1 Todo es una referencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2 Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.2.1 Tipos simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2.2 Tipos compuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3 Conversión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4 Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.1 Pruebas de verdad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.2 Operadores lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4.3 Matemá cos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4.4 Operador ternario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4.5 Operación en función del po . . . . . . . . . . . . . . . . . . . . . . . 20
2.4.6 Precedencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5 Mutabilidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

3 Estructura del lenguaje 23


3.1 Sintaxis general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.1.1 Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.1.2 Control de flujo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.1.3 List comprehensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.1.4 Excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.5 Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.1.6 Sentencias ú les . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

4 Funciones 33
4.1 Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

3
ÍNDICE GENERAL

4.2 First-class ci zens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34


4.3 Lambdas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.4 Scope avanzado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.4.1 Scope léxico, Closures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
4.4.2 Global y No-local . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.5 Argumentos de entrada y llamadas . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.5.1 Callable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.5.2 Posi onal vs Keyword Arguments . . . . . . . . . . . . . . . . . . . . . 40
4.6 Decorators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
4.7 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

5 Orientación a Objetos 45
5.1 Programación basada en clases . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
5.1.1 Fundamento teórico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.2 Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
5.2.1 Creación de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.2.2 Herencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.2.3 Métodos de objeto o funciones de clase . . . . . . . . . . . . . . . . . 49
5.2.4 Variables de clase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
5.2.5 Encapsulación explícita . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
5.2.6 Acceso a la superclase . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
5.3 Duck Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
5.3.1 Representable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.3.2 Contable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.3.3 Buscable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.3.4 Hasheable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
5.3.5 Iterable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
5.3.6 Inicializable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
5.3.7 Abrible y cerrable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.3.8 Llamable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
5.3.9 Subscriptable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
5.3.10 Ejemplo de uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.4 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

6 Módulos y ejecución 65
6.1 Terminología: módulos y paquetes . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.2 Ejecución . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
6.3 Importación y namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
6.3.1 Búsqueda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
6.4 Ejecución e importación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.5 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

7 Instalación y dependencias 71
7.1 Sobre PIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.1.1 PyPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
7.1.2 Reglas de instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

4 Ekaitz Zárraga
7.2 Entornos virtuales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
7.2.1 Instalación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
7.2.2 Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.2.3 Usar IDLE desde un entorno virtual . . . . . . . . . . . . . . . . . . . . 74
7.3 Otras herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7.4 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

8 La librería estándar 77
8.1 Interfaz al sistema opera vo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
8.2 Funciones relacionadas con el intérprete . . . . . . . . . . . . . . . . . . . . . 78
8.2.1 Salida forzada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
8.2.2 Standard streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
8.2.3 Argumentos de entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
8.3 Procesamiento de argumentos de entrada . . . . . . . . . . . . . . . . . . . . . 80
8.4 Expresiones regulares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
8.5 Matemá cas y estadís ca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
8.6 Protocolos de internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
8.7 Fechas y horas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
8.8 Procesamiento de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
8.9 Aritmé ca de coma flotante decimal . . . . . . . . . . . . . . . . . . . . . . . . 82
8.10 Lo que has aprendido . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

9 Librerías ú les 85
9.1 Librerías cien ficas: ecosistema SciPy . . . . . . . . . . . . . . . . . . . . . . . 85
9.2 Machine Learning: ScikitLearn . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
9.3 Pe ciones web: Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
9.4 Manipulación de HTML: Beau fulsoup . . . . . . . . . . . . . . . . . . . . . . 86
9.5 Tratamiento de imagen: Pillow . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
9.6 Desarrollo web: Django, Flask . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
9.7 Protocolos de red: Twisted . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
9.8 Interfaces gráficas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

10 Lo que has aprendido 89


10.1 El código pythónico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90

Anexo I: Herramientas 93
10.2 Desarrollo de código fuente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
10.2.1 Entornos de desarrollo integrados . . . . . . . . . . . . . . . . . . . . . 93
10.2.2 Editores de código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
10.3 Herramientas de depuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
10.4 Testeo de aplicaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94

Anexo II: Licencia CC BY-SA 4.0 95

5
ÍNDICE GENERAL

6 Ekaitz Zárraga
Programar en Python

1 Introducción

Python es un lenguaje de programación de alto nivel orientado al uso general. Fue creado por
Guido Van Rossum y publicado en 1991. La filoso a de python hace hincapié en la limpieza
y la legibilidad del código fuente con una sintaxis que facilita expresar conceptos en menos
líneas de código que en otros lenguajes.

Python es un lenguaje de pado dinámico y ges ón de memoria automá ca. Soporta múl-
ples paradigmas de programación, incluyendo la programación orientada a objetos, impe-
ra va, funcional y procedural e incluye una extensa librería estándar.

Pronto entenderás lo que todo esto significa, pero antes hay que instalar las herramientas
necesarias y trastear con ellas.

1.1 Instalación
Para trabajar con python se necesita:

• python3: el intérprete de python, en su versión 3. Verás que hay muchas subversiones.


Este documento cubre cualquiera de ellas.

• pip: el gestor de paquetería de python. También se conoce como pip3 para diferenciarlo
del pip de python2.

Nosotros añadiremos un par de amigos a la lista:

• idle3: un editor de código python muy sencillo. Usaremos este porque representa el
ecosistema de forma muy simple. En el futuro, te recomiendo usar algún otro editor
más avanzado.

• pipenv: el estándar de facto para ges onar entornos virtuales en python. Luego en-
tenderás qué es eso.

1.1.1 Instalación en distribuciones de Linux


La instalación puede realizarse desde el gestor de paquetes habitual, ya que python suele
distribuirse en todos los repositorios de paquetes.

En las distribuciones que usan el sistema de paquetes de Debian, puede instalarse desde la
terminal con el siguiente comando:
sudo apt-get install python3 python3-pip idle3

7
CAPÍTULO 1. INTRODUCCIÓN

1.1.2 Instalación en otros sistemas


Como siempre, instalar en otros sistemas es más farragoso. Pero no es demasiado di cil en
este caso. La instalación puede realizarse con una descarga desde la página web oficial de
python:
https://python.org/downloads/
Una vez ahí seleccionar la versión necesaria, descargar el instalador y seguir las instrucciones
de éste. Recuerda seleccionar instalar pip entre las opciones y ac var la casilla de añadir
python al PATH, que permi rá que ejecutes programas de python sin problemas. También
puedes añadir IDLE, el programa que sirve para editar el código, pero te recuerdo que es un
programa muy sencillo, que nos servirá para entender lo básico del entorno sin ocultarnos
el proceso, pero que más adelante podrás u lizar otros editores que simplifiquen tareas.

1.2 Admira el paisaje


Una vez que has instalado python, es interesante ver lo que eso significa. Python es un intér-
prete de código fuente del lenguaje del mismo nombre. Concretamente, la que has instalado
es una de las posibles implementaciones (la implementación de referencia, en este caso) de
este intérprete, conocida como CPython, en su versión 3. Existen otras implementaciones,
cada una con sus peculiaridades, pero ésta es la principal y la más usada.
Como intérprete que es, python es capaz de leer un archivo escrito en su lenguaje y ejecutar
sus órdenes en tu computadora. Ésta es principalmente su labor. Sin embargo, también es
capaz de recibir las órdenes una por una y devolver el resultado de su ejecución como res-
puesta. Este proceso se conoce como REPL, acrónimo de read-eval-print-loop (lee-evalúa-
imprime-repite), aunque en otros lugares se le conoce como la shell de python.

La shell de python (o REPL) y la shell del sistema son cosas diferentes. La shell
de sistema también es un intérprete pero del lenguaje que el sistema ha definido
(Bash, PowerShell…) y no suele ser capaz de entender python.

Para acostumbrarte a la shell te propongo que abras IDLE. Lo primero que verás será parecido
a esto:
Python 3.6.8 (default, Oct 7 2019, 12:59:55)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license()" for more information.
>>>

Todo lo que escribas tras el símbolo >>> será interpretado como una orden y cuando la ter-
mines pulsando la tecla ENTER de tu teclado, recibirás el resultado de la ejecución de la orden
insertada. El acrónimo REPL define el comportamiento de este ciclo a las mil maravillas:
1. Lee lo que introduces.
2. Lo evalúa, obteniendo así un valor como resultado.
3. Lo imprime.
4. Repite el ciclo volviendo a leer.

8 Ekaitz Zárraga
1.2. ADMIRA EL PAISAJE

En este documento, siempre que veas el símbolo >>> significa que se trata de
un ejemplo ejecutado en la REPL. Si no lo ves, se tratará del contenido de un
archivo de código python ejecutado de forma independiente.

Por tanto, si introduces un valor directamente será devuelto:


>>> 1
1

Y si lo alteras, por ejemplo, con una operación matemá ca sencilla, devuelve el resultado
correspondiente:
>>> 2+2
4

Como ejercicio te propongo lo siguiente:


1. Abre la shell de python (puedes hacerlo en IDLE o desde la shell de sistema ejecutando
python o python3).
2. Entra en la ayuda interac va.

PISTA: el mensaje que aparece al abrir la REPL te dice cómo.

3. Sal de la ayuda (descubre tú mismo cómo se hace).


4. Ejecuta import this y lee el resultado.

1.2.1 Tu primer archivo de código fuente


La REPL es interesante para probar y depurar tus programas (o para usarla como calculadora),
pero es necesario grabar tus programas en ficheros si quieres poder volver a ejecutarlos más
adelante o compar rlos.
En IDLE puedes abrir un nuevo documento de código en el menú de archivo. Una vez lo
tengas, como aún no sabes python puedes introducir lo siguiente:
nombre = "Guido"
print("Hola, " + nombre)

Si guardas el fichero y pulsas F5 (Ejecutar módulo), verás que en la pantalla de la REPL aparece
el resultado Hola, Guido.
Como ves, el resultado de ejecutar los ficheros de código fuente aparece en la shell, pero
únicamente aparece lo que explícitamente le has pedido que imprima con la orden print.
Para entender el valor de la REPL, te sugiero que vayas a su ventana, y justo después del
resultado de la ejecución hagas lo siguiente:
Hola, Guido
>>> nombre
'Guido'
>>>

9
CAPÍTULO 1. INTRODUCCIÓN

La REPL conoce el valor nombre a pesar de que tu programa ha terminado de ejecutarse.


Esto es interesante a la hora de probar y analizar el programa.

1.2.2 La vida real


En realidad, los programas de producción no se ejecutan en una shell como la que IDLE nos
brinda. IDLE sólo está facilitando nuestro trabajo de desarrollo, como otros entornos hacen,
cada uno a su manera. En producción el código se levantará ejecutando el intérprete de
python directamente con nuestro programa como input. Por ejemplo en la shell de sistema
usando el siguiente comando.
python ejemplo.py

También es posible ejecutar los programas de python desde la interfaz gráfica, pero inter-
namente el resultado será el mismo. Siempre que todo esté bien instalado y configurado, el
sistema opera vo despertará un intérprete de python que ejecute las órdenes del fichero.
Es importante ser consciente de lo que ocurre bajo la alfombra, para así ser capaces de
intervenir si encontramos errores.
Más adelante, en la sección sobre módulos e importación volveremos aquí y estudiaremos
cómo se cargan y se interpretan los programas.

1.3 Lo que has aprendido


Has instalado python y te has acostumbrado a la herramienta (IDLE) que usarás durante tu
aprendizaje. Has ejecutado tu primer fichero y encontrado la potencia de la REPL.
Además, has abierto la ayuda y te has leído el Zen de Python, que pronto iremos desgranando
juntos.
Para ser una introducción no está nada mal.

10 Ekaitz Zárraga
Programar en Python

2 Trabajando con datos

Programar es, principalmente, tratar con datos y los datos no son más que piezas de infor-
mación que se estructura de una forma concreta.

2.1 Nombrando datos


Los datos se almacenan en la memoria principal de la computadora. Puedes imaginarte la
memoria como un conjunto de cajas iden ficadas con direcciones, como si fuesen los bu-
zones de un portal con muchos pisos. Para u lizar datos, éstos se guardan en los diferentes
cajones y se van extrayendo y actualizando. La importancia de nombrar las cosas es eviden-
te, si no guardamos un listado de dónde hemos guardado qué, no podemos recuperar los
datos que hemos creado.
Al igual que en las matemá cas se u lizan los símbolos para representar posibles valores y
simplificar los procesos, en los lenguajes de programación se u lizan símbolos para definir
referencias a los datos y así poder referirse a los mismos datos por su nombre sin tener que
introducir su contenido constantemente. Los lenguajes de programación aportan a quien
programa la facilidad de poder crear sus propios nombres para no tener que usar las di-
recciones propias de la memoria, que normalmente son números sin más significado que
su posición, la mayor parte de las veces permi endo a quien programa abstraerse de estos
detalles internos.
En python existe un operador para declarar símbolos que hacen referencia a un valor: el
operador =. Este operador enlaza el valor de la derecha con el nombre de la izquierda. Con
un ejemplo es más fácil de comprender. Probando en la REPL:
>>> a = 10
>>> a
10
>>> a + 1
11

Como ves, en el primer paso se asocia el valor 10 al iden ficador a y más adelante se puede
u lizar a para hacer referencia al valor enlazado.
Las referencias han de ser declaradas antes de usarse, si no, el intérprete no las conoce y
lanza una excepción:
>>> b
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
b
NameError: name 'b' is not defined

11
CAPÍTULO 2. TRABAJANDO CON DATOS

Los nombres para poder ser interpretados correctamente por python deben
cumplir unas normas estrictas:
• No pueden tener espacios.
• Sólo pueden estar formados por combinaciones de letras, números y el
símbolo _.
• No pueden empezar por un dígito.

2.1.1 Todo es una referencia


El comportamiento de estas referencias puede no ser intui vo si vienes de otros lenguajes.
El operador = enlaza, como se dice anteriormente, un nombre a un valor concreto, pero eso
no significa que copie su contenido. En python los valores y los nombres son conceptos
independientes. Los valores ocupan su lugar en la memoria y los nombres hacen referencia
a dónde se encuentran estos valores. Es muy común tener muchas referencias a la misma
estructura de datos y transformar su contenido desde todas las referencias.
A nivel técnico, lo que en python se conoce como variable y en este documento hemos
hecho el esfuerzo de llamar, hasta este momento, referencia es parecido a lo que en otros
lenguajes se conoce como puntero y la labor del operador = es la de asignar el puntero a la
dirección donde se encuentran los datos a los que debe apuntar.
Volviendo a la metáfora de los buzones, en lenguajes de más bajo nivel como C estás obligado
a seleccionar qué buzón vas a u lizar para introducir cada dato. Por lo que si cambia el po
de dato a ges onar, puede que el buzón se quede pequeño o que los datos se interpreten de
forma incorrecta. Sin embargo, python guarda las referencias de forma independiente a los
valores y adecua el número de buzones en uso al tamaño de los datos de los que dispones
reordenando, si es necesario, la estructura completa de valores y referencias. A este con-
cepto se le conoce como ges ón automá ca de memoria (automa c memory management).
En resumen, las referencias en python son únicamente un recordatorio que sirve para poder
acceder a un valor. Esto cobra importancia más adelante, y no vamos a rehuir la responsa-
bilidad de enfangarnos en ello.

2.2 Tipos
Tal y como aclaraba el texto de la introducción, python ene un sistema de pos dinámico
(dynamic type system). Lo que significa que ges ona los pos de forma automá ca, permi-
endo a los nombres hacer referencia a diferentes pos de valor durante la ejecución del
programa a diferencia de otros lenguajes como, por ejemplo, C, donde el po de las variables
debe ser declarado de antemano y no puede cambiarse.
Esto es posible debido al fenómeno explicado en el apartado anterior por un lado, y, por el
otro, a que los datos de python son un poco más complejos que en otros lenguajes y guardan
una pequeña nota que indica cómo deben ser interpretados.
Si en algún momento se le pide a python que asigne un valor de un po dis nto al que una

12 Ekaitz Zárraga
2.2. TIPOS

referencia tenía no habrá problemas porque es el propio dato quien guarda la información
suficiente para saber cómo entenderlo. Las referencias sólo almacenan dónde se guarda este
dato.

Seguramente te habrás dado cuenta de que el funcionamiento de python es más


ineficiente que el de C o lenguajes similares pero mucho más flexible. Y así es. A
la hora de elegir el lenguaje debemos valorar cuál nos interesa más para la labor
que vamos a realizar.

2.2.1 Tipos simples


Hemos denominado pos simples a los que no empaquetan más de un valor internamente.
En otros lenguajes o contextos se les conoce como escalares.

La nada

La nada en python se representa con el valor None y es ú l en innumerables ocasiones.

Boolean

Los valores booleanos expresan verdad (True) o men ra (False) y sirven para ges onar lógica
desde esos términos. Mas adelante los veremos en acción.

Integer

Los Integer, números enteros en inglés, ya han aparecido anteriormente. Para usar un nú-
mero entero puedes introducirlo tal cual. Recuerda que hay enteros posi vos y nega vos.
El símbolo para marcar números nega vos en python es el -, que coincide con el operador
de la resta.
>>> 14
14
>>> -900
-900
>>>

Los números enteros también pueden expresarse en otras bases, como en hexadecimal. De-
pendiendo de la aplicación en la que te encuentres igual necesitas mirarlo más en detalle:
>>> 0x10
16

Float

Los números Float, o de coma flotante, son números no-enteros. Ten cuidado con ellos por-
que la coma flotante es peculiar.
El nombre coma flotante viene de que la coma no siempre se man ene con la misma
precisión. En realidad estos números se guardan como los números en notación cien fica

13
CAPÍTULO 2. TRABAJANDO CON DATOS

(2,997E8 m/s para la velocidad de la luz, por ejemplo). La notación cien fica siempre implica
tener una coma, pero cuya posición se varía con el exponente posterior.

El modo de almacenamiento de los números de coma flotante es muy similar a la notación


cien fica: se almacenan dos valores de tamaño fijo, la man sa y el exponente para, de este
modo, poder ajustar la precisión en función del tamaño del número almacenado. No es lo
mismo expresar la velocidad de la luz, 2,997E8 m/s, que la longitud de onda del color rojo,
6,250E-7 m, ambos valores enen un tamaño muy dis nto, pero usando dos man sas de
tamaño similar, cuatro dígitos (2997 y 6250), y dos exponentes de tamaño similar, un dígito
(8 y -7), hemos expresado valores muy diferentes, ambos con la misma precisión rela va.

El problema viene cuando nos apetece mezclarlos, por ejemplo, sumándolos. Imagina que
enes dos valores de esas dimensiones, uno de millones y otro de millonésimas partes de la
unidad, y los quieres sumar entre ellos. Si sólo enes una man sa limitada para representar-
los, la suma resultará en el redondeo de ambos a la precisión que enes disponible. Es decir:
el resultado será el valor grande y el pequeño se perderá en el redondeo.

Aunque en este caso la suma es precisa, si tratas con un billón de valores pequeños y uno
grande y quieres obtener la suma de todos y los sumas en parejas siempre con el grande, en
cada suma se descartará el valor pequeño en el redondeo y el resultado total será el valor
grande que tenías. Sin embargo, si sumas los valores de tamaño similar entre ellos primero,
obtendrás un valor suficientemente grande como para alterar el resultado de la suma contra
el valor grande al final, dando así un resultado dis nto. Te recomiendo entonces, que si te
encuentras en una situación como ésta tengas cuidado y, por ejemplo, ordenes los números
de menor a mayor antes de sumarlos, para obtener una suma de buena precisión.

En realidad, el exponente en el caso de python (y en casi todos los demás lenguajes) no está
elevando un 10 a la enésima potencia, si no que lo hace con un 2. Por lo que lo expresado
anteriormente es un poco dis nto. Esto provoca que algunos números de coma flotante
no sean tan redondos como deberían (por ejemplo, 2.999999999, cuando debería ser 3.0)
y compararlos entre ellos puede ser desastroso. Para evitarlo, te recomiendo que siempre
redondees los valores a una precisión que puedas controlar.

Aunque realmente es algo más complejo, lo que sabes ahora te evitará problemas en el fu-
turo, sobre todo cuando analices datos, uno de los sectores donde python se usa de forma
extensiva. Si necesitas saber más, debes inves gar la ar mé ca de coma flotante, o floa ng
point arithme c en inglés.

Declarar números de coma flotante es natural porque usa una sintaxis a la que estamos
acostumbrados:

>>> 1E10
10000000000.0
>>> 1.0
1.0
>>> 0.2E10
2000000000.0
>>>

14 Ekaitz Zárraga
2.2. TIPOS

Complex

Python soporta números complejos y los expresa u lizando la letra j. Como suponen un caso
bastante concreto no los analizaremos en detalle. Pero enes disponible la documentación
de python para lo que quieras.
>>> 1-23j
(1-23j)

String

Un String es una cadena de caracteres. Los Strings en python son, a diferencia de en otros
lenguajes, un escalar, al contrario de lo que la primera definición que hemos expresado pue-
de hacernos pensar. En python los Strings no son un conjunto de caracteres alfanuméricos
sueltos que se comportan como un valor, es al revés. El concepto de carácter no existe y ha
de expresarse con un String de longitud 1.

Los strings se expresan rodeando texto con comillas dobles, ", o simples ' (el símbolo del
apóstrofe).
>>> "Hola"
'Hola'
>>> 'Hola'
'Hola'

El hecho de que haya dos opciones para delimitar los strings facilita el e quetado como string
de valores que con enen las propias comillas en su contenido. También puede u lizarse la
contrabarra \ para cancelar la acción de las comillas.
>>> "Tiene un apóstrofe: Luke's"
"Tiene un apóstrofe: Luke's"
>>> 'Tiene un apóstrofe: Luke's'
SyntaxError: invalid syntax
>>> 'Tiene un apóstrofe: Luke\'s'
"Tiene un apóstrofe: Luke's"

la contrabarra sirve para introducir caracteres especiales o caracteres de escape:


\n salto de línea, \t tabulador, etc. Que son una herencia de los empos de las
máquinas de escribir, pero son aún ú les y muy usados. Para expresar la propia
contrabarra ha de escaparse a sí misma con otra contrabarra para que no evalúe
el siguiente caracter como un caracter de escape.: \\.

2.2.2 Tipos compuestos


Hemos denominado pos compuestos a los que pueden incluir diferentes combinaciones de
pos simples. Estos pos dejan de ser escalares y se comportan como vectores o conjun-
tos de datos. Estos pos de dato pueden contenerse a sí mismos, por lo que pueden crear
estructuras anidadas complejas.

15
CAPÍTULO 2. TRABAJANDO CON DATOS

Tuple

Las tuplas o tuple en inglés son el po compuesto más sencillo en python. Las tuplas definen
un conjunto de valores de cualquier po.
Se declaran u lizando paréntesis añadiendo sus elementos separados por comas. Y se acce-
de a sus contenidos u lizando los corchetes e introduciendo el índice del elemento que se
quiere extraer.
>>> (2, 3, "HOLA")
(2, 3, 'HOLA')
>>> (2, 3, "HOLA")[0]
2

En python los índices comienzan en 0.

List

Las listas o list son muy similares a las tuplas, pero son algo más complejas porque pueden
alterarse así mismas. A diferencia de todos los pos que hemos visto hasta ahora, tanto las
listas como los diccionarios que veremos a con nuación son mutables. Esto significa que
puede transformarse su valor. Más adelante trataremos esto en detalle.
De momento, recuerda que las listas se construyen de forma similar a las tuplas, pero u li-
zando corchetes en lugar de paréntesis. La forma de acceder a los índices es idén ca.
>>> [2, 3, "HOLA"]
[2, 3, 'HOLA']
>>> [2, 3, "HOLA"][0]
2

Dic onary

Los diccionarios o dic onary son un po de dato similar a los dos anteriores, pero que en lugar
de u lizar índices basados en la posición de sus elementos usan claves arbitrarias definidas
por quien programa.
Además, los diccionarios no están ordenados así que no se puede suponer que las claves
siempre van a estar en el orden en el que se introducen.
Para declarar diccionarios es necesario indicar qué claves se quieren usar. Las claves pueden
ser de cualquier po que se considere hasheable1 , concepto que se analiza más adelante,
aunque normalmente su usan cadenas de caracteres como claves.
El acceso a sus valores se realiza con los corchetes, del mismo modo que en las listas, pero
es necesario seleccionar la clave para acceder.
Los diccionarios, al igual que las listas, son mutables. Como veremos en seguida.
>>> {"nombre": "Guido", "apellido": "Van Rossum", "popularidad": 8.0}
{'nombre': 'Guido', 'apellido': 'Van Rossum', 'popularidad': 8.0}

1
Los diccionarios son una implementación del concepto conocido como hashmap o hash-table. Su funciona-
miento interno requiere que las claves puedan procesarse mediante una función de hash.

16 Ekaitz Zárraga
2.3. CONVERSIÓN

>>> {"nombre": "Guido", "apellido": "Van Rossum",


"popularidad": 8.0}["popularidad"]
8.0

Set

Los sets son muy similares a las listas y tuplas, pero con varias peculiaridades:
• Sus valores son únicos. No pueden repe rse.
• No están ordenados.
• No se puede acceder a ellos mediante los corchetes ([]).
Estas dos caracterís cas tan estrictas, lejos de ser limitantes, aportan una mejora radical en
su rendimiento. Buscar elementos en un set es extremadamente eficiente y se usan princi-
palmente para esa labor.
Si quieres validar en algún momento que un valor pertenece a un conjunto de valores, el set
es el po de dato que estás buscando.
Los sets se declaran también usando las llaves, como un diccionario, pero no usan claves.
>>> {"a", "b", 1}
{'a', 1, 'b'}

Otro de los usos más habituales de los sets es el de aplicar teoría de conjuntos (set significa
«conjunto»). Los sets pueden combinarse forma eficiente mediante uniones (union), diferen-
cias (difference), intersecciones (intersec on) y otros métodos descritos en esta teoría.

2.3 Conversión
Ahora que conoces los valores sé que quieres saber cómo cambiar de uno a otro. Cómo leer
un Integer desde un String, etc. Python ene funciones para construir sus diferentes pos
de datos a par r de los diferentes inputs posibles.
Aunque aún no sabes ejecutar funciones te adelanto cómo se hace con algunos ejemplos:
>>> bool(1)
True
>>> bool(0)
False
>>> int("hola")
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
int("hola")
ValueError: invalid literal for int() with base 10: 'hola'
>>> int("10")
10
>>> float(10)
10.0
>>> complex(19)
(19+0j)
>>> str(10)
'10'

17
CAPÍTULO 2. TRABAJANDO CON DATOS

>>> tuple([1,2,3])
(1, 2, 3)
>>> list((1,2,3))
[1, 2, 3]
>>> dict((("a", 1),("b", 2)))
{'a': 1, 'b': 2}
>>> set([1,2,2,3,4,4,4,4,4])
{1, 2, 3, 4}

Los propios nombres de las funciones son bastante representa vos de a qué po convierten.
Si quieres saber más puedes ejecutar help(nombre) y ver qué te cuenta la ayuda.

Fíjate que si conviertes una secuencia de valores repe dos a set únicamente
almacena los que no se repiten. Es uno de los usos más comunes que enen.

2.4 Operadores
Ahora que sabes el contexto en el que vas a jugar, necesitas poder alterar los datos.
Existen operadores básicos que te permiten transformar los datos. Algunos ya los has visto
antes, como el operador =, que sirve para nombrar cosas, la suma (+) o la resta (-), pero hay
otros.
>>> 1 + 1
2
>>> 10 - 9
1
>>> 10 ** 2
100
>>>

Los siguientes apartados muestran algunos operadores que es interesante memorizar.

2.4.1 Pruebas de verdad


Las pruebas de verdad generan un valor booleano desde una pareja de valores. A con nua-
ción una lista de las pruebas de verdad con unos ejemplos:

operador significado
< menor que
<= menor o igual que
> mayor que
>= mayor o igual que
== igual que
!= diferente de
is iden dad de objetos: «es»
is not iden dad negada: «no es»
in comprobación de contenido: «en»

18 Ekaitz Zárraga
2.4. OPERADORES

operador significado
not in comprobación de contenido negada: «no en»

>>> 1 > 1
False
>>> 1 >= 1
True
>>> 1 not in (0, 2, 3)
True

Aunque en otros lenguajes no es posible, la notación matemá ca habitual se puede u lizar


en python concatenando pruebas de verdad:
>>> x = 1.2
>>> 1 < x < 2
True

2.4.2 Operadores lógicos


Los operadores lógicos mezclan booleanos y son muy importantes, sobre todo para combinar
las pruebas de verdad.

operador significado
and «Y» lógico, es True si todos sus operandos son True
or «O» lógico, es True si algún operando es True
not «No» lógico, invierte el operando

La mayor parte de los operadores son binarios (como la suma), necesitan dos valores y de-
vuelven otro, pero existe al menos una excepción que funciona con un único valor. El ope-
rador not sirve para darle la vuelta a un Booleano.
>>> not True
False
>>> True and True
True
>>> False and True
False
>>> False or True
True
>>> 1 > 0 and 2 > 1
True

2.4.3 Matemá cos


Los operadores matemá cos transforman números entre ellos. Casi todos son conocidos por
su operación matemá ca.

operador significado
+ Suma
19
CAPÍTULO 2. TRABAJANDO CON DATOS

operador significado
- Nega vo o resta
* Mul plicación
/ División
** Potencia
% Resto

2.4.4 Operador ternario


Existe además un operador que puede usar tres parámetros, el inline-if (if en línea), o ternary
operator2 . El ternary operator se comporta así:
>>> 1 if 1 > 9 else 9
9
>>> 1 if 1 < 9 else 9
1

2.4.5 Operación en función del po


Python simplifica muchas tareas transformando el comportamiento de los operadores en
función del po de dato sobre el que trabajan. Los operadores matemá cos están prepara-
dos para trabajar sobre números (de cualquier po) pero la verdad es que algunos pueden
ejecutarse sobre otros formatos. Por ejemplo:
>>> "a" + "a"
'aa'
>>> [1,2] + [3,4]
[1, 2, 3, 4]

Esto se debe a que la funcionalidad del operador + ha sido diseñada para operar de forma
especial en Strings y en Listas, haciendo una concatenación.
En el futuro, cuando aprendas a diseñar tus propios pos podrás hacer que los operadores
les afecten de forma especial, tal y como pasa aquí.

2.4.6 Precedencia
La precedencia en python es muy similar a la matemá ca y usa las mismas reglas para mar-
carla de forma explícita. Recuerda, en matemá cas se u lizan los paréntesis para esto.
Los operadores siempre trabajan con sus correspondientes valores y python los resuelve de
forma ordenada. Si generas una operación muy compleja, python la irá desgranando paso a
paso y resolviendo las parejas una a una, cuanto más te acostumbres a hacerlo en tu mente
menos errores cometerás.
2
En realidad, el nombre de operador ternario no indica nada más que el hecho de que use tres argumentos.
Históricamente se ha usado este nombre para este operador en concreto, que en otros lenguajes aparece con
la forma condición ? resultado1 : resultado2, porque no solía exis r ningún otro operador que recibiera
tres argumentos.

20 Ekaitz Zárraga
2.5. MUTABILIDAD

>>> 8 + 7 * 10 == (8 + 7) * 10
False
>>> 8 + 7 * 10
78
>>> (8 + 7) * 10
150
>>> 78 == 150
False

2.5 Mutabilidad
Ya adelantamos que el operador = sirve para nombrar cosas. Ahora vamos a combinar esa
propiedad con la mutabilidad, o la propiedad de las cosas de alterarse a sí mismas. Empece-
mos con un ejemplo:
>>> a = 10
>>> b = a + 10
>>> b
20
>>> a = b
>>> a
20

En este ejemplo hacemos que a haga referencia al valor 10, y después creamos b a par r de a
y otro 10. Gracias a la precedencia, primero se resuelve el lado derecho completo obteniendo
un 20 y después se asigna la referencia b a ese valor.
Si queremos, después podemos reasignar el símbolo a a otro valor nuevo, en este caso al
que hacer referencia b, que es 20.
En este primer ejemplo, ningún valor está siendo alterado, si te fijas, sólo estamos creando
nuevos valores y cambiando las referencias a éstos.
Con los datos mutables podemos alterar los valores. Lo vemos con otro ejemplo:
>>> a = {}
>>> b = a
>>> a["cambio"] = "hola!"
>>> b
{'cambio': 'hola!'}

Primero creamos un diccionario vacío y le asignamos la referencia a. Después le asignamos la


referencia b a quien referenciaba a, es decir, al diccionario vacío. Ambas referencias apuntan
al mismo dato. Si después usamos alguna alteración en el diccionario a como asignarle una
nueva clave, b, que hace referencia al mismo diccionario, también ve los cambios. Esto mismo
podría hacerse si se tratara de listas, ya que enen la capacidad de alterarse a sí mismas, pero
nunca podría hacerse en tuplas, porque son inmutables.

Los diccionarios y las listas soportan un montón de funciones y alteraciones, no


se mencionan en este apartado porque nunca terminaría. Se dejan para el futuro
y para los ejemplos que se verán durante el documento.

21
CAPÍTULO 2. TRABAJANDO CON DATOS

Si intentásemos un ejemplo similar en tupla, no nos dejaría:


>>> a = ()
>>> b = a
>>> a[0] = 1
Traceback (most recent call last):
File "<pyshell#67>", line 1, in <module>
a[0] = 1
TypeError: 'tuple' object does not support item assignment

Ten cuidado cuando trates con elementos mutables, sobre todo si enen muchas referencias,
porque puede que estés alterando los valores en lugares que no te interesa. Para evitar este
po de problemas, puedes generar copias de los objetos, pero el proceso es poco eficiente
y tedioso.
En este segundo caso, creamos una copia de a para que b sea independiente de los cambios
que ocurran en ésta. Aquí ya no estamos haciendo referencia desde b a los datos que había
en a, sino a una copia de éstos, almacenada en otro lugar.
>>> a = {}
>>> b = dict(a)
>>> a["cambio"] = "hola!"
>>> b
{}
>>> a
{'cambio': 'hola!'}

2.6 Lo que has aprendido


En este apartado has conocido los pos fundamentales de python y cómo conver r de uno
a otro. Además, al conocer los operadores y su funcionamiento ya eres más o menos capaz
de usar python como una calculadora.
Además, has tenido ocasión de entender de forma superficial varios conceptos avanzados
como el manejo automá co de memoria, el pado dinámico y los números de coma flotante,
que son muy interesantes a la hora de trabajar porque te permiten comprender la realidad
que enes a tu alrededor.

22 Ekaitz Zárraga
Programar en Python

3 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).
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 cuáles 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) es lo que define
dónde empieza o termina un bloque en python. Las líneas consecu vas 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. Pue-
des usar dos espacios, el tabulador, cuatro espacios o lo que desees, pero elijas lo que elijas
debe ser coherente en todo el documento. Los editores de código, como IDLE, pueden con-
figurarse para usar una anchura de indentación concreta, que se insertará cuando pulses la
tecla tabulador. El estándar de python es cuatro espacios.

23
CAPÍTULO 3. ESTRUCTURA DEL LENGUAJE

3.1 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.

3.1.1 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 con nuación:
# En este ejemplo se muestran comentarios, como este mismo
print("Hola") # Esto es otro comentario

3.1.2 Control de flujo


Como ya se ha adelantado, es posible cambiar el orden de ejecución del programa en función
de unas normas para evitar que el programa ejecute ciertas sentencias o repita la ejecución
de algunos bloques. 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:
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 expresiones de python
cuyo resultado sea True o False. Cuando la expresión resulte en un True la condición se
cumplirá y el bloque interior se ejecutará.

24 Ekaitz Zárraga
3.1. SINTAXIS GENERAL

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

Bucles

Existen dos pos de sentencia para hacer repe ciones 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 repe rla en función de una condición.

While
El while («mientras que») es la más sencilla de estas estructuras, y la menos usada.
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í sucesiva-
mente.
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 rela vamente 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 mencio-
namos anteriormente pero que en este caso toma un uso dis nto:
>>> 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.

25
CAPÍTULO 3. ESTRUCTURA DEL LENGUAJE

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

Truthy and Falsey

En este po de sentencias donde se comprueba si una condición es verdadera o falsa, python


automá camente trata de conver r el resultado a Boolean usando la función bool que ya
conoces del apartado sobre pos. No es necesario que conviertas a Boolean manualmente
ya que estas sentencias disponen de una conversión implícita a Boolean1 .
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 rela vamente sencillo prever qué valores son truthy o falsey, normalmente los valores que
representan un vacío se consideran False.

3.1.3 List comprehensions


Una de las excepciones sintác cas 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á cas.
Como mejor se en ende 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)
>>> { 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 desde el propio número, así que se comportará de forma similar a una lista, ya
que los índices serán numéricos. Eso sí, las claves no estarán ordenadas.
1
La documentación oficial de python describe estas conversiones en detalle en la sección Truth value tes ng.

26 Ekaitz Zárraga
3.1. SINTAXIS GENERAL

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 úl mo de los ejemplos,
para filtrar algunos casos.
Te habrá mosqueado el uso de tuple para crear la tupla. Todo ene una razón. En la tupla,
al estar formada por paréntesis, python no ene 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>

3.1.4 Excepciones
Las excepciones o excep on 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 ges onen. Se consideran
fallos de los que el programa no se puede recuperar a no ser que se le indique cómo. Algunas
funciones y librerías lanzan excepciones que nosotros debemos ges onar, por ejemplo: que
un archivo no exista, o que no se tenga permisos de edición en el directorio, etc. Es nuestra
responsabilidad tener un plan be o aceptar la excepción depor vamente a sabiendas que
nuestro programa terminará indicando un error.
Hay ocasiones en las que las excepciones pueden capturarse y otras en las que 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.
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.


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.
try:
# Bloque que puede lanzar un ValueError

27
CAPÍTULO 3. ESTRUCTURA DEL LENGUAJE

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 para entender cómo
hacerlo. Te adelanto que python ene una larga lista de excepciones y que está considerado
una mala prác ca crear nuevas si las excepciones por defecto cubren un caso similar al que
se encuentra en nuestro programa.

3.1.5 Funciones
Las funciones sirven, sobre todo, para reu lizar código. Si una pieza de código se u liza en
más de una ocasión en tu programa, es una buena candidata para agruparse en una función
y poder reu lizarla sin necesidad de duplicar el código fuente. Aunque sirven para más fines
y enen 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.
La definición de funciones se realiza con una estructura similar a las anteriores, una línea
descrip va terminada en dos puntos (:) y después un bloque con mayor sangría para definir
el cuerpo.
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:


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 po función!
Pronto ahondaremos más en este tema. De momento recuerda la declaración de las funcio-
nes. 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

28 Ekaitz Zárraga
3.1. SINTAXIS GENERAL

adelanto que cuando llamaste a la función range anteriormente, le introdujiste dos argumen-
tos. Esos dos argumentos deben declararse como argumentos de entrada. Probablemente
de una forma similar a esta:
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:
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 en endes.

3.1.6 Sentencias ú les


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 san-
grí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
...

29
CAPÍTULO 3. ESTRUCTURA DEL LENGUAJE

Suele u lizarse 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.

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.

Con nue

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:
text = "texto de prueba"
pos = 0

for i in text:
if i == "b":

30 Ekaitz Zárraga
3.2. LO QUE HAS APRENDIDO

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 ele-
gante y te será ú l.

Return

La sentencia return sólo ene sen do dentro de las funciones. Sirve para finalizar la eje-
cución de una función sus tuyendo 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 sus tuir al break en muchas ocasiones.

3.2 Lo que has aprendido


Es di 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 refe-
rencia 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 empo 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 men ra mediante los valores
truthy y falsey, para después avanzar a las list comprehensions, cuyo nombre con ene 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 haber visitado, aún, la programación orientada a objetos. Pero calma,
pronto lo haremos.
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 ú les que hemos recopilado al final permiten juguetear con todas las estruc-
turas que hemos definido en el capítulo de modo que puedas usarlas a tu antojo de forma

31
CAPÍTULO 3. ESTRUCTURA DEL LENGUAJE

cómoda. Algunas de ellas como continue y break no son realmente necesarias, puede pro-
gramarse evitándolas y, de hecho, en algunos lugares enseñan a no usarlas, como si de una
buena prác ca se tratara, cambiando las condiciones de los bucles para que hagan esta la-
bor. 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 sen-
tencias que simplifican el código haciéndolo más legible o más sencillo por muy impuras que
a algunos programadores les puedan parecer.

32 Ekaitz Zárraga
Programar en Python

4 Funciones

El obje vo de este capítulo es que te familiarices con el uso de las funciones. Parece sencillo
pero es una tarea un tanto complicada porque, visto cómo nos gusta hacer las cosas, tenemos
una gran can dad de complejidad que abordar.

Antes de entrar, vamos a definir una función y a usarla un par de veces:


def inc(a):
b = a + 1
return b

Si la llamamos:
>>> inc(1)
2
>>> inc(10)
11

Cuidado con las declaraciones internas en las funciones. Si preguntamos por b:


>>> b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'b' is not defined

Parece que no conoce el nombre b. Esto es un tema relacionado con el scope.

4.1 Scope
Anteriormente se ha dicho que python es un lenguaje de programación con ges ón automá-
ca de la memoria. Esto significa que él mismo es capaz de saber cuándo necesita pedir más
memoria al sistema opera vo y cuándo quiere liberarla. El scope es un resultado este siste-
ma. Para que python pueda liberar memoria, necesita de un proceso conocido como garbage
collector (recolector de basura), que se encarga de buscar cuándo las referencias ya no van a
poder usarse más para pedir una liberación de esa memoria. Por tanto, las referencias enen
un empo de vida, desde que se crean hasta que el recolector de basura las elimina. Ese
empo de vida se conoce como scope y, más que en empo, se trata en términos de espacio
en el programa.

El recolector de basura ene unas normas muy estrictas y conociéndolas es fácil saber en
qué espacio se puede mover una referencia sin ser disuelta.

Resumiendo mucho, las referencias que crees se man enen vivas hasta que la función ter-
mine. Como en el caso de arriba la función en la que se había creado b había terminado,

33
CAPÍTULO 4. FUNCIONES

b había sido limpiada por el recolector de basura. b era una referencia local, asociada a la
función inc.

Puede haber referencias declaradas fuera de cualquier función, que se llaman globales. Éstas
se man enen accesibles desde cualquier punto del programa, y se man enen vivas hasta
que éste se cierre. Considera que el propio programa es una función gigante que engloba
todo.

Python define que cualquier declaración está disponible en bloques internos, pero no al
revés. El siguiente ejemplo lo muestra:
c = 100
def funcion():
a = 1
# Se conoce c aquí dentro
# Aquí fuera no se conoce a

El scope es peculiar en algunos casos que veremos ahora, pero mientras tengas claro que se
ex ende hacia dentro y no hacia fuera, todo irá bien.

4.2 First-class ci zens


Antes de seguir jugando con el scope, necesitas saber que las funciones en python son lo que
se conoce como first-class ci zens (ciudadanos de primera clase). Esto significa que pueden
hacer lo mismo que cualquier otro valor.

Las funciones son un valor más del sistema, como puede ser un string, y su nombre no es
más que una referencia a ellas.

Por esto mismo, pueden ser enviadas como argumento de entrada a otras funciones, de-
vueltas con sentencias return o incluso ser declaradas dentro de otras funciones.

Por ejemplo:
>>> def filtra_lista(list):
... def mayor_que_4(a):
... return a > 4
... return list( filter(mayor_que_4, lista) )
...
>>> filtra_lista( [1,2,3,4,5,6,7] )
[5, 6, 7]

En este ejemplo, haciendo uso de la función filter (usa la ayuda para ver lo que hace),
filtramos todos los elementos mayores que 4 de la lista. Pero para ello hemos creado una
función que sirve para compararlos y se la hemos entregado a la función filter.

Este ejemplo no ene más interés que intentar enseñarte que puedes crear funciones co-
mo cualquier otro valor y asignarles un nombre, para después pasarlas como argumento de
entrada a otra función.

34 Ekaitz Zárraga
4.3. LAMBDAS

4.3 Lambdas

Las funciones lambda1 o funciones anónimas son una forma sencilla de declarar funciones
simples sin tener que escribir tanto. La documentación oficial de python las define como
funciones para vagos.

La sintaxis de una función lambda te la enseño con un ejemplo:


>>> lambda x,y: x + y
<function <lambda> at 0x7f035b879950>
>>> (lambda x,y: x + y)(1,2)
3

En el primer ejemplo se muestra la declaración de una función lambda. En el segundo, co-


locando los paréntesis de precedencia y después de llamada a función, se construye una
función lambda y después se ejecuta con los valores 1 y 2.

Es fácil de entender la sintaxis de la función lambda, básicamente es una función reducida


de sólo una sentencia con un return implícito.

El ejemplo de la función filtra_lista puede reducirse mucho usando una función lambda:
>>> def filtra_lista( lista ):
... return list( filter(lambda x: x > 4, lista) )
...
>>> filtra_lista( [1,2,3,4,5,6,7] )
[5, 6, 7]

No necesitábamos una función con nombre en este caso, porque sólo iba a u lizarse esta
vez, así que resumimos y reducimos tecleos.

De todos modos, podemos asignarlas a una referencia para poder repe r su uso:
>>> f = lambda x: x + 1
>>> f(1)
2
>>> f(10)
11
>>> f
<function <lambda> at 0x7f02184febf8>

Las funciones lambda se usan un montón como closure, un concepto donde el scope se tra-
baja más allá de lo que hemos visto. Sigamos visitando el scope, para entender sus usos más
en detalle.

4.4 Scope avanzado


Cada vez que se crea una función, python crea un nuevo contexto para ella. Puedes entender
el concepto de contexto como una tabla donde se van guardando las referencias que se
declaran en la función. Cuando la función termina, su contexto asociado se elimina, y el
1
Toman su nombre del Lambda Calculus.

35
CAPÍTULO 4. FUNCIONES

recolector de basura se encarga de liberar la memoria de sus referencias, tal y como vimos
anteriormente.
Lo que ocurre es que estos contextos son jerárquicos, por lo que, al crear una función, el
padre del contexto que se crea es el contexto de la función madre. Python u liza esto como
método para encontrar las referencias. Si una referencia no se encuentra en el contexto
actual, python la buscará en el contexto padre y así sucesivamente hasta encontrarla o lanzar
un error diciendo que no la conoce. Esto explica por qué las referencias declaradas en la
función madre pueden encontrarse y accederse y no al revés.
Aunque hemos explicado el scope como un concepto asociado a las funciones, la realidad es
que hay varias estructuras que crean nuevos contextos en python. El comportamiento sería
el mismo del que se ha hablado anteriormente, las referencias que se creen en ellos no se
verán en el scope de nivel superior, pero sí al revés. Los casos son los siguientes:
• Los módulos. Ver capítulo correspondiente
• Las clases. Ver capítulo de Programación Orientada a Objetos.
• Las funciones, incluidas las funciones anónimas o lambda.
• Las expresiones generadoras definidas en el PEP-2892 , que normalmente se encuen-
tran en las list-comprehension que ya se han tratado en el capítulo previo.

4.4.1 Scope léxico, Closures


Hemos dicho que las funciones pueden declararse dentro de funciones, pero no hemos ha-
blado de qué ocurre con el scope cuando la función declarada se devuelve y ene una vida
más larga que la función en la que se declaró. El siguiente ejemplo te pone en contexto:
def create_incrementer_function(increment):
def incrementer (val):
# Recuerda que esta función puede ver el valor `increment` por
# por haber nacido en un contexto superior.
return val + increment
return incrementer

increment10 = create_incrementer_function(10)
increment10(10) # 20
increment1 = create_incrementer_function(1)
increment1(10) # 11

En este ejemplo hemos creado una función que construye funciones que sirven para incre-
mentar valores.
Las funciones devueltas viven durante más empo que la función que las albergaba por lo
que saber qué pasa con la variable increment es di cil a simple vista.
Python no destruirá ninguna variable a la que todavía se pueda acceder, si lo hiciera, las fun-
ciones devueltas no funcionarían porque no podrían incrementar el valor. Habrían olvidado
con qué valor debían incrementarlo.
2
Los PEP son documentos donde se proponen mejoras para el lenguaje. Puedes leer el contenido completo
del PEP en:
https://www.python.org/dev/peps/pep-0289/

36 Ekaitz Zárraga
4.4. SCOPE AVANZADO

Para que esto pueda funcionar, las funciones guardan el contexto del momento de su crea-
ción, así que la función incrementer recuerda la primera vez que fue construida en un con-
texto en el que increment valía 10 y la nueva incrementer creada en la segunda ejecución
de create_incrementer_function recuerda que cuando se creó increment tomó el valor
1. Ambas funciones son independientes, aunque se llamen de la misma forma en su con-
cepción, no se pisaron la una a la otra, porque pertenecían a contextos dis ntos ya que la
función que las creaba terminó y luego volvió a iniciarse.
Este funcionamiento donde el comportamiento de las funciones depende del lugar donde
se crearon y no del contexto donde se ejecutan se conoce como scope léxico.
Las closures son una forma de implementar el scope léxico en un lenguaje cuyas funciones
sean first-class ci zens, como es el caso de python, y su funcionamiento se basa en la cons-
trucción de los contextos y su asociación a una función capaz de recordarlos aunque la fun-
ción madre haya terminado.
Python analiza cada función y revisa qué referencias del contexto superior deben mante-
nerse en la función. Si encuentra alguna, las asocia a la propia función creando así lo que se
conoce como closure, una función que recuerda una parte del contexto. No todas las funcio-
nes necesitan del contexto previo así que sólo se crean closures en función de lo necesario.
Puedes comprobar si una función es una closure analizando su campo __closure__. Si no es-
tá vacío (valor None), significará que la función es una closure como la que ves a con nuación.
Una closure que recuerda un int del contexto padre:
>>> f.__closure__
(<cell at 0x7f04b4ebfa68: int object at 0xa68ac0>,)

Lo que estás viendo lo entenderás mejor cuando llegues al apartado de programación orien-
tada a objetos. Pero, para empezar, ves que con ene una tupla con una cell de po integer.
A nivel prác co, las closures son ú les para muchas labores que iremos desgranando de
forma accidental. Si enes claro el concepto te darás cuenta dónde aparecen en los futuros
ejemplos.

4.4.2 Global y No-local


Hemos hablado de qué sentencias crean nuevos contextos, pero no hemos hablado de qué
pasa si esos nuevos contextos crean referencias cuyo nombre es idén co al de las referencias
que aparecen en contextos superiores.
Par endo de lo que se acaba de explicar, y antes de adentrarnos en ejemplos, si se crea una
función (o cualquiera de las otras estructuras) python creará un contexto para ella. Una vez
creado, al crear una variable en este nuevo contexto, python añadirá una nueva entrada en
su tabla hija con el nombre de la variable. Al intentar consultarla, python encontrará que
en su tabla hija existe la variable y tomará el valor con el que la declaramos. Cuando la
función termine, la tabla de contexto asociada a la función será eliminada. Esto siempre es
así, independientemente del nombre de referencia que hayamos seleccionado. Por tanto, si
el nombre ya exis a en alguno de los contextos padre, lo ocultaremos, haciendo que dentro
de esta función se encuentre el nombre recién declarado y no se llegue a buscar más allá.

37
CAPÍTULO 4. FUNCIONES

Cuando la función termine, como el contexto asociado a ésta no está en la zona de búsqueda
de la función madre, en la función madre el valor seguirá siendo el que era.

Ilustrándolo en un ejemplo:
>>> a = 1
>>> def f():
... a = 2
... print(a)
...
>>> f()
2
>>> a
1

Aunque el nombre de la referencia declarada en el interior sea el mismo que el de una re-
ferencia externa su declaración no afecta, lógicamente, al exterior ya que ocurre en un con-
texto independiente.

Para afectar a la referencia global, python dispone de la sentencia global. La sentencia


global afecta al bloque de código actual, indicando que los iden ficadores listados deben
interpretarse como globales. De esta manera, si se reasigna una referencia dentro de la fun-
ción, no será el contexto propio el que se altere, sino el contexto global, el padre de todos
los contextos.
>>> a = 1
>>> def f():
... global a
... a = 2
... print(a)
...
>>> f()
2
>>> a
2

Te recomiendo, de todas formas, que nunca edites valores globales desde el


cuerpo de funciones. Es más elegante y comprensible si los efectos de las fun-
ciones sólo se aprecian en los argumentos de entrada y salida.

Para más detalles sobre limitaciones y excepciones, puedes buscar en la ayuda ejecutando
help("global").

El caso de nonlocal es similar, sin embargo, está diseñado para trabajar en contextos anida-
dos. Es decir, en lugar de saltar a acceder a una variable global, nonlocal la busca en cual-
quier contexto que no sea el actual. nonlocal comienza a buscar las referencias en el con-
texto padre y va saltando hacia arriba en la jerarquía en busca de la referencia. Para saber
más: help("nonlocal").

La diferencia principal entre ambas es que global puede crear nuevas referencias, ya que se
sabe a qué contexto debe afectar: al global. Sin embargo, nonlocal necesita que la referencia
a la que se pretende acceder esté creada, ya que no es posible saber a qué contexto se

38 Ekaitz Zárraga
4.5. ARGUMENTOS DE ENTRADA Y LLAMADAS

pretende acceder.
Las sentencias global y nonlocal son tramposas, ya que dificultan la comprensión del pro-
grama. La mejor recomendación que puede hacerse es tratar de evitarlas. Usarlas en exceso
es, en general, un indicador de un mal diseño de programa.

4.5 Argumentos de entrada y llamadas


Los argumentos de entrada se definen en la declaración de la función y se ha dado por hecho
que es evidente que se separan por comas (,) y que, a la hora de llamar a la función, deben
introducirse en el orden en el que se han declarado. Por mucho que esto sea cierto, requiere
de una explicación más profunda.

4.5.1 Callable
En python las funciones son un po de callable, «cosa que puede ser llamada» en inglés. Esto
significa, de algún modo que hay otras cosas que pueden ser llamadas que no sean funciones.
Y así es.
Para python cualquier valor que soporte la aplicación de los paréntesis se considera «llama-
ble». En el apartado de programación orientada a objetos entenderás esto en detalle. De
momento, piensa que, igual que pasa al acceder a los campos de una colección usando los
corchetes, siempre que python se encuentre unos paréntesis después de un valor tratará de
ejecutar el valor. Así que los paréntesis no son una acción que únicamente pueda aplicarse
en nombres de función3 y python no lanzará un fallo de sintaxis cuando los usemos fuera
de lugar, sino que será un fallo de empo de ejecución al darse cuenta de lo que se intenta
ejecutar no es ejecutable.
>>> 1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable

Caso de estudio: Switch Case

Si quieres ver un ejemplo avanzado de esto, te propongo la creación de la estructura switch-


case, que puede encontrarse en otros lenguajes, pero que en lugar de usar una estructura
basada en un if con múl ples elif uses un diccionario de funciones.
Las funciones son valores, por lo que pueden ocupar un diccionario como cualquier otro
valor. Construyendo un diccionario en cuyas claves se encuentran los casos del switch-case
y en cuyos valores se encuentran sus funciones asociadas se puede crear una sentencia con
el mismo comportamiento.
En el siguiente ejemplo se plantea una aplicación por comandos. Captura el tecleo del usua-
rio y ejecuta la función asociada al comando. Las funciones no están escritas, pero puedes
3
Aunque en realidad esto ya lo has visto en los ejemplos de las funciones lambda.

39
CAPÍTULO 4. FUNCIONES

completarlas y analizar su comportamiento. Las palabras que no en endas puedes consul-


tarlas en la ayuda.
def borrar(*args):
pass
def crear(*args):
pass
def renombrar(*args):
pass

casos = {
"borrar": borrar,
"crear": crear,
"renombrar": renombrar
}

comando = input("introduce el comando> ")

try:
casos[comando]()
except KeyError:
print("comando desconocido")

4.5.2 Posi onal vs Keyword Arguments


Las funciones enen dos pos de argumentos de entrada, aunque sólo hayamos mostrado
uno de ellos de momento.
El que ya conoces se denomina posi onal argument y se refiere a que son argumentos que se
definen en función de su posición. Los argumentos posicionales deben ser situados siempre
en el mismo orden, si no, los resultados de la función serán dis ntos.
Observa el siguiente ejemplo. Las referencias source y target toman el primer argumento
y el segundo respec vamente. Darles la vuelta resulta en el resultado opuesto al que se
pretendía.
def move_file ( source, target ):
"Mueve archivo de `source` a `target"
pass

move_file("file.txt", "/home/guido/doc.txt")
# "file.txt" -> "/home/guido/doc.txt"
move_file("/home/guido/doc.txt", "file.txt")
# "/home/guido/doc.txt"-> "file.txt"

Los keyword argument o argumentos con nombre, por otro lado, se comportan como un dic-
cionario. Su orden no importa pero es necesario marcarlos con su respec va clave. Además,
son opcionales porque en el momento de la declaración de la función python te obliga a que
les asocies un valor por defecto (default). En el siguiente ejemplo se convierte la función a
una basada en argumentos con nombre. No se han u lizado valores por defecto especiales,
pero pueden usarse otros.
def move_file(source=None, target=None):
"Mueve archivo de `source` a `target"

40 Ekaitz Zárraga
4.5. ARGUMENTOS DE ENTRADA Y LLAMADAS

pass

move_file(source="file.txt", target="/home/guido/doc.txt")
# "file.txt" -> "/home/guido/doc.txt"
move_file(target="/home/guido/doc.txt", source="file.txt")
# "file.txt" -> "/home/guido/doc.txt"

Si quieres que sean obligatorios, siempre puedes lanzar una excepción.

Para funciones que acepten ambos pos de argumento, es obligatorio declarar e introducir
todos los argumentos posicionales primero. Es lógico, porque son los que requieren de una
posición.
También es posible declarar funciones que acepten cualquier can dad de argumentos de un
po u otro. Ésta es la sintaxis:
def argument_catcher( *args, **kwargs ):
"Función ejecutable con cualquier número de argumentos de entrada, tanto
posicionales como con nombre."
print( args )
print( kwargs )

Los nombres args y kwargs son convenciones que casi todos los programadores de python
u lizan, pero puedes seleccionar los que quieras. Lo importante es usar * para los argumen-
tos posicionales y ** para los argumentos con nombre.
Prueba a ejecutar la función del ejemplo, verás que los argumentos posicionales se capturan
en una tupla y los argumentos con nombre en un diccionario.
Este po de funciones mul argumento se u lizan mucho en los decorators, caso que estu-
diaremos al final de este capítulo.

Peligro: mutable defaults

Existe un caso en el que enes que tener mucho cuidado. Los valores por defecto en los
argumentos con nombre se memorizan de una ejecución de la función a otra. En caso de
que sean valores inmutables no tendrás problemas, porque su valor nunca cambiará, pero si
almacenas en ellos valores mutables y los modificas, la próxima vez que ejecutes la función
los valores por defecto habrán cambiado.
La razón por la que los valores por defecto se recuerdan es que esos valores se construyen
en la creación de la función, no en su llamada. Lógicamente, puesto que es en la sentencia
def donde aparecen.
>>> def warning(default=[]):
... default.append(1)
... return default
...
>>> warning()
[1]
>>> warning()
[1, 1]
>>> warning()

41
CAPÍTULO 4. FUNCIONES

[1, 1, 1]
>>> warning()
[1, 1, 1, 1]

4.6 Decorators
Los decorators son un concepto que, a pesar de ser bastante concreto, nos permite descu-
brir todo el potencial de lo que se acaba de tratar en este apartado. Sirven para dotar a las
funciones de caracterís cas adicionales.
Por ejemplo, éste es un decorador que mide el empo de ejecución de una función. No lo
consideres la forma adecuada para hacerlo porque no es para nada preciso, pero es suficiente
para entender el funcionamiento de lo que queremos representar:
1 >>> import time
2 >>> def timer(func_to_decorate):
3 ... def decorated_function(*args, **kwargs):
4 ... start = time.time()
5 ... retval = func_to_decorate(*args, **kwargs)
6 ... end = time.time()
7 ... print("Function needed:", end - start, "s to execute")
8 ... return retval
9 ... return decorated_function
10 ...
11 >>> @timer
12 ... def my_function(secs):
13 ... time.sleep(secs)
14 ... return "whatever"
15 ...
16 >>> my_function(1)
17 Function needed: 1.0002844333648682 s to execute
18 'whatever'
19 >>> my_function(4)
20 Function needed: 4.004255533218384 s to execute
21 'whatever'
22 >>>

Hay muchos detalles que te habrán llamado la atención del ejemplo, el uso de @timer pro-
bablemente sea uno de ellos. Éste es, sin embargo, el detalle menos importante ya que úni-
camente se trata de un poco de syntac c sugar4 .
Los decorators pueden entenderse como un envoltorio para una función. No son más que
una función que devuelve otra. En el caso del decorador del ejemplo, el decorator timer
es una función que recibe otra función como argumento de entrada y devuelve la función
decorated_function. Este decorador, al aplicarlo a una función con @timer está haciendo
lo siguiente:
my_function = timer(my_function)

4
El syntac c sugar son simplificaciones sintác cas que el lenguaje define para acortar expresiones muy u li-
zadas. El ejemplo clásico de syntac c sugar es:
a += b
Que es equivalente a:
a = a + b

42 Ekaitz Zárraga
4.6. DECORATORS

@decorator es syntac c sugar de fn = decorator(fn). Simplemente, es más


corto y más bonito.

Por lo que la función my_function ya no es lo que creíamos. Se ha sobrescrito con


decorated_function. En el ejemplo, la función decorated_function llama a la fun-
ción function_to_decorate de la función madre (decorated_function es una closure).
Cuando se aplica el decorador sobre my_function, la función function_to_decorate es
my_function para esa closure.
La línea 5 del ejemplo traslada los argumentos capturados en la función decorated_function
a la función function_to_decorate usando los mismos asteriscos que se u lizan para
declarar la captura de argumentos. Estos asteriscos son necesarios porque los argumentos
en args y kwargs están guardados en una tupla y un diccionario respec vamente y deben
desempaquetarse para que se inserten sus contenidos como argumentos de la función. De
no aplicarse, se llamaría a la función con dos argumentos: una tupla y un diccionario.
Al capturar todos los argumentos y pasarlos tal y como se recibieron a la función decorada,
el decorador timer es transparente para la función. La función cree que ha sido llamada
de forma directa aunque se haya añadido funcionalidad alrededor de ésta que es capaz de
contar el empo de ejecución.
Si se desea, se pueden alterar args y kwargs para transformar los argumentos de la llamada
a la función, pero es algo que debe hacerse cuidadosamente porque deformar las llamadas
a las funciones puede confundir a quien aplique el decorador.
Los decoradores, usados de forma tan cruda, añaden ciertos problemas. El principal es que
la función que hemos decorado ya no es la que parecía ser, así que su docstring, sus argu-
mentos de entrada, etc. ya no pueden comprobarse desde la REPL usando la ayuda, ya que
la ayuda buscaría la ayuda de la función devuelta por el decorador (decorated_function en
el ejemplo). Usando @functools.wraps5 podemos resolver este problema.
La realidad es que los decorators son una forma muy elegante de añadir funcionalidades a
las funciones sin complicar demasiado el código. Permiten añadir capacidad de depuración,
profiling y todo po de funcionalidades que se te ocurran.
Este apartado se deja varias cosas en el ntero, como los decoradores con parámetros de
entrada, pero no pretende ser una referencia de cómo se usan, sino una introducción a un
concepto ú l que resume perfectamente lo tratado durante todo el capítulo.
Te animo, como ejercicio, a que analices el decorador @lru_cache del módulo functools
y comprendas su interés y su funcionamiento. Para leerlo en la ayuda debes importar el
módulo functools primero. Como aún no sabes hacerlo, aquí enes la receta:
>>> import functools
>>> help(functools.lru_cache)

A parte de los decoradores de funciones, python permite decorar clases. No son di ciles de
5
Puedes leer por qué y cómo en la documentación oficial de python:
https://docs.python.org/3/library/functools.html#functools.wraps

43
CAPÍTULO 4. FUNCIONES

entender una vez se conocen los decoradores de funciones así que te animo a que los inves-
gues cuando hayas estudiado la programación orientada a objetos en el capítulo siguiente.

4.7 Lo que has aprendido


Este capítulo puede que sea el más complejo de todos los que te has encontrado y te encon-
trarás. En él has aprendido a declarar y a usar funciones, cosa sencilla, y todos los conceptos
importantes relacionados con ellas. Un conocimiento que es ú l en python, pero que puede
ser extendido a casi cualquier lenguaje.
Tras un sencillo acercamiento al scope, has comprendido que las funciones en python son
sólo un valor más, como puede ser un int, y que pueden declararse en cualquier lugar, lo
que te abre la puerta a querer declarar funciones sencillas sin nombre, que se conocen como
funciones lambda.
Una vez has aclarado que las funciones son ciudadanos de primera clase (first-class ci zens)
ya era momento de afrontar la realidad del scope donde has tratado los contextos y cómo
funcionan definiendo el concepto del scope léxico que, colateralmente, te ha enseñado lo
que es una closure, un método para implementarlo.
Pero no había quedado claro en su momento cómo funcionaban los argumentos de entrada
y las llamadas a las funciones, así que has tenido ocasión de ver por primera vez lo que es
un callable en python, aunque se te ha prome do analizarlo en el futuro. Lo que sí que has
tratado en profundidad son los argumentos posi onal y keyword, y cómo se u lizan en todas
sus posibles formas.
Finalmente, para agrupar todo esto en un único concepto, se te han mostrado los decorators,
aunque de forma muy general, con el fin de que vieras que todo lo que se ha tratado en este
capítulo aparece en conceptos avanzados y es necesario entenderlo si quieren llegar a usarse
de forma eficiente.

44 Ekaitz Zárraga
Programar en Python

5 Orientación a Objetos

La programación orientada a objetos u object oriented programming (OOP) es un paradigma de


programación que envuelve python de pies a cabeza. A pesar de que python se define como
un lenguaje de programación mul paradigma, la programación orientada a objetos es el pa-
radigma principal de éste. Aunque varias de las caracterís cas que tratamos en el apartado
anterior se corresponden más con un lenguaje de programación funcional, en python todo
(o casi todo) es una clase.
Python usa una programación orientada a objetos basada en clases, a diferencia de otros
lenguajes como JavaScript, donde la orientación a objetos está basada en proto pos. No es
el obje vo de este documento el de contarte cuáles son las diferencias entre ambas, pero es
interesante que sepas de su existencia, ya que es una de las pocas diferencias que existen
entre estos dos lenguajes de amplio uso en la actualidad.

5.1 Programación basada en clases


Tras haber hecho una afirmación tan categórica como que en python todo son clases, es
nuestra obligación entrar a definir lo que son y qué implica la programación basada en clases.
Los objetos, objects, son en dades que encapsulan un estado, un comportamiento y una
iden dad capaz de separarlos de otras en dades. Una clase, class, es la descripción de estos
objetos.
Saliendo de la definición filosófica y trayéndola a un nivel de andar por casa, puedes aclararte
sabiendo que las clases son la definición enciclopédica de algo, mientras que los objetos son
el propio objeto, persona o animal descrito.
Llevándolo al ejemplo de un perro, la clase es la definición de qué es un perro y los objetos
son los dis ntos perros que te puedes encontrar en el mundo. La definición de perro indica
qué caracterís cas ha de tener un ente para ser un perro, como ser un animal, concretamente
domés co, qué anatomía debe tener, cómo debe comportarse, etc. Mientras que el propio
perro es uno de los casos de esa definición.
Cada perro ene una iden dad propia y es independiente de los otros, ene un comporta-
miento concreto (corre, salta, ladra…) y ene un estado (está despierto o dormido, ene una
edad determinada…).
La diferencia entre una clase y un objeto ene lógica si lo piensas desde la perspec va de
que python no ene ni idea de lo que es un perro y tú enes que explicárselo. Una vez lo
haces, declarando tu clase, puedes crear diferentes perros y ponerlos a jugar. Lo bonito de
programar es que tu programa es tu mundo y tú decides lo que es para (o para tu programa)
un perro.

45
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

A nivel prác co, los objetos son grupos de datos (el estado) y funciones (la funcionalidad).
Estas funciones son capaces de alterar los datos del propio objeto y no de otro (se intuye el
concepto de iden dad). Analizándolo desde el conocimiento que ya enes, es lógico pensar
que un objeto es, por tanto, una combinación de valores y funciones accesible a modo de
elemento único. Exactamente de eso se trata.

Existe una terminología técnica, eso sí, para referirse a esos valores y a esas funciones. Nor-
malmente los valores se conocen como propiedades del objeto y las funciones se conocen
como métodos. Así que siempre que hagamos referencia a cualquiera de estas dos palabras
clave debes recordar que hacen referencia a la programación orientada a objetos.

5.1.1 Fundamento teórico


La programación basada en clases se basa en tres conceptos fundamentales que repasare-
mos aquí de forma rápida para razonar el interés de la programación orientada a objetos
sobre otros paradigmas.

La encapsulación trata de crear datos que restrinjan el acceso directo su contenido con el
fin de asegurar una coherencia o robustez interna. Puedes entender esto como una forma
de esconder información o como mi profesor de Programación II en la universidad solía de-
cir: «Las patatas se pelan en la cocina del restaurante, no en el comedor». La u lidad de la
encapsulación es la de aislar secciones del programa para tener total control sobre su con-
tenido gracias a tener total control de la vía de acceso a estos datos. A nivel prác co este
concepto puede usarse para, por ejemplo, obligar a que un objeto sólo pueda ser alterado
en incrementos controlados en lugar de poder pisarse con un valor arbitrario.

La herencia es un truco para reu lizar código de forma agresiva que, casualmente, sirve co-
mo una buena forma de razonar. Aporta la posibilidad de crear nuevas clases a par r de
clases ya existentes. Volviendo a la simplificación anterior, si una clase es una definición en-
ciclopédica de un concepto, como un perro, puede estar basada en otra descripción para
evitar contar todo lo relacionado con ella. En el caso del perro, el perro es un animal. Ani-
mal podría ser otra clase definida previamente de la que el perro heredara y recibiera gran
parte de su descripción genérica para sólo cubrir puntos que necesite especificar como el
tamaño, la forma, el po de animal, el comportamiento concreto, etc. Existe la posibilidad
de hacer herencias múl ples también ya que algunos conceptos pueden describirse en dos
superclases dis ntas: un perro es un animal (vive, muere, se alimenta, se reproduce) y tam-
bién es terrestre (camina sobre una superficie, etc). Ambos conceptos son independientes:
los coches también son terrestres pero no son animales y los peces también son animales
pero no terrestres.

Y, finalmente, el polimorfismo. La propia e mología de la palabra define con bastante pre-


cisión el concepto, pero aplicarlo a la programación orientada a objetos no es tan evidente.
Existen varios pos de polimorfismo pero el más sencillo es entender el subtyping. Una vez
lo comprendas el resto será evidente. Si volvemos al ejemplo del perro, para ciertos compor-
tamientos, nos da igual que tratemos de perros, de peces o de pájaros, todos son animales y
todos los animales se comportan de la misma forma. Es decir, todas las subclases señaladas
comparten el comportamiento de la superclase animal. Si esto es cierto, puede suponerse

46 Ekaitz Zárraga
5.2. SINTAXIS

que en cualquier caso en el que se espere un objeto de la clase animal es seguro usar una
subclase de ésta.

Visto desde otra perspec va, las subclases comparten comportamiento porque reu lizan las
funciones de la clase principal o las redefinen (herencia), pero podemos asegurar que todas
las subclases enen un conjunto de funciones con la misma estructura, independientemente
de lo que hagan, que aseguran que siempre van a ser compa bles. El nombre de esta cualidad
viene a que un perro puede tomar la forma de un animal.

Los otros pos de polimorfismo explotan el mismo comportamiento de diferentes maneras,


mientras que recuerdes que es posible programar de modo que el po de los datos que trates
sea indiferente o pueda variar es suficiente. Otro ejemplo de esto son los operadores mate-
má cos, que son capaces de funcionar en cualquier po de número (integer, float, complex,
etc.) de la misma manera, ya que todos son números, al fin y al cabo.

Entender estos conceptos a nivel intui vo, sin necesidad de entrar en los detalles específicos
de cada uno, es interesante para a la hora de diseñar programas y facilita de forma radical
la comprensión de muchas de las decisiones de diseño tomadas en python y en proyectos
relacionados aunque también, por supuesto, de otros lenguajes y herramientas.

5.2 Sintaxis
En el siguiente ejemplo se muestra la sintaxis básica a la hora de crear una clase y des-
pués instanciar dos nuevos objetos bobby y beltza. Los puntos (.) se u lizan para indicar a
quién pertenece el método o propiedad al que se hace referencia (iden dad). De este modo,
no ocurrirá lo mismo cuando el perro (Dog) bobby ladre (bark) que cuando lo haga el perro
beltza.

Los métodos describen la funcionalidad asociada a los perros en general, pero además, la
función bark los describe en par cular, haciendo que cada perro tome su nombre (name),
una propiedad, es decir: su estado.
class Dog:
type = "canine"
def __init__(self, name):
self.name = name
def bark(self):
print("Woof! My name is " + self.name)

bobby = Dog("Bobby") # Nuevo Dog llamado "Bobby"


beltza = Dog("Beltza") # Nuevo Dog llamado "Beltza"

bobby.name # Bobby
beltza.name # Beltza

bobby.type # canine
beltza.type # canine

bobby.bark() # "Woof! My name is Bobby"


beltza.bark() # "Woof! My name is Beltza"

47
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

5.2.1 Creación de objetos


El ejemplo muestra cómo crear nuevos objetos de la clase Dog. Las llamadas a Dog("Bobby")
y Dog("Beltza") crean las diferentes instancias de la clase.
Llamar a los nombres de clase como si de funciones se tratara crea una instancia de éstas. Los
argumentos de entrada de la llamada se envían como argumentos de la función __init__
declarada también en el propio ejemplo. En ende de momento que los argumentos posicio-
nales se introducen a par r de la segunda posición, dejando el argumento llamado self en
el ejemplo para un concepto que más adelante entenderás.
En el ejemplo, por tanto, se introduce el nombre (name) de cada Dog en su creación y la
función __init__ se encarga de asignárselo a la instancia recién creada mediante una me-
todología que se explica más adelante en este mismo capítulo. De momento no es necesario
comentar en más profundidad estos detalles, con lo que sabes es suficiente para entender
el funcionamiento general.
Queda por aclarar, sin embargo, qué es la función __init__ y por qué ene un nombre tan
extraño y qué es type = canine, que lo trataremos en próximos apartados de este capítulo.

5.2.2 Herencia
Antes de entrar en los detalles propuestos en el apartado anterior, que tratan conceptos
algo más avanzados, es interesante ver cómo definir clases mediante la herencia. Basta con
introducir una lista de clases de las que heredar en la definición de la clase, entre paréntesis,
como si de argumentos de entrada de una función se tratara, tal y como se muestra en la
clase Dog del siguiente ejemplo ejecutado en la REPL:
>>> class Animal:
... def live(self):
... print("I'm living")
...
>>> class Terrestrial:
... def move(self):
... print("I'm moving on the surface")
...
>>> class Dog(Animal, Terrestrial):
... def bark(self):
... print("woof!")
... def move(self):
... print("I'm walking on the surface")
...
>>> bobby = Dog()
>>> bobby.bark()
woof!
>>> bobby.live()
"I'm living"
>>> bobby.move()
"I'm walking on the surface"

El ejemplo muestra un claro uso de la herencia. La clase Dog hereda automá camente las
funciones asociadas a las superclases, pero es capaz de definir las propias e incluso redefinir
algunas. Independientemente de la redefinición del método move, cualquier perro (Dog) va

48 Ekaitz Zárraga
5.2. SINTAXIS

a ser capaz de moverse por la superficie, porque la superclase Terrestrial ya le da los


métodos necesarios para hacerlo. Lo que ocurre es que cualquier subclase de Terrestrial
ene la ocasión moverse (move) a su manera: en el caso del perro, caminando.

La herencia es interesante, pero tampoco debe caerse en la psicosis de añadir


demasiadas superclases. En ocasiones las superclases son necesarias, sobre to-
do cuando aprovechar el polimorfismo facilita el trabajo, pero usarlas de forma
agresiva genera código extremadamente complejo sin razón.

5.2.3 Métodos de objeto o funciones de clase


Los métodos reciben un parámetro de entrada llamado self que no se u liza a la hora de
llamarlos: al hacer bobby.bark() no se introduce ningún argumento de entrada a la función
bark.
Sin embargo, si no se añade el argumento de entrada a la definición del método bark y se
llama a bobby.bark() pasa lo siguiente:
>>> class Dog:
... def bark():
... pass
...
>>> bobby = Dog()
>>> bobby.bark()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bark() takes 0 positional arguments but 1 was given

Python dice que bark espera 0 argumentos posicionales pero se le ha entregado 1, que
nosotros no hemos me do en la llamada, claro está. Así que ha debido de ser él.
Efec vamente, python introduce un argumento de entrada en los métodos, el argumento de
entrada que por convención se suele llamar self. Este parámetro es el propio bobby en este
caso.

Por convención se le denomina self. Tú le puedes llamar como te apetezca pero,


si pretendes que los demás te en endan, mejor self.

Para explicar por qué ocurre esto es necesario diferenciar bien entre clase y objeto. Tal y co-
mo hemos hecho antes con las definiciones enciclopédicas (clase) y los conceptos del mundo
real que encajan en la definición (objeto). Los objetos también se conocen como instancias,
son piezas de información independiente que han sido creadas a par r de la definición que
la clase aportaba.
En python las clases enen la posibilidad de tener funciones, que definen el comportamiento
de la clase y no el de los objetos que se crean desde ellas. Ten en cuenta que las clases tam-
bién deben procesarse y ocupan un espacio en la memoria, igual que te ocurre a , puedes
conocer un concepto y su comportamiento y luego muchos casos que cumplan ese concep-
to y ambas cosas son independientes. Esta posibilidad aporta mucha flexibilidad y permite

49
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

definir clases complejas.

Ahora bien, para python las funciones de clase y los métodos (de los objetos, si no no se
llamarían métodos), se implementan de la misma manera. Para la clase ambas cosas son lo
mismo. Sin embargo, el comportamiento del operador punto (.), que dice a quién pertenece
la función o método, es diferente si el valor de la izquierda es una clase o un objeto, introdu-
ciendo en el segundo caso el propio objeto como primer parámetro de entrada, el self del
que hablamos, para que la clase sepa qué objeto ene que alterar. Este es el mecanismo de
la iden dad del que antes hablamos y no llegamos a definir en detalle. Cada objeto es único,
y a través del self se accede a él.

Es un truco interesante para no almacenar las funciones en cada uno de los objetos como
método. En lugar de eso, se man enen en la definición de la clase y cuando se llama al
método, se busca de qué clase es el objeto y se llama a la función de la clase con el objeto
como argumento de entrada.

Dicho de otra forma, bobby.bark() es equivalente a Dog.bark( bobby ).

Ilustrado en un ejemplo más agresivo, puedes comprobar que en función de a través de qué
elemento se acceda a la función bark python la interpreta de forma dis nta. A veces como
función (func on) y otras veces como método (method), en función de si se accede desde la
clase o desde el objeto:
>>> class Dog:
... def bark(self):
... pass
...
>>> type ( Dog.bark)
<class 'function'>
>>> type ( bobby.bark )
<class 'method'>

También te habrás fijado, y si no lo has hecho es momento de hacerlo, que los


nombres de las clases empiezan por mayúscula en los ejemplos (Dog) mientras
que los objetos comienzan en minúscula (bobby). Se trata de otra convención
ampliamente u lizada para saber diferenciar entre uno y otro de forma sencilla.
Es evidente cuál es la clase y el objeto con los nombres que hemos tratado en los
ejemplos, pero en otros casos puede no serlo y con este sencillo truco facilitas
la lectura de tu código. Hay muchas ocasiones en las que esta convención se
ignora, así que cuidado.
Prueba a hacer type(int) en la terminal.

5.2.4 Variables de clase


En el primer ejemplo del capítulo hemos postergado la explicación de type = canine y aho-
ra que ya manejas la mayor parte de la terminología y dominas la diferencia entre una clase
y una instancia de ésta (un objeto) es momento de recogerla. A con nuación se recupera la
sección del ejemplo para facilitar la consulta, jate en la línea 2.

50 Ekaitz Zárraga
5.2. SINTAXIS

1 class Dog:
2 type = "canine"
3 def __init__(self, name):
4 self.name = name
5 def bark(self):
6 print("Woof! My name is " + self.name)

type es lo que se conoce como una variable de clase (class variable).

En este documento se ha evitado de forma premeditada usar la palabra variable


para referirse a los valores y sus referencias con la intención de marcar la dife-
rencia entre ambos conceptos. En este apartado, sin embargo, a pesar de que se
siga tratando de una referencia, se usa el nombre class variable porque es como
se le llama en la documentación y así será más fácil que lo encuentres si en algún
momento necesitas buscar información al respecto. De esto ya hemos discu do
en el capítulo sobre datos, donde decimos que todo es una referencia.

Previamente hemos hablado de que los objetos pueden tener propiedades asociadas, y cada
objeto tendrá las suyas. Es decir, que cada instancia de la clase puede tener sus propias
propiedades independientes. El caso que tratamos en este momento es el contrario, el type
es un valor que comparten todas las instancias de Dog. Cualquier cambio en esos valores los
verán todos los objetos de la clase, así que hay que tener cuidado.
El acceso es idén co al que ocurriría en un valor asociado al objeto, como en el caso name
del ejemplo, pero en este caso observas que en su declaración en la clase no es necesario
indicar self. No es necesario decir cuál es la instancia concreta a la que se le asigna el valor:
se le asigna a todas.
Aparte de poder acceder a través de los objetos de la clase, es posible acceder directamente
desde la clase a través de su nombre, como a la hora de acceder a las funciones de clase:
Dog.type resultaría en "canine".

Si en algún caso python viera que un objeto ene propiedades y variables de


clase definidas con el mismo nombre, cosa que no debería ocurrir a menudo,
tendrán preferencia las propiedades.

5.2.5 Encapsulación explícita


Es posible que te encuentres en alguna ocasión con métodos o propiedades, campos en
general, cuyo nombre comience por _ o por __. Se trata de casos en los que esas propiedades
o métodos quieren ocultarse del exterior.
El uso de _ al inicio del nombre de un campo es una convención que avisa de que este campo
no debe accederse desde el exterior de la clase y su obje vo es usarlo desde el interior de
ésta.
Esta convención se llevó al extremo en algún momento y se decidió crear un caso en el que
esta convención inicial tuviera cierta funcionalidad añadida para el doble guión bajo (__) que

51
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

impidiera un acceso accidental a esos campos conocido como name mangling.

Campos privados: name mangling

El name mangling es un truco que hace python para asegurarse de que no se entra por acci-
dente a las secciones que empiezan por __. Añade _nombredeclase al inicio de los campos,
transformando su nombre final y dificultando el acceso por accidente.

Ese acceso accidental no sólo es para que quien programa no acceda, ya que, si se esfuerza
la suficiente, va a poder hacerlo de igual modo, sino para que el propio python no acceda
al campo que no corresponde. El hecho de añadir el nombre de la clase al campo crea una
brecha en la herencia, haciendo que los campos no se hereden de la forma esperada.

En una subclase en la que los campos de la clase madre han sido marcados con __, la he-
rencia hace que estos campos se hereden con el nombre cambiado que con ene el nombre
de la superclase. De este modo, es di cil para la subclase pisar estos campos ya que ten-
dría que definirlos manualmente con el nombre cambiado. Crear nuevos campos con __ no
funcionaría, ya que, al haber cambiado de clase, el nombre generado será dis nto.

Este mecanismo es un truco para crear campos privados, concepto bastante común en otros
lenguajes como Java o C++, que en python es inexistente.

El concepto de los campos privados es interesante en la programación orientada a objetos.


Pensando en la encapsulación, es lógico que a veces las clases definan métodos o propiedades
que sólo los objetos creados a par r de ellas conozcan y que los objetos creados de clases
heredadas no. Este es el método que python ene para aportar esta funcionalidad.

Es interesante añadir, por otro lado, que python es un lenguaje de programación muy diná-
mico por lo que la propia definición de las clases, y muchas cosas más, puede alterarse una
vez creadas. Esto significa que el hecho de ocultar campos no es más que un acuerdo tácito
entre quienes programan porque, si quisieran, podrían definir todo de nuevo. Trucos como
este sirven para que seamos conscientes de que estamos haciendo cosas que se supone que
no deberíamos hacer. Cuando programes en python, tómate esto como pistas que te indican
cómo se supone que deberías estar usando las clases.

5.2.6 Acceso a la superclase


A pesar de la herencia, no siempre se desea eliminar por completo la funcionalidad de un
método o pisar una propiedad. A veces es interesante simplemente añadir funcionalidad
sobre un método o recordar algún valor definido en la superclase.

Python soporta la posibilidad de llamar a la superclase mediante la función super, que per-
mite el acceso a cualquier campo definido en la superclase.
class Clase( SuperClase ):
def metodo(self, arg):
super().metodo(arg) # Llama a la definición de
# `metodo` de `SuperClase`

52 Ekaitz Zárraga
5.3. DUCK TYPING

super busca la clase previa por preferencia, si usas herencias múl ples y pisas
los campos puede complicarse.

5.3 Duck Typing


Una de las razones principales para usar programación orientada a objetos es que, si se eligen
los métodos con precisión, pueden crearse estructuras de datos que se comporten de similar
forma pero que tengan cualidades diferentes. Independientemente de cómo estén definidas
sus clases, si dos objetos disponen de los mismos métodos podrán ser sus tuidos el uno por
el otro en el programa y seguirá funcionando aunque su funcionalidad cambie.
Dicho de otra forma, dos objetos (o dos cosas, en general) podrán ser intercambiados si
disponen de la misma interfaz. Interfaz, de inter: entre; y faz: cara, viene a significar algo
así como «superficie de contacto» y es la palabra que se usa principalmente para definir la
frontera compar da entre dos componentes o, centrándonos en el caso que nos ocupa, su
conexión funcional.
Si recuerdas la herencia y la combinas con estos conceptos, puedes interpretar que además
de una metodología para reu lizar código es una forma de crear nuevas definiciones que
soporten la misma interfaz.
En otros lenguajes de programación, Java, por ejemplo, existe el concepto interfaz que serían
una especie de pequeñas clases que definen qué funciones debe cumplir una clase para ser
compa ble con la interfaz. A la hora de crear las clases se les puede indicar qué interfaces
implementan y el lenguaje se encarga de asegurarse de que quien programa ha hecho todo
como debe.
El dinamismo de python hace que esto sea mucho más flexible. Debido a que python no hace
casi comprobaciones antes de ejecutarse, necesita un método mucho más directo. Python
aplica lo que se conoce como duck typing (el pado del pato), es decir, si anda como un pato,
vuela como un pato y nada como un pato: es un pato.
Para que los objetos creados manualmente puedan comportarse como los que el propio
sistema aporta, python define unos nombres de métodos especiales (special method names).
Estos métodos enen infinidad de u lidades: que sea posible u lizarlos como iterable en un
for, que el sistema pueda cerrarlos de forma automá ca, buscar en ellos usando el operador
in, que puedan sumarse y restarse con los operadores de suma y resta, etc. Simplemente,
el sistema define qué funciones se deben cumplir en cada uno de esos casos y cuando se
encuentre con ellos intentará llamarlas automá camente. Si el elemento no dispone de esas
funciones lanzará una excepción como la que lanza cuando intentamos acceder a un método
que no existe (que es básicamente lo que estamos haciendo en este caso).
En general, python, con el fin de diferenciar claramente qué nombres se eligen manualmente
y cuales han sido seleccionados por el lenguaje, suele u lizar una convención para la nomen-
clatura: comienzan y terminan por: __
A con nuación se describen algunos de los nombres especiales más comunes. Algunos ya

53
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

han aparecido a lo largo de los ejemplos del documento, otros las verás por primera vez
ahora. Existen muchos más, y todos están extremadamente bien documentados. Si en algún
momento necesitas crear algunos nuevos, la documentación de python es una buena fuente
donde empezar.

Todos los nombres de métodos especiales agrupan un conjunto de caracterís cas que se
presentan con una palabra, en muchos casos inventada, terminada en -able. Python u liza
también este po de nombres, como el ya aparecido llamable, o callable en inglés, que se
refiere a cualquier cosa que puede ser llamada. Representar las capacidades de esta manera
sirve para expresar el interés de los nombres de métodos especiales. Si en algún momento
necesitas crear una clase que defina un objeto en el que se puede buscar necesitas que sea
un buscable, es decir, que soporte el nombre de método especial que define ese comporta-
miento.

5.3.1 Representable

Un objeto representable es aquél que puede representarse automá camente en modo texto.
Al ejecutar la función print o al exponer valores en la REPL (recuerda que la P significa print),
python trata de visualizarlos.

El método __repr__ se ejecuta justo antes de imprimirse el objeto, de forma automá ca.
La función requiere que se devuelva un elemento de po string, que será el que después se
visualice.

En el ejemplo a con nuación se comienza con la clase Dog vacía y se visualiza una de sus
instancias. Posteriormente, se reasigna la función __repr__ de Dog con una función que
devuelve un string. Al volver a mostrar a bobby el resultado cambia.

Como se ve en el ejemplo, es interesante tener una buena función de representación si lo


que se pretende es entender el contenido de los objetos.

Python ya aporta una forma estándar de representar los objetos, si la función


__repr__ no se define simplemente se usará la forma estándar.

>>> class Dog:


... pass
...
>>> bobby = Dog()
>>> bobby
<__main__.Dog object at 0x7fb7fba1b908>

>>> Dog.__repr__ = lambda self: "Dog called " + self.name


>>> bobby.name = "Bobby"
>>> bobby
Dog called Bobby
>>>

54 Ekaitz Zárraga
5.3. DUCK TYPING

5.3.2 Contable
En python se u liza la función len para comprobar la longitud de cualquier elemento con-
table. Por ejemplo:
>>> len( (1,2,3) )
3

Las objetos que soporten esta función podrán contarse para conocer su longitud mediante
la función len. Python llamará al método __len__ del objeto (que se espera que devuelva
un número entero) y ésta será su longitud. Siguiendo con el ejemplo anterior:
>>> Dog.__len__ = lambda self: 12 # Siempre devuelve 12
>>> len(bobby)
12

Este método permite crear elementos contables, en lugar de los picos diccionario, tupla y
lista. Como por ejemplo los ya existentes NamedTuple, OrderedDict y otros. Los métodos
buscable e iterable también son muy interesantes para esta labor.

5.3.3 Buscable
El método __contains__ debe devolver True o False y recibir un argumento de entrada.
Con esto el objeto será capaz de comprobarse con sentencias que hagan uso del operador
in (y not in). Las dos llamadas del ejemplo son equivalentes. La segunda es lo que python
realiza internamente al encontrarse el operador in o el operador not in.
>>> 1 in [1,2,3]
True
>>> [1,2,3].__contains__(1)
True

5.3.4 Hasheable
Los objetos hasheables, pueden conver rse a un valor numérico mediante una función hash.
Estas funciones habilitan la existencia de los diccionarios, siendo el mecanismo principal para
obtener una mejora en el rendimiento en el acceso y la inserción aunque también sirven para
infinidad de aplicaciones, como la comparación de objetos, agrupaciones, etc.

La función __hash__ será ejecutada siempre que se intente aplicar hash() a un objeto, cosa
que ocurre de forma automá ca en varios escenarios. Su único requerimiento es que retorne
un número, y que el hash de dos objetos idén cos sea el mismo.

Con el fin de que las comparaciones entre objetos puedan realizarse como es debido, es ne-
cesario implementar al menos la función __eq__, función que será llamada al realizar com-
paraciones como a == b. Ésta sirve para poder realizar comparaciones complejas (rich com-
parisons) en objetos que en principio no pueden compararse.

Los objetos básicos de python son hasheables.

55
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

5.3.5 Iterable
Estos métodos permiten crear objetos con los que es posible iterar en bucles for y otras
estructuras. Por ejemplo, los archivos de texto en python soportan este protocolo, por lo
que pueden leerse línea a línea en un bucle for.
Igual que en el caso de __len__, que servía para habilitar la llamada a la función len,
__iter__ y __next__ sirven, respec vamente, para habilitar las llamadas a iter y next.
La función iter sirve para conver r el elemento a iterable, que es una clase que soporte
el funcionamiento de la función next. Y next sirve para pasar al siguiente elemento de un
iterable. Ejemplificado:
>>> l = [1,2,3]
>>> next(l)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'list' object is not an iterator
>>> it = iter(l)
>>> it
<list_iterator object at 0x7ff745723908>
>>>
>>> next(it)
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

La función __next__ ene un comportamiento muy sencillo. Si hay un próximo elemento,


lo devuelve. Si no lo hay lanza la excepción StopIteration, para que la capa superior la
capture.
Fíjate que la lista por defecto no es un iterable y que se debe construir un elemento iterable
desde ella con iter para poder hacer next. Esto se debe a que la función iter está pensada
para restaurar la posición del cursor en el primer elemento y poder volver a iniciar la iteración.
Sorprendentemente, este es el procedimiento de cualquier for en python. El for es una es-
tructura creada sobre un while que construye iterables e itera sobre ellos automá camente.
Este bucle for:
for el in secuencia:
# hace algo con `el`

Realmente se implementa de la siguiente manera:


# Construye un iterable desde la secuencia
iter_obj = iter(secuencia)

# Bucle infinito que se rompe cuando `next` lanza una


# excepción de tipo `StopIteration`

56 Ekaitz Zárraga
5.3. DUCK TYPING

while True:
try:
el = next(iter_obj)
# hace algo con `el`
except StopIteration:
break

Así que, si necesitas una clase con capacidad para iterarse sobre ella, puedes crear un pe-
queño iterable que soporte el método __next__ y devolver una instancia nueva de éste en
el método __iter__.

5.3.6 Inicializable
El método __init__ es uno de los más usados e interesantes de esta lista, esa es la razón
por la que ha aparecido en más de una ocasión durante este capítulo.
El método __init__ es a quien se llama al crear nuevas instancias de una clase y sirve para
inicializar las propiedades del recién creado objeto.
Cuando se crean nuevos objetos, python construye su estructura en memoria, pidiéndole
al sistema opera vo el espacio necesario. Una vez la ene, envía esa estructura vacía a la
función __init__ como primer argumento para que sea ésta la encargada de rellenarla.
Como se ha visto en algún ejemplo previo, el método __init__ (es un método, porque el
objeto, aunque vacío, ya está creado) puede recibir argumentos de entrada adicionales, que
serán los que la llamada al nombre de la clase reciba, a la hora de crear los nuevos objetos.
Es muy habitual que el inicializador reciba argumentos de entrada, sobre todo argumentos
con nombre, para que quien cree las instancias tenga la opción de inicializar los campos que
le interesen.
Volviendo a un ejemplo previo:
class Dog:
type = "canine"
def __init__(self, name):
self.name = name
def bark(self):
print("Woof! My name is " + self.name)

bobby = Dog("Bobby") # Aquí se llama a __init__

El nombre del perro, "Bobby" será recibido por __init__ en el argumento name e insertado
al self mediante self.name = name. De este modo, esa instancia de Dog, bobby, tomará el
nombre Bobby.

En muchas ocasiones, el método __init__ inicializa a valores vacíos todas las


posibles propiedades del objeto con el fin de que quien lea el código de la clase
sea capaz de ver cuáles son los campos que se u lizan en un primer vistazo. Es
una buena prác ca listar todos los campos posibles en __init__, a pesar de que
no se necesite inicializarlos aún, con el fin de facilitar la lectura.

57
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

Quien tenga experiencia con C++ puede equivocarse pensando que __init__ es
un constructor. Tal y como se ha explicado anteriormente, al método __init__
ya llega un objeto construido. El obje vo de __init__ es inicializar. En python
el constructor, que se encarga de crear las instancias de la clase, es la función
__new__.

Si creas una clase a par r de la herencia y sobreescribes su método __init__


es posible que tengas que llamar al método __init__ de la superclase para ini-
cializar los campos asociados a la superclase. Recuerda que puedes acceder a la
superclase usando super.

Los pos básicos de python están definidos en clases también, pero su nombre puede usarse
para hacer conversiones.
>>> int("1")
1

Para entender el funcionamiento de esa llamada, no hay más que recordar el que el aplicar
el nombre de la clase como una llamada a función sirve para crear un objeto del po indi-
cado, enviando los argumentos a su inicializador. Es decir, simplemente soportan el método
__init__ y construyen un nuevo objeto del po indicado a par r de lo que se les envía como
argumento.

5.3.7 Abrible y cerrable


Los objetos abribles y cerrables puedan ser abiertos y cerrados de forma segura y con una
sintaxis eficiente. Aunque no se van a detallar en profundidad, el obje vo de este punto es
mostrar la sentencia with que se habilita gracias a estos métodos y mostrar cómo facilitan
la apertura y cierre.
El PEP 3431 muestra en detalle la implementación de la sentencia with. Simplificándolo y
resumiéndolo, with sirve para abrir elementos y cerrarlos de forma automá ca.

Los PEP (Python Enhancement Proposals) son propuestas de mejora para el len-
guaje. Puedes consultar todos en la web de python. Son una fuente interesante
de información y conocimiento del lenguaje y de programación en general.
https://www.python.org/dev/peps/

Pensando en, por ejemplo, la lectura de un archivo, se requieren varias etapas para tratar
con él, por ejemplo:
f = open("file.txt") # apertura del fichero
f.read() # lectura
f.close() # cierre

1
Puedes leer el contenido completo del PEP en:
https://www.python.org/dev/peps/pep-0343/

58 Ekaitz Zárraga
5.3. DUCK TYPING

Este método es un poco arcaico y peligroso. Si durante la lectura del fichero ocurriera alguna
excepción el fichero no se cerraría, ya que la excepción bloquearía la ejecución del programa.
Para evitar estos problemas, lo lógico sería hacer una estructura try-except y añadir el cierre
del fichero en un finally.

La sentencia with se encarga básicamente de hacer eso y facilita la escritura de todo el


proceso quedándose así:
with f as open("file.txt"): # apertura
f.read() # en este cuerpo `f` está abierto

# Al terminar el cuerpo, de forma normal o forzada,


# `f` se cierra.

Ahora bien, para que el fichero pueda ser abierto y cerrado automá camente, deberá tener
implementados los métodos __enter__ y __exit__. En el PEP 343 se muestra la equivalen-
cia entre la sentencia with y el uso de __enter__, __close__ y el try-except.

5.3.8 Llamable
Queda pendiente desde el capítulo sobre funciones responder a qué es un callable o llamable.
Una vez llegados a este punto, ene una respuesta fácil: un llamable es un objeto que soporta
el método __call__.

Aunque pueda parecer sorprendente, las funciones en python también se llaman de este
modo, así que realmente son objetos que se llaman porque soportan este método. Es lógico,
porque las funciones, recuerda el capítulo previo, pueden guardar valores, como el contexto
en el que se crean (la closure). Las funciones son meros llamables y como tales se comportan.
>>> class Dog:
... def __call__(self):
... print("Dog called")
...
>>> dog = Dog()
>>> dog()
Dog called

Ten en cuenta que el método __call__ puede recibir cualquier can dad de argumentos
como ya hemos visto en apartados anteriores, pero el primero será el propio objeto que está
siendo llamado, el self que ya conocemos.

Resumiendo, el método __call__ describe cómo se comporta el objeto cuando se le aplican


los paréntesis.

5.3.9 Subscriptable
Tal y como el método anterior describía cómo se aplican los paréntesis a un objeto, los méto-
dos que se muestran en este apartado describen el comportamiento del objeto cuando se le
aplican los corchetes. Recordando el capítulo sobre datos, los corchetes sirven para acceder
a valores de las listas, tuplas y diccionarios.

59
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

Cuando python encuentra que se está tratando de acceder a un campo de un objeto me-
diante los corchetes llama automá camente al método __getitem__ y cuando se intenta
asociar un campo a un valor llama al método __setitem__ del objeto. Al pedir la eliminación
de un campo del objeto con la sentencia del, se llama al método __delitem__.
Aunque en otros conjuntos de métodos aquí descritos hemos inventado un nombre para este
documento, Python denomina a este comportamiento subscriptable así que cuando intentes
acceder usando corchetes a un objeto que no soporta esta funcionalidad, el error que saltará
u lizará la misma nomenclatura que nosotros.
El siguiente ejemplo muestra el funcionamiento en una clase que en lugar de usar los méto-
dos, imprime en pantalla. Lo lógico y funcional sería u lizar estos dos métodos para facilitar
el acceso a campos de estas clases o para crear clases que pudiesen sus tuir a listas, tuplas o
diccionarios de forma sencilla, pero puede hacerse cualquier porque son métodos normales.
>>> class Dog:
... def __getitem__(self, k):
... print(k)
... def __setitem__(self, k, v):
... print(k, v)
...
>>> bobby = Dog()
>>> bobby["field"]
field
>>> bobby["field"] = 10
field 10

Fíjate en que reciben diferente can dad de argumentos de entrada cada uno de los métodos.
El método __setitem__ necesita indicar no sólo qué item desea alterarse, sino su también
su valor.

Slice nota on

Se trata de una forma avanzada de seleccionar las posiciones de un objeto, el nombre viene
de slice, rebanada, y significa que puede coger secciones del objeto en lugar de valores úni-
cos. Piénsalo como en una barra de pan cortada en rebanadas de la que quieres seleccionar
qué rebanadas te interesan en bloque.
No todos los objetos soportan slicing, pero los que lo hacen permiten acceder a grupos de va-
lores en el orden en el que están indicando el inicio del grupo (inclusive), el final (no inclusive)
y el salto de un elemento al siguiente.
Además, los valores del slice pueden ser nega vos. Añadir un número nega vo al salto im-
plica que el salto se hace hacia atrás. Añadirlo en cualquier de los otros dos valores, inicio o
final de grupo, implica que se cuenta el elemento desde el final de la colección en dirección
opuesta a la normal.
La sintaxis de los slices es la siguiente: [inicio:fin:salto]. Cada uno de los valores es
opcional y si no se añaden se comportan de la siguiente manera:
• Inicio: primer elemento
• Fin: úl mo elemento inclusive

60 Ekaitz Zárraga
5.3. DUCK TYPING

• Salto: un único elemento en orden de cabeza a cola

El índice para representar el úl mo elemento es -1, pero si se quiere indicar


como final, usar -1 descartará el úl mo elemento porque el final no es inclusivo.
Para que sea inclusivo es necesario dejar el campo fin vacío.

Dada una lista de los números naturales del 1 al 99, ambos incluidos, de nombre l se mues-
tran unos casos de slicing.
>>> l[-5:]
[95, 96, 97, 98, 99]
>>> l[6:80:5]
[6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61, 66, 71, 76]
>>> l[60:0:-5]
[60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5]

La sintaxis de los slices mostrada sólo ene sen do a la hora de acceder a los campos de
un objeto, si se trata de escribir suelta lanza un error de sintaxis. Para crear slices de forma
separada se construyen mediante la clase slice de la siguiente manera: slice(inicio,
fin, salto).
En los métodos que permiten a un objeto ser subscriptable (__getitem__, __setitem__ y
__delitem__) a la hora de elegir un slice se recibe una instancia del po slice en lugar de una
selección única como en el ejemplo previo:
>>> class Dog:
... def __getitem__(self, item):
... print(item)
...
>>> bobby = Dog()
>>> bobby[1:100]
slice(1, 100, None)
>>> bobby[1:100:9]
slice(1, 100, 9)
>>> bobby[1:100:-9]
slice(1, 100, -9)

Por complicarlo todavía más, los campos del slice creado desde la clase slice pueden ser
del po que se quiera. El formato de los : es únicamente sintac c sugar para crear slices de
po integer o string. Aunque después es responsabilidad del quien implemente soportar el
po de slice definido, es posible crear slices de lo que sea, incluso anidarlos.
Como ejemplo de un caso que u liza slices no integer, los pos de datos como los que te
puedes encontrar en la librería pandas soportan slicing basado en claves, como si de un
diccionario se tratara.

5.3.10 Ejemplo de uso


Para ejemplificar varios de estos métodos especiales, tomamos como ejemplo una pieza de
código fuente que quien escribe este documento ha usado en alguna ocasión en su trabajo
como desarrollador.

61
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

Se trata de un iterable que es capaz de iterar en un sistema de ficheros estructurado en car-


petas año-mes-día con la estructura AAAA/MM/DD. Este código se creó para analizar datos que
se almacenaban de forma diaria en carpetas con esta estructura. Diariamente se insertaban
fichero a fichero por un proceso previo y después se realizaban análisis semanales y men-
suales de los datos. Esta clase permi a buscar por las carpetas de forma sencilla y obtener
rápidamente un conjunto de carpetas que procesar.
El ejemplo hace uso del módulo datetime, un módulo de la librería estándar que sirve para
procesar fechas y horas. Por ahora, puedes ver la forma de importarlo como una receta y
en el siguiente capítulo la entenderás a fondo. El funcionamiento del módulo es sencillo y
puedes usar la ayuda para comprobar las funciones que no conozcas.
Te animo a que analices el comportamiento del ejemplo, viendo en detalle cómo se comporta.
Como referencia, fuera de la estructura de la clase, en las úl mas líneas, enes disponible
un bucle que puedes probar a ejecutar para ver su comportamiento.
1 from datetime import timedelta
2 from datetime import date
3
4 class dateFileSystemIterator:
5
6 """
7 Iterate over YYYY/MM/DD filesystems or similar.
8 """
9 def __init__( self, start = date.today(), end = date.today(),
10 days_step = 1, separator = '/'):
11 self.start = start
12 self.current = start
13 self.end = end
14 self.separator = separator
15 self.step = timedelta( days = days_step )
16
17 def __iter__( self ):
18 self.current = self.start
19 return self
20
21 def __next__( self ):
22 if self.current >= self.end:
23 raise StopIteration
24 else:
25 self.current += self.step
26 datestring = self.current - self.step
27 datestring = datestring.strftime( "%Y" \
28 + self.separator \
29 + "%m"+self.separator \
30 +"%d")
31 return datestring
32
33 def __repr__( self ):
34 out = self.current - self.step
35 tostring = lambda x: x.strftime("%Y" \
36 + self.separator \
37 + "%m" \
38 + self.separator + "%d")
39 return "<dateFileSystemIterator: <Current: " \

62 Ekaitz Zárraga
5.4. LO QUE HAS APRENDIDO

40 + tostring(self.current) + ">" \
41 + ",<Start: " + tostring(self.start) + ">" \
42 + ",<End: " + tostring(self.end) + ">" \
43 + ",<Step: " + str(self.step) + ">"
44
45
46 it = dateFileSystemIterator(start = date.today() - timedelta(days=30))
47 print(it)
48 for i in it:
49 print(i)

Ejercicio libre: generadores

La parte de la iteración del ejemplo previo puede realizarse forma más breve mediante el
uso de la sentencia yield. Aunque no la trataremos, yield habilita muchos conceptos in-
teresantes, entre ellos los generadores.
A con nuación enes un ejemplo de cómo resolver el problema anterior mediante el uso
de esta sentencia. Te propongo como ejercicio que inves gues cómo funciona buscando
información sobre los generadores (generator) y la propia sentencia yield.
from datetime import datetime, timedelta

def iterate_dates( date_start, date_end=datetime.today(),


separator='/', step=timedelta(days=1)):
date = date_start
while date < date_end:
yield date.strftime('%Y'+separator+'%m'+separator+'%d')
date += step

yield ene mucha relación con las corru nas (corou ne) que, aunque no se tratarán en este
documento, son un concepto muy interesante que te animo a inves gar. Si lo haces, verás
que los generadores son un caso simple de una corru na.

5.4 Lo que has aprendido


Este capítulo también ha sido intenso como el anterior, pero te prometo que no volverá a
pasar. El interés principal de este capítulo es el de hacerte conocer la programación orientada
a objetos y enseñarte que en python lo inunda todo. Todo son objetos.
Para entenderlo has comenzado aprendiendo lo que es la programación orientada a obje-
tos, concretamente la orientada a clases, donde has visto por primera vez los conceptos de
iden dad propia, comportamiento y estado.
Desde ahí has saltado al fundamento teórico de la programación orientada a objetos y has
visitado la encapsulación, la herencia y el polimorfismo para luego, una vez comprendidos,
comenzar a definir clases en python.
Esto te ha llevado a necesitar conocer qué es el argumento que suele llamarse self, una
excusa perfecta para definir qué son las variables y funciones de clase y en qué se diferencian
de las propiedades y métodos.

63
CAPÍTULO 5. ORIENTACIÓN A OBJETOS

Como la encapsulación no se había tratado en detalle aún, lo próximo que has hecho ha sido
zambullirte en los campos privados viendo cómo python los crea mediante un truco llamado
name mangling y su impacto en la herencia.
Aunque en este punto conocías el comportamiento general de la herencia hacia abajo, ne-
cesitabas conocerlo hacia arriba. Por eso, ha tocado visitar la función super en este punto,
función que te permite acceder a la superclase de la clase en la que te encuentras. En lu-
gar de contártela en detalle, se te ha dado una pincelada sobre ella para que tú inves gues
cuando lo veas necesario, pero que sepas por dónde empezar.
Para describir más en detalle lo calado que está python de programación orientada a ob-
jetos necesitabas un ejemplo mucho más agresivo: los métodos con nombres especiales. A
través de ellos has visto cómo python recoge las funcionalidades estándar y te permite crear
objetos que las cumplan. Además, te ha servido para ver que todo en python es un objeto
(hasta las clases lo son2 ) y para ver formas elegantes de resolver problemas comunes, como
los iteradores, with y otros.
También, te recuerdo que, aunque sea de forma colateral y sin prestarle demasiada atención,
se te ha sugerido que cuando programamos no lo hacemos únicamente para nosotros mis-
mos y que la facilidad de lectura del código y la preparación de éste para que otros lo usen
es primordial. Los próximos capítulos tratan en parte de ésto: de hacer uso del patrimonio
tecnológico de la humanidad, y de ser parte de él.

2
Puedes preguntárselo a python:
>>> class C: pass
...

>>> isinstance(C, object)


True

64 Ekaitz Zárraga
Programar en Python

6 Módulos y ejecución

Hasta ahora, has ejecutado el código en la REPL y de vez en cuando has usado F5 en IDLE
para ejecutar. Aunque te ha permi do salir del paso, necesitas saber más en detalle cómo
funciona la ejecución para empezar a hacer tus programas. Además, es absurdo que te pelees
contra todo, hay que saber qué batallas librar, así que necesitarás aprender a importar código
realizado por otras personas para poder centrarte en lo que más te interesa: resolver tu
problema.
Este capítulo trata ambas cosas, que están muy relacionadas, y sirve como trampolín para el
siguiente, la instalación de nuevos paquetes y la ges ón de dependencias, y los posteriores
sobre librerías interesantes que te facilitarán el desarrollo de tus proyectos.
Este capítulo ya te capacita casi al cien por cien para la programación aunque aún no hemos
trabajado su u lidad, pero seguro que alguna idea se te habrá ocurrido, si no no estarías
leyendo este documento.

6.1 Terminología: módulos y paquetes


En python a cualquier fichero de código (extensión .py) se le denomina módulo (modu-
le). A cualquier directorio que contenga módulos de código python y un fichero llamado
__init__.py, que puede estar vacío, se le denomina paquete (package). El uso del fichero
__init__.py permite que python busque módulos dentro del directorio.
Piensa en los paquetes como grupos de módulos que incluso pueden anidarse con subpa-
quetes. En la documentación oficial verás en más de una ocasión que se trata a los paquetes
como si fueran módulos, y ene cierto sen do, porque, normalmente, existe un módulo
principal que permite el acceso a un subpaquete. Así que, principalmente estás trabajando
con un único módulo de un paquete, que con ene subpaquetes a los que este módulo hace
referencia. Aunque pueda sonar algo enrevesado, no te preocupes por ahora: los módulos
son ficheros únicos y los paquetes conjuntos de ellos.

6.2 Ejecución
Ya conoces un par de maneras de ejecutar tus módulos de python. Usar la REPL, introdu-
ciéndole el código que quieres ejecutar, llamar a la función «ejecutar módulo» de IDLE con
la tecla F5 e incluso llamar a la shell de sistema con un comando similar a este:
python mi_archivo.py

Normalmente, los ficheros de python se ejecutan de este úl mo modo en producción, mien-


tras que los dos anteriores son más usados a la hora de desarrollar. Realmente son métodos

65
CAPÍTULO 6. MÓDULOS Y EJECUCIÓN

similares, en todos ellos el intérprete accede al fichero o contenido que recibe y ejecuta las
líneas una a una.
Existe también una opción adicional muy usada que sirve para ejecutar módulos que el sis-
tema sea capaz de encontrar por sí mismo, en lugar de indicarle la ruta, se le puede indicar
simplemente el nombre del módulo usando la opción -m:
python -m nombre_de_modulo

6.3 Importación y namespaces


Anteriormente hemos pasado sobre la sintaxis de la importación de forma muy superficial
pero tampoco es mucho más compleja a lo que ha aparecido. La sentencia import permite
importar diferentes módulos a nuestro programa como en el siguiente ejemplo:
>>> import datetime
>>> datetime
<module 'datetime' from '/usr/lib/python3.6/datetime.py'>

Han pasado, sin embargo, muchas cosas interesantes en el ejemplo. En primer lugar, python
ha buscado y encontrado el módulo datetime en el sistema y, en segundo lugar, ha creado
un objeto módulo llamado datetime que atesora todas las definiciones globales del módulo
datetime.
Empezando por el final, python usa lo que se conoce como namespace de forma muy exten-
dida. Los namespaces, de nombre (name) y espacio (space), son una herramienta para separar
contextos ampliamente usada. Los objetos, en realidad, son una caso de namespace ya que
cuando se llama a un método se le dice cuál es el contexto de la llamada, es decir: al método
de qué objeto se llama.
Para los módulos el proceso es el mismo. La sentencia import trae un módulo al programa
pero lo esconde tras su namespace, de este modo, para acceder a algo definido en el recién
importado módulo es necesario indicarle el nombre de éste de la siguiente manera:
>>> import datetime
>>> datetime.date.today()
datetime.date(2019, 12, 3)

En el ejemplo se accede a la clase date dentro del módulo datetime, y se lanza su función
today, que indica el día de hoy. Como puedes apreciar, el operador . se u liza del mismo
modo que en las clases y objetos, y en realidad es di cil saber cuándo se está accediendo a
una clase y cuándo a un módulo, aunque tampoco es necesario saberlo.
Para no tener que escribir el nombre del módulo completo, existe otra versión de la sentencia
import que ene un comportamiento muy similar:
>>> import datetime as dt
>>> dt.date.today()
datetime.date(2019, 12, 3)

En este ejemplo, se ha cambiado el nombre del módulo a uno más corto decidido por el
programador, dt. El funcionamiento es el mismo, simplemente se ha cambiado el nombre

66 Ekaitz Zárraga
6.3. IMPORTACIÓN Y NAMESPACES

para simplificar. Este cambio de nombre también es ú l cuando se va a importar un módulo


cuyo nombre es igual que alguna otra definición. Cambiando el nombre se evitan colisiones.
Existen versiones además, que permiten importar únicamente las funciones y clases selec-
cionadas, pero que las añaden al namespace actual, para evitar tener que usar el prefijo.
>>> from datetime import date
>>> date.today()
datetime.date(2019, 12, 3)

En este úl mo ejemplo, se trae la clase date al contexto actual. También existe la posibilidad
de importar más de una definición del módulo, usando la coma para separarlas, o todo lo
que el módulo exponga mediante el símbolo *. Es peligroso, sin embargo, traer definiciones
al namespace actual de forma descuidada, sobre todo con la úl ma opción, porque es posible
que se repitan nombres por accidente y se pisen definiciones. Los namespaces se inventan
con el fin de separar las definiciones y evitar colisiones de este po.

6.3.1 Búsqueda
Una vez descrito cómo se interactúa con los módulos importados, es necesario describir
dónde se buscan estos módulos.
Los módulos se buscan en los siguientes lugares:
1. El directorio del fichero ejecutado o el directorio de trabajo de la REPL
2. Los directorios indicados en el entorno
3. La configuración por defecto (depende de la instalación)
Esto significa que si guardas un archivo de python en IDLE y guardas otro más en el mismo
directorio con el nombre modulo.py podrás importarlo usando import modulo en el pri-
mero, ya que comparten directorio. Lo mismo ocurre con los paquetes, crear un directorio
con nombre paquete y añadirle un fichero vacío llamado init.py te permi rá hacer import
paquete. Si añadieras más módulos dentro del paquete, podrías importar cada uno de ellos
mediante paquete.modulo.

Los nombres de los ficheros deben coincidir con el el nombre del módulo más
la extensión .py. En el caso de los directorios, saltar a un subdirectorio implica
acceder a un paquete, por lo que se añadirá un punto (.).

El primer punto sirve para facilitar que organices tu proyecto de python en varios módulos,
separando así la funcionalidad en diferentes archivos.
Los úl mos dos puntos son los que permiten a python encontrar su librería estándar y los
módulos de sistema. El tercero depende de la instalación y del formato de ésta: si python
está instalado como portable no será igual que si se instala en el sistema del modo habitual.
El segundo punto también puede variar de un sistema a otro, pero en resumen se trata de
varias variables de entorno de sistema que le indican a python dónde buscar (normalmente
toman el nombre PYTHONPATH, pero no es siempre así). El segundo punto puede alterarse
de modo que en función de lo que se le indique, se puede pedir a python que busque los
módulos en un lugar u otro.

67
CAPÍTULO 6. MÓDULOS Y EJECUCIÓN

Estos lugares de búsqueda se pueden mostrar de la siguiente manera:


>>> import sys
>>> print(sys.path)
[ '',
'/usr/lib/python36.zip',
'/usr/lib/python3.6',
'/usr/lib/python3.6/lib-dynload',
'/usr/local/lib/python3.6/dist-packages',
'/usr/lib/python3/dist-packages']

En función del sistema en el que te encuentres y la configuración que tengas, python mos-
trará diferente resultado.
Rescatando un ejemplo previo:
>>> import datetime
>>> datetime
<module 'datetime' from '/usr/lib/python3.6/datetime.py'>

Ahora en endes por qué es capaz de encontrar datetime en /usr/lib/python3.6, carpeta


listada en sys.path, bajo el nombre datetime.py.

6.4 Ejecución e importación


A la hora de importar un módulo, python procesa el contenido de éste ya que necesita definir
las funciones, clases, valores, etc. a exportar. Para poder hacerlo, python necesita ejecutar
el módulo.
Python define una forma de separar la funcionalidad del código de sus definiciones con el
fin de poder crear código cuyas definiciones sean reu lizables mediante la importación en
otro módulo, sin que tenga ninguna funcionalidad cuando esto ocurra, pero habilitando que
tenga funcionalidades cuando sea llamado directamente.
Un ejemplo de uso de esto puede ser un módulo de acceso a ficheros, por ejemplo, que vi-
sualice el contenido del fichero cuando se llame de forma directa pero que cuando se importe
únicamente aporte las funciones de lectura y escritura sin leer y mostrar ningún fichero.
Para que los módulos puedan tener esta doble vida, python define la variable __name__ que
representa en qué nivel del scope se está ejecutando el módulo actual. La variable __name__
toma el valor del nombre del módulo cuando éste está siendo importado y el valor __main__
cuando ha sido llamado de forma directa o está siendo ejecutado en la REPL. __main__ es
el scope global de los programas, por lo que cuando algo se declara en él, implica que es el
programa principal.
Para poder diferenciar cuándo se ha ejecutado un módulo de forma directa y cuando se ha
importado se u liza lo que se conoce como __main__ guard:
if __name__ == "__main__":
# Este bloque sólo se ejecuta cuando el módulo es el principal

Aunque igual es un poco incómodo de entender de primeras, encontrarás esta estructura en


casi cualquier módulo de código python. Se u liza constantemente, incluso para los casos

68 Ekaitz Zárraga
6.5. LO QUE HAS APRENDIDO

en los que no se pretende que el código pueda importarse. Es una buena prác ca incluir el
guard para separar la ejecución de las definiciones, de este modo, quien quiera saber cuál es
la funcionalidad del módulo tendrá mucho más fácil la búsqueda.
Puedes leer más sobre este tema en la documentación de python1 .
Siguiendo este concepto, también existe un estándar de nomenclatura de ficheros. El nom-
bre __main__.py hace referencia al fichero que con ene el código principal del programa
y será el fichero que python buscará ejecutar siempre que se le pida ejecutar un paquete o
un directorio sin especificar qué módulo debe lanzar. Por ejemplo, ejecutar python .2 en la
shell de sistema es equivalente a ejecutar python __main__.py.

6.5 Lo que has aprendido


En este capítulo corto has aprendido lo necesario sobre importación de módulos y ejecución
de código. Conocer en detalle el patrón de búsqueda de módulos de python es primordial
para evitar problemas en el futuro y organizar los proyectos de forma elegante.
Además, el __main__ guard era una de las úl mas convenciones de uso común que queda-
ban por explicar y una vez vista ya eres capaz de leer proyectos de código fuente que te
encuentres por ahí sin demasiados problemas.
Los próximos capítulos, basándose en lo aprendido en éste, te mostrarán cómo instalar nue-
vas dependencias y cómo preparar tu propio código para que pueda ser instalado de forma
limpia y elegante.

1
https://docs.python.org/3/library/__main__.html
2
. significa directorio actual en cualquiera de los sistemas opera vos comunes.

69
CAPÍTULO 6. MÓDULOS Y EJECUCIÓN

70 Ekaitz Zárraga
Programar en Python

7 Instalación y dependencias

Ahora que sabes lidiar con módulos, necesitas aprender a instalarlos en tu propio sistema,
porque es bastante tedioso que tengas que copiar el código de todas tus dependencias en
la carpeta de tu proyecto.
En la introducción nos aseguramos de instalar con python la herramienta pip. Que sirve para
instalar paquetes nuevos en el sistema de forma sencilla.

7.1 Sobre PIP


pip es una herramienta extremadamente flexible, capaz de instalar módulos de python de
diferentes fuentes: repositorios de git, carpetas de sistema o, la más interesante quizás de
todas, el Python Package Index (PyPI)1 .
pip buscará la descripción del paquete en la fuente que se le indique y, de esta descripción,
obtendrá las dependencias necesarias y las indicaciones de cómo debe instalarlo. Una vez
procesadas las normas, procederá a instalar el paquete en el directorio de sistema con todas
las dependencias de éste para que funcione correctamente.
Una vez instalado el paquete en el directorio de sistema está listo para ser importado.

7.1.1 PyPI
El Python Package Index o PyPI es un repositorio que con ene so ware programado en py-
thon. En él se listan miles de librerías independientes para que cualquiera pueda descargarlas
e instalarlas. Más adelante veremos algunas de ellas y nos acostumbraremos a usar PyPI co-
mo recurso.
Ahora que sabes programar en python tú también puedes publicar tus proyectos ahí para
que otras personas los usen para crear los suyos.

7.1.2 Reglas de instalación


Para que pip pueda hacer su trabajo correctamente hay que indicarle cómo debe hacerlo, ya
que cada paquete es un mundo y ene necesidades dis ntas. El módulo setuptools permite
crear un conjunto de reglas comprensible por pip que facilita la distribución e instalación.
Normalmente este conjunto de reglas suele almacenarse en un fichero de nombre setup.py.
Como ejemplo de setup.py puedes ver el de la librería BeautifulSoup42 que se adjunta a
1
https://pypi.org/
2
https://www.crummy.com/software/BeautifulSoup/bs4/doc/

71
CAPÍTULO 7. INSTALACIÓN Y DEPENDENCIAS

con nuación con ligeras alteraciones para que encaje en la página:

1 from setuptools import (


2 setup,
3 find_packages,
4 )
5
6 with open("README.md", "r") as fh:
7 long_description = fh.read()
8
9 setup(
10 name="beautifulsoup4",
11 # NOTE: We can't import __version__ from bs4 because bs4/__init__.py
12 # is Python 2 code, and converting it to Python 3 means going through
13 # this code to run 2to3.
14 # So we have to specify it twice for the time being.
15 version = '4.8.1',
16 author="Leonard Richardson",
17 author_email='leonardr@segfault.org',
18 url="http://www.crummy.com/software/BeautifulSoup/bs4/",
19 download_url = "http://www.crummy.com/software/BeautifulSoup/bs4/download/",
20 description="Screen-scraping library",
21 install_requires=["soupsieve>=1.2"],
22 long_description=long_description,
23 long_description_content_type="text/markdown",
24 license="MIT",
25 packages=find_packages(exclude=['tests*']),
26 extras_require = {
27 'lxml' : [ 'lxml'],
28 'html5lib' : ['html5lib'],
29 },
30 use_2to3 = True,
31 classifiers=[
32 "Development Status :: 5 - Production/Stable",
33 "Intended Audience :: Developers",
34 "License :: OSI Approved :: MIT License",
35 "Programming Language :: Python",
36 "Programming Language :: Python :: 2.7",
37 'Programming Language :: Python :: 3',
38 "Topic :: Text Processing :: Markup :: HTML",
39 "Topic :: Text Processing :: Markup :: XML",
40 "Topic :: Text Processing :: Markup :: SGML",
41 "Topic :: Software Development :: Libraries :: Python Modules",
42 ],
43 )

En el ejemplo se aprecia a la perfección el po de información que es necesario aportarle a


setuptools. Dependiendo del proyecto, esta configuración puede ser más compleja o más
sencilla, y tendrás que indagar a través de la configuración de setuptools para ajustar la
herramienta a tu proyecto.

72 Ekaitz Zárraga
7.2. ENTORNOS VIRTUALES

7.2 Entornos virtuales


La herramienta pip es interesante para instalar herramientas en el sistema pero ene ciertas
carencias. La primera, que no es capaz de resolver las dependencias a la hora de desinstalar
paquetes, por lo que, si se instala un paquete que dependa de otro paquete, pip instalará
todas las dependencias necesarias, pero por miedo a romper paquetes, no las desinstalará si
se le pide desinstalar el paquete que las arrastró.

Por otro lado, si quieres trabajar en proyectos de desarrollo, probablemente tengas que ins-
talar sus dependencias. Si enes varios proyectos en marcha simultáneamente o si tu sistema
necesita de alguna herramienta escrita en python, es posible que tengas colisiones.

Imagina que dos de los proyectos, por ejemplo, usan versiones diferentes de una de sus
librerías. Si instalas sus dependencias usando pip, se mezclaran en tu sistema y no podrán
coexis r. Además, cuando termines los proyectos o abandones su desarrollo, te interesará
limpiar sus dependencias de tu sistema, cosa complicada si pip no ges ona la liberación de
paquetes de forma correcta.

Para evitar estos problemas y algún otro adicional, existen herramientas que alteran el com-
portamiento de pip, y del propio python, creando lo que se conoce como entornos virtuales
(virtual environments) que quedan aislados entre ellos y el sistema.

El funcionamiento de los entornos virtuales es muy sencillo. Cuando se ac van, crean un


nuevo contexto en el que alteran las variables de entorno que describen dónde debe bus-
carse el intérprete de python, dónde busca éste los módulos y dónde instala pip los paque-
tes. Cuando se desac van, se restaura el entorno por defecto. De este modo, cada entorno
virtual queda perfectamente aislado de otros o incluso de la instalación del sistema, per-
mi éndote hasta tener diferentes versiones de python en tu sistema y que no colisionen
entre ellas. Cuando has terminado con tu entorno virtual puedes borrarlo de forma segura
sabiendo que no va a afectar a tu sistema y que va a llevarse todas las dependencias con él.

Históricamente se han u lizado varias herramientas para esta labor, como virtualenv,
que como era poco amigable se simplificaba con virtualenv-wrapper, u otras. Hoy en día
pipenv es la herramienta recomendada.

pipenv es una combinación de virtualenv y pip creada para ges onar entornos virtuales y
dependencias de desarrollo. Puedes considerarla un gestor de paquetes de desarrollo como
npm en JavaScript, composer en PHP o cualquier otro que conozcas. Aporta la mayor parte
de funcionalidades habituales como ficheros de dependencias, lockfiles etc. mientras que
expone una interfaz de comandos sencilla y bien documentada.

7.2.1 Instalación
Para instalar pipenv, podemos usar pip, que instalamos en la introducción. En la shell de
sistema ejecutando:
pip install pipenv

73
CAPÍTULO 7. INSTALACIÓN Y DEPENDENCIAS

En función del sistema que u lices, puede que pip se llame pip3. El funciona-
miento es idén co.

7.2.2 Uso
Una vez instalado pipenv, puedes usarlo en el directorio que desees para crear un conjunto
de nuevas dependencias pidiéndole que instale un nuevo paquete lanzando la orden pipenv
install en la shell de sistema.

Para ejecutar módulos en el entorno virtual recién creado dispones de dos opciones: pipenv
shell que prepara una shell de sistema en el entorno o pipenv run que ejecuta el comando
que se le indique en el entorno.

Puedes seguir añadiendo dependencias al proyecto con pipenv install y eliminar las que
no te gusten con pipenv uninstall. Además, dispones de muchas opciones adicionales
que te animo que ojees ejecutando pipenv --help.

7.2.3 Usar IDLE desde un entorno virtual


Si u lizas entornos virtuales deberás preparar IDLE para verlos y que su REPL y su intérprete
encuentren los paquetes del entorno virtual.

Puedes lanzar IDLE desde el entorno virtual usando el siguiente truco en la shell de sistema:
pipenv run python -m idlelib.idle

Recordando el capítulo anterior y lo descrito en este, ese comando ejecuta python -m


idlelib.idle en el entorno virtual en el que te encuentres. El comando, por su parte le
pide a python que ejecute el módulo idle del paquete idlelib, que con ene el propio
programa IDLE.

Si trabajas con otros editores integrados de código tendrás que aprender a hacer que sus
intérpretes busquen en el entorno virtual actual, pero casi todos los editores actuales so-
portarán esta opción de una forma u otra.

7.3 Otras herramientas


La realidad es que las herramientas propuestas no son las únicas que existen para estas
tareas. Históricamente, python ha tenido otras herramientas con comportamientos similares
a pip, como easy_install y otras con parecidas a setuptools como distutils y otras que
asemejan a pipenv. Este capítulo trata únicamente las herramientas que se consideran las
recomendadas en el momento en el que se está escribiendo3 , aunque los conceptos descritos
son extrapolables, no sólo a otras herramientas sino también a otros lenguajes y entornos.
3
Para un listado más extenso, visitar:
https://packaging.python.org/guides/tool-recommendations/

74 Ekaitz Zárraga
7.4. LO QUE HAS APRENDIDO

7.4 Lo que has aprendido


En este capítulo has aprendido lo necesario sobre las herramientas que rodean a python y su
uso. De este modo, no te vas perder en un maremágnum de nombres extraños y comandos
cuando trabajes en proyectos que ya las usan.
Más que conver rte en un experto de cómo trabajar con estas herramientas, cosa que te
dará la prác ca, este episodio te ha dado las referencias que necesitas para ir creciendo por
tu cuenta en su uso, explicándote el interés de cada una de ellas.
Te encontrarás, probablemente, proyectos que u licen las herramientas de un modo peculiar,
usen otras herramientas o hasta proyectos que no las usen correctamente. Este es un mundo
complejo, y la historia de python no facilita la elección. Durante mucho empo la comunidad
creó nuevas herramientas para suplir las carencias de otras y el ecosistema se complicó. A
pesar de que hoy en día se recomiende el uso de unas herramientas sobre otras, no siempre
fue así y muchos proyectos se han quedado obsoletos en este sen do.
Para evitar atarte a las herramientas que aquí se muestran, se ha preferido darte una ligera
noción, haciéndote recordar que las herramientas no son realmente lo importante, sino el
conocimiento subyacente.
Con la herramienta principal que has conocido en este apartado, pipenv, podrás instalar los
paquetes que quieras de forma aislada y jugar con ellos todo lo que desees sin manchar
tu sistema por lo que podrás adentrarte en los próximos capítulos sin miedo a estropear tu
pulcra configuración inicial.

75
CAPÍTULO 7. INSTALACIÓN Y DEPENDENCIAS

76 Ekaitz Zárraga
Programar en Python

8 La librería estándar

La librería estándar se refiere a todas las u lidades que un lenguaje de programación trae
consigo. Los lenguajes de programación, a parte de aportar la propia funcionalidad del len-
guaje 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 mo vo 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, aun-
que esté diseñado con el obje vo de ser un lenguaje válido para cualquier uso, su área de
trabajo se centra en el entorno cien fico. Es por eso que incluye en su librería estándar
paquetes de álgebra lineal, estadís ca y otros.

Existen muchas diferentes aproximaciones a la librería estándar. Algunos lenguajes las man-
enen extremadamente reducidas con el fin de que la implementación del lenguaje sea más
liviana, con la contrapar da de forzar a quien los use a tener que u lizar herramientas ex-
ternas o a desarrollarlas.

Python es un lenguaje de propósito general con una extensísima librería estándar. Esto difi-
culta 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 pos de fichero, la con-
versió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.

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 empo a desarrollar funciona-
lidades 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 con nuació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ón1 .
1
https://docs.python.org/3/library/index.html#library-index

77
CAPÍTULO 8. LA LIBRERÍA ESTÁNDAR

8.1 Interfaz al sistema opera vo


Ya definimos previamente el concepto interfaz como superficie de contacto entre dos en -
dades. El módulo os facilita la interacción entre python y el sistema opera vo.
La comunicación con el sistema opera vo es primordial para cualquier lenguaje de progra-
mación de uso general, ya que es necesario tener la capacidad de hacer pe ciones directas al
sistema opera vo. Por ejemplo, cambiar de directorio actual para facilitar la inclusión rutas
rela vas en el programa, resolver rutas a directorios y un largo etc.
En capítulos previos hemos hablado de las diferencias entre sistemas opera vos. Esta libre-
rí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 mul plataforma, nos
encontraríamos con problemas. Sin embargo, el módulo os.path dispone de herramientas
para ges onar 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 plata-
formas.

8.2 Funciones relacionadas con el intérprete


Aunque el nombre de este módulo, sys, 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.

8.2.1 Salida forzada


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

8.2.2 Standard streams


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 ob ene 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 dis nto y porque ene ciertas peculia-
ridades dis ntas. 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 disposi vos sicos que
an guamente se u lizaban para comunicarse con una computadora. Hoy en día, estos tres

78 Ekaitz Zárraga
8.2. FUNCIONES RELACIONADAS CON EL INTÉRPRETE

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 opera vos 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 corres-
pondiente. Es decir, en realidad print, input, etc. son únicamente funciones que facilitan la
labor de escribir manualmente en estos streams:
>>> 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 sus tuirse por otros, permi-
é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:
>>> 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'

8.2.3 Argumentos de entrada


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:
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:
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:

79
CAPÍTULO 8. LA LIBRERÍA ESTÁNDAR

import sys
print(sys.argv)

Verás que se imprime una lista con el nombre del archivo en su primer elemento. Esta dife-
rencia sirve para que desde el propio programa se conozca también cómo se le llamó. El uso
más obvio de esto es poder mostrar una ayuda coherente con el nombre del programa.
Si ejecutas el módulo desde la shell de sistema añadiéndole argumentos de entrada:
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 permi r que los progra-
mas 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.

8.3 Procesamiento de argumentos de entrada


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é po de argumentos de entrada y opciones ene 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 u lizarla.

8.4 Expresiones regulares


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.

8.5 Matemá cas y estadís ca


El módulo math soporta gran can dad de operaciones matemá cas avanzadas para coma
flotante. En él puedes encontrar logaritmos, raíces, etc.
El módulo statistics soporta estadís ca básica como medias, medianas, desviación pica,
etc.
Ambos módulos enen mucho interés ya que python se usa extensivamente en el análisis
de datos. Aunque ene librerías de terceros mucho más adecuadas para esta labor, para
proyectos pequeños puede que sea suficiente con estos módulos.

80 Ekaitz Zárraga
8.6. PROTOCOLOS DE INTERNET

8.6 Protocolos de internet


urllib es un conjunto de paquetes que permiten seguir URLs o enlaces, principalmente
para HTTP y su versión segura HTTPs. Soporta cookies, redirecciones, auten cació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, 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.
>>> 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

81
CAPÍTULO 8. LA LIBRERÍA ESTÁNDAR

referred to as "HTTP/1.1".

'
>>>

8.7 Fechas y horas


datetime, que ya ha aparecido anteriormente, es un módulo para ges ón de fecha y hora.
datetime soporta gran can dad de operaciones y pos de dato. Entre ellos los timedeltas,
diferencias temporales que te permiten sumar y restar fechas con facilidad con los operado-
res habituales.
Con las facilidades de datetime, es poco probable que necesites importar una librería de
ges ón de fecha y hora independiente.

8.8 Procesamiento de ficheros


Python habilita gran can dad de procesadores de formatos de fichero, los dos que se lista
en este apartado enen 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 u lizan 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 conver r 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 resistente a las corrupciones.

8.9 Aritmé ca de coma flotante 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é ca decimal
aporta una solución rigurosa a este problema con el fin de facilitar el uso de python en en-
tornos que requieren precisión estricta que incluso puede requerir cumplir con norma vas,
como puede ser la banca.
La documentación del módulo muestra un par de ejemplos muy interesantes usando la clase
Decimal aportada por éste. Se adjuntan a con nuación para que los estudies y los diseccio-
nes en busca de las diferencias con el uso de los números de coma flotante normales:
>>> from decimal import *
>>> round(Decimal('0.70') * Decimal('1.05'), 2)

82 Ekaitz Zárraga
8.10. LO QUE HAS APRENDIDO

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

8.10 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 en-
tornos normales y algunos otros que enen 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 enes con él, únicamente con la librería estándar. En el próximo verás la can dad 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 pro-
blema que te despista de trabajar en la funcionalidad principal de tu aplicación, empieza por
la librería estándar.

83
CAPÍTULO 8. LA LIBRERÍA ESTÁNDAR

84 Ekaitz Zárraga
Programar en Python

9 Librerías ú les

Ahora que ya sabes cómo instalar librerías y que has visto que muchas funcionalidades están
contenidas en la librería estándar de python, es un buen momento para que visites varios
proyectos que aportan recursos muy interesantes a la hora de resolver problemas. Debido
al carácter de uso general de python, estas librerías aportan facilidades muy diversas. El
criterio para escogerlas parte de la experiencia personal del autor de este documento y añade
algunas librerías y herramientas que pueden ser interesantes debido a su amplio uso en la
industria.

9.1 Librerías cien ficas: ecosistema SciPy


SciPy es un ecosistema de librerías que ene como obje vo facilitar el cálculo en ingeniería,
matemá ca y ciencia en general.
Además de ser el nombre del ecosistema, comparte nombre con una de las librerías funda-
mentales de éste. El ecosistema está formado por varias librerías, entre ellas se encuentran:
• Numpy: un paquete de computación cien fica para python. Soporta matrices mul di-
mensionales, funciones sofis cadas y álgebra lineal, entre otras.
• SciPy: librería basada en Numpy que aporta ru nas numéricas eficientes para interpo-
lación, op mización, algebra lineal, estadís ca y otros.
• SymPy: una librería de matemá ca simbólica para python que complementa el resto
de librerías del ecosistema, ya que casi todas están orientadas al análisis numérico.
• Matplotlib: librería para representar gráficos y figuras cien ficas en 2D.
• Pandas: aporta unas estructuras de datos muy potentes basadas en tablas, su obje vo
es reforzar a python a la hora de tratar datos. El área de esta librería es el del análi-
sis de datos, pero puede combinarse con otras áreas de estudio como la econometría
(ver el proyecto statsmodels). Esta librería dispone de un ecosistema muy poderoso a
su alrededor debido al auge del análisis de datos en la industria del so ware. Muchas
librerías comparten la interfaz de Pandas por lo que tener nociones de su comporta-
miento abre muchas puertas en el sector del análisis de datos. Al igual que ocurre en
SciPy, las estructuras de datos de Pandas también se basan en Numpy.
• IPython: más que una librería, IPython es una herramienta. Se trata de una REPL inter-
ac va (su propio nombre viene de Interac ve Python) que añade diversas funcionalida-
des sobre la REPL de python habitual: histórico de comandos, sugerencias, comandos
mágicos (magic) que permiten alterar el comportamiento de la propia interfaz y un lar-
guísimo etcétera. IPython, además, sirve como núcleo de los cuadernos Jupyter que

85
CAPÍTULO 9. LIBRERÍAS ÚTILES

integran una shell de python con visualización de tablas y gráficos para generar docu-
mentos es lo literate programming.

9.2 Machine Learning: ScikitLearn


ScikitLearn es una librería de machine learning muy potente, implementa gran can dad de
algoritmos y ene una documentación extensa, sencilla y educa va.
Encaja a la perfección con el ecosistema SciPy, ya que se basa en NumPy, SciPy y Matplotlib.

9.3 Pe ciones web: Requests


Requests es una librería alterna va al módulo urllib aportado por la librería estándar de
python. Se describe a sí misma como «HTTP para seres humanos», sugiriendo que urllib
no es cómoda de usar.
Requests ges ona automá camente las URL-s de las pe ciones a par r de los datos que se
le entreguen, sigue redirecciones, almacena cookies, descomprime automá camente, deco-
difica las respuestas de forma automá ca, etc. En general es una ayuda cuando no se quiere
dedicar empo a controlar cada detalle de la conexión de modo manual.

9.4 Manipulación de HTML: Beau fulsoup


Beau fulsoup es una librería de procesado de HTML extremadamente potente. Simplifica
el acceso a campos de ficheros HTML con una sintaxis similar a los objetos de python, per-
mi endo acceder a la estructura anidada mediante el uso del punto en lugar de tener que
lidiar con consultas extrañas o expresiones regulares. Esta funcionalidad puede combinarse
con selectores CSS para un acceso mucho más cómodo.

9.5 Tratamiento de imagen: Pillow


Pillow es un fork de la librería PIL (Python Imaging Library) cuyo desarrollo fue abandonado.
En sus diversos submódulos, Pillow permite acceder a datos de imágenes, aplicarles trans-
formaciones y filtros, dibujar sobre ellas, cambiar su formato, etc.

9.6 Desarrollo web: Django, Flask


Existen infinidad de frameworks y herramientas de desarrollo web en python. Así como en
el caso del análisis de datos la industria ha convergido en una herramienta principal, Pandas,
en el caso del desarrollo web hay muchas opciones donde elegir.
Los dos frameworks web más usados son Django y Flask, siendo el segundo menos común
que el primero pero digno de mención en conjunción con el otro por varias razones.

86 Ekaitz Zárraga
9.7. PROTOCOLOS DE RED: TWISTED

La primera es la diferencia en la filoso a: así como Django decide con qué herramientas
se debe trabajar, Flask, que se define a sí mismo como microframework, deja en manos de
quien lo usa la elección de qué herramientas desea aplicarle. Cada una de las dos filoso as
ene ventajas y desventajas y es tu responsabilidad elegir las que más te convengan para tu
proyecto.
La segunda razón para mencionar Flask es que su código fuente es uno de los más intere-
santes a la hora de usar como referencia de cómo se debe programar en python. Define su
propia norma de es lo de programación, basada en la sugerencia de es lo de python1 y su
desarrollo es extremadamente elegante.
Django, por su parte, ha sido muy influyente y muchas de sus decisiones de diseño han sido
adoptadas por otros frameworks, tanto en python como en otros lenguajes. Lo que sugiere
que está extremadamente bien diseñado.
A pesar de las diferencias filosóficas, existen muchas similitudes entre ambos proyectos por
lo que aprender a usar uno de ellos facilita mucho el uso del otro y no es aprendizaje perdido.
No tengas miedo en lanzarte a uno.

9.7 Protocolos de red: Twisted


Twisted es motor de red asíncrono para python. Sobre él se han escrito diferentes librerías
para ges ón de protocolos de Internet como DNS (via Twisted-Names), IMAP y POP3 (via
Twisted-Mail), HTTP (via Twisted-Web), IRC y XMPP (via Twisted-Words), etc.
El diseño asíncrono del motor facilita sobremanera las comunicaciones eficientes. Programar
código asíncrono en python es rela vamente sencillo, pero ha preferido dejarse fuera de este
documento por diversas razones. Te animo a indagar en esta librería para valorar el interés
del código asíncrono.

9.8 Interfaces gráficas


A pesar de que python dispone de un módulo en su librería estándar para tratar interfaces
gráficas llamado TKinter, es recomendable u lizar librerías más avanzadas para esto. TKinter
es una interfaz a la herramienta Tk del lenguaje de programación Tcl y acompaña a python
desde hace años.
En programas simples TKinter es más que suficiente (IDLE, por ejemplo, está desarrollado
con TKinter) pero a medida que se necesita complejidad o capacidad del usuario para confi-
gurar detalles de su sistema suele quedarse pequeño.
Para programas complejos se recomienda usar otro po de librerías más avanzadas como
PyQt, PyGTK o wxPython, todas ellas interfaces a librerías escritas en C/C++ llamadas Qt,
GTK y wxWidgets respec vamente. Estas librerías aportan una visualización más elegante,
en algunos casos usando widgets na vos del sistema opera vo en el que funcionan.
1
https://www.python.org/dev/peps/pep-0008/

87
CAPÍTULO 9. LIBRERÍAS ÚTILES

Debido a la complejidad del ecosistema nace el proyecto PySimpleGUI, que pretende aunar
las diferentes herramientas en una sola, sirviendo de interfaz a cualquiera de las anteriores
y alguna otra. Además, el proyecto aporta gran can dad de ejemplos de uso. PySimpleGUI
aún está en desarrollo y el soporte de algunos de los motores no está terminado, pero es
una fuente interesante de información y recursos.

88 Ekaitz Zárraga
Programar en Python

10 Lo que has aprendido

Rescatando la definición de la introducción:

Python es un lenguaje de programación de alto nivel orientado al uso general.


Fue creado por Guido Van Rossum y publicado en 1991. La filoso a de python
hace hincapié en la limpieza y la legibilidad del código fuente con una sintaxis
que facilita expresar conceptos en menos líneas de código que en otros lengua-
jes.
Python es un lenguaje de pado dinámico y ges ón de memoria automá ca. So-
porta múl ples paradigmas de programación, incluyendo la programación orien-
tada a objetos, impera va, funcional y procedural e incluye una extensa librería
estándar.

Ahora sí que estás en condición de entenderla no sólo para python sino para cualquier otro
lenguaje que se te presente de este modo. Ahora enes la habilidad de poder comprender de
un vistazo qué te aporta el lenguaje que enes delante únicamente leyendo su descripción.
Desgranándola poco a poco, has conocido la sintaxis de python en bastante detalle y has vis-
to cómo hace uso de las sangrías para delimitar bloques de código, cosa que otros lenguajes
hacen con llaves ({}) u otros símbolos.
La facilidad de expresar conceptos complejos en pocas líneas de código puede verse en las
list comprehensions, la sentencia with y muchas otras estructuras del sistema. Python es un
lenguaje elegante y directo, similar al lenguaje natural.
El pado dinámico trata lo que estudiaste en el apartado sobre datos, donde se te cuenta
que las referencias pueden cambiar de po en cualquier momento ya que son los propios
valores los que son capaces de recordar qué po enen.
La ges ón de memoria automá ca también se presenta en el mismo apartado, contándo-
te que python hace uso de un garbage collector o recolector de basura para limpiar de la
memoria los datos que ya no usa.
Los diferentes paradigmas de programación no se han tratado de forma explícita en este
documento, más allá de la programación orientada a objetos, que inunda python por com-
pleto. Sin embargo, el apartado sobre funciones adelanta varios de los conceptos básicos del
paradigma de programación funcional: que las funciones sean ciudadanos de primera clase
(first-class ci zens), el uso de funciones anónimas (lambda) y las closures.
Los paradigmas procedural e impera vo son la base para los dos paradigmas de los que
hemos hablado. La programación impera va implica que se programa mediante órdenes (el
caso de python, recuerda) en lugar de declaraciones (como puede ser la programación lógica,

89
CAPÍTULO 10. LO QUE HAS APRENDIDO

donde se muestran un conjunto de normas que el programa debe cumplir). La programación


procedural es un paradigma cuyo fundamento es el uso de bloques de código y su scope,
creando funciones, estructuras de datos y variables aunque, a diferencia de la programación
funcional, en la programación procedural no es necesario que las funciones sean ciudadanos
de primera clase y pueden tener restricciones.
Estos dos úl mos paradigmas, en realidad, se soportan casi por accidente al habilitar los dos
anteriores.
En muchas ocasiones, te encontrarás escribiendo pequeñas herramientas y no necesitarás
mucho más que usar las estructuras básicas de python y varias funciones para alterarlas, por
lo que estarás pensando de forma procedural accidentalmente.
Los paradigmas no son más que patrones de diseño que nos permiten clasificar los lenguajes
y sus filoso as, pero son muy interesantes a la hora de diseñar nuestras aplicaciones.
Además de todo esto, has tenido ocasión de conocer de forma superficial la librería estándar
del lenguaje y un conjunto de librerías adicionales que te aportan los puntos de los que la
librería estándar carece. Ahora sabes instalar dependencias y usarlas en entornos virtuales
(virtual environments) para mantener limpia tu instalación.
A parte de lo mencionado en la definición del lenguaje, has aprendido a ejecutar, cargar y
distribuir módulos de python, algo primordial si pretendes crear paquetes o nuevas librerías
y usar las de terceros.
Con todo esto, enes una visión general pero bastante detallada a nivel técnico de lo que
python aporta y cómo. Lo que necesitas para compensarla es trabajar con él, acostumbrar-
te a su ecosistema y leer mucho código de buena calidad para acostumbrarte a seguir las
convenciones y recetas habituales.

10.1 El código pythónico


A lo largo del documento se tratan temas que puede que no te esperases encontrar al leer
sobre programación, ya que tu interés principal es resolver tus problemas de forma efec va
y construir aplicaciones. Hacer robots que te hagan la vida más fácil, en defini va.
Sin embargo, quien se dedica a la programación ene una vida muy ligada a la vida de quien
se dedica a la filoso a o al diseño y es por eso que esas dos disciplinas aparecen de vez en
cuando en cualquier conversación un poco seria sobre el trabajo con so ware.
Las tres disciplinas, en primer lugar, ocurren en la mente de las personas y no en sus manos.
Es por eso que los patrones mentales y los modos de pensamiento son parte fundamental de
ellas. Ninguno de ellos son trabajos para los que se pueda entrenar una memoria muscular.
Es necesario pensar. Y es necesario pensar de forma consciente y premeditada.
Ver cómo desarrollan otras personas su ac vidad es valioso para realizar tu tarea con ele-
gancia.
Otro detalle que has debido de observar, sobre todo porque acaba de aparecer, es la elegan-
cia. La elegancia es subje va y depende del gusto de quien la mira. Sin embargo, esto sólo

90 Ekaitz Zárraga
10.1. EL CÓDIGO PYTHÓNICO

es así hasta cierto punto. La realidad es que alguien puede considerar algo elegante y aun
así no gustarle. Python es un ejemplo de algo así. Guste o no guste, python es un lenguaje
de programación elegante, cuya elegancia forma parte primordial de la filoso a del lenguaje.
El autor de este documento, por ejemplo, no es un entusiasta de python, pero a lo largo de la
travesía de escribir este documento ha podido reencontrarse, una vez más, con su elegancia.
Cuando se habla de código pythónico (pythonic code), se habla de un código que sigue los
estándares de elegancia de python. Que es bonito, comprensible y claro. Un código que la
comunidad de desarrollo de python aprobaría.
Cuando programes en python, trata de programar código pythónico, pues es esa la verdadera
razón por la que se creó el lenguaje y es la forma en la que el lenguaje más fácil te lo va a
poner.

91
CAPÍTULO 10. LO QUE HAS APRENDIDO

92 Ekaitz Zárraga
Programar en Python

Anexo I: Herramientas

IDLE es una herramienta de desarrollo muy limitada, suficiente para seguir los ejemplos que
se recogen en este documento pero insuficiente para desarrollar aplicaciones avanzadas.

10.2 Desarrollo de código fuente


Existen gran can dad de entornos de desarrollo (IDE) avanzados y editores que pueden ser
recomendables, aunque es cues ón de gusto personal decantarse por uno de ellos o por
otro.
La diferencia entre un entorno de desarrollo integrado y un editor es la siguiente: los en-
tornos de desarrollo cumplen varias funciones adicionales, como, en el caso de IDLE, dar
acceso a una REPL de python y la posibilidad de analizar las variables en memoria. Los edi-
tores únicamente sirven para escribir el código, aunque en muchos casos la línea que separa
ambos conceptos es bastante borrosa: existen editores con funcionalidades avanzadas y
entornos integrados muy sencillos que parecen un simple editor. Resumiendo, los entornos
integrados de desarrollo, o IDE (Integrated Development Environment), enen editores entre
sus herramientas.

10.2.1 Entornos de desarrollo integrados


Quien escribe este documento no u liza entornos de desarrollo avanzados (una cues ón de
gusto personal), por lo que se le hace di cil recomendar alguno en par cular. Sin embargo,
el wiki de python recoge una larguísima lista de editores y entornos de desarrollo integrado
interesantes1 .
En el entorno del análisis de datos, la distribución Anaconda es muy usada. Anaconda es más
que un entorno de desarrollo integrado. Incluye un entorno de desarrollo llamado Spyder,
una shell propia, un gestor de paquetes y dependencias propio llamado Conda, posibilidad
de integración con el lenguaje de programación R y gran can dad de paquetes instalados
por defecto.
En otros entornos PyCharm es bastante común, aunque también son muy comunes los en-
tornos de desarrollo integrados pensados para otros lenguajes que han comenzado a sopor-
tar python posteriormente como KDevelop, NetBeans y otros.
Te recomiendo que, si usas un entorno de desarrollo integrado en otros lenguajes, inves -
gues si soporta python. De este modo no tendrás que aprender una nueva herramienta. Al
1
https://wiki.python.org/moin/PythonEditors

93
ANEXO I: HERRAMIENTAS

ser un lenguaje tan común, probablemente lo soporte. Si no lo soporta prueba con un IDE
que siga una filoso a similar al que uses.

10.2.2 Editores de código


Quien te escribe usa Vim, un editor de texto muy an guo con muchas caracterís cas que le
hacen ser un editor muy eficiente. Existe gran variedad de editores de código que recomen-
dar: Emacs, gEdit, Kate, Sublime, Atom… Todo dependerá de tus gustos personales.
La ventaja principal de los editores de código es que conociendo uno en profundidad es más
que suficiente para cualquier lenguaje, ya que están diseñados únicamente para escribir el
contenido de tus programas, dejando las peculiaridades de ejecución de cada lenguaje a
parte. Esto les aporta una ligereza di cilmente alcanzable por los IDEs.
Sin embargo, esta virtud también es su mayor defecto. Al no integrar ninguna herramienta
adicional, es necesario trabajar todo manualmente. En el caso de python, te fuerzan a usar
una shell independiente y a interactuar con ella de forma manual. Al principio puede ser
tedioso, pero aprender a ges onar los detalles manualmente es interesante ya que te permite
obtener un gran conocimiento del sistema y lenguaje en el que trabajas.

10.3 Herramientas de depuración


El propio diseño de python permite que sea fácilmente depurable. La REPL facilita que se
pruebe la aplicación a medida que se va desarrollando, función a función, para asegurar que
su comportamiento es el correcto. Además, la capacidad introspec va del lenguaje es una
buena herramienta, en conjunción con la REPL, para comprobar el comportamiento.
Además de estas caracterís cas, la instalación de python viene acompañada del programa
pdb (Python Debugger), un depurador de código similar al conocido GNU-Debugger. Existen
otros depuradores de código más amigables que este, pero la realidad es que no suelen ser
necesarios.

10.4 Testeo de aplicaciones


Hoy en día el testeo de so ware es muy común, en parte gracias al desarrollo guiado por
pruebas, o TDD (Test Driven Development).
La librería estándar de python incluye un módulo para pruebas unitarias llamado unittest
en que la librería Nose, muy conocida y usada, se basa para facilitar el trabajo de modo similar
a lo que ocurre con Requests y urllib.
Por supuesto, existen otras alterna vas, pero estas son las principales.

94 Ekaitz Zárraga
Programar en Python

Anexo II: Licencia CC BY-SA 4.0

Crea ve Commons Atribución/Reconocimiento-Compar rIgual 4.0 Licencia Pública Inter-


nacional

Al ejercer los Derechos Licenciados (definidos a con nuación), Usted acepta y acuerda
estar obligado por los términos y condiciones de esta Licencia Internacional Pública de
Atribución/Reconocimiento-Compar rIgual 4.0 de Crea ve Commons (“Licencia Pública”).
En la medida en que esta Licencia Pública pueda ser interpretada como un contrato, a Usted
se le otorgan los Derechos Licenciados en consideración a su aceptación de estos términos
y condiciones, y el Licenciante le concede a Usted tales derechos en consideración a los
beneficios que el Licenciante recibe por poner a disposición el Material Licenciado bajo
estos términos y condiciones.

Sección 1 – Definiciones.
a. Material Adaptado es aquel material protegido por Derechos de Autor y Derechos
Similares que se deriva o se crea en base al Material Licenciado y en el cual el Material
Licenciado se traduce, altera, arregla, transforma o modifica de manera tal que dicho
resultado sea de aquellos que requieran autorización de acuerdo con los Derechos de
Autor y Derechos Similares que ostenta el Licenciante. A los efectos de esta Licencia
Pública, cuando el Material Licenciado se trate de una obra musical, una interpretación
o una grabación sonora, la sincronización temporal de este material con una imagen
en movimiento siempre producirá Material Adaptado.
b. Licencia de adaptador es aquella licencia que Usted aplica a Sus Derechos de Autor
y Derechos Similares en Sus contribuciones consideradas como Material Adaptado de
acuerdo con los términos y condiciones de esta Licencia Pública.
c. Una Licencia Compa ble con BY-SA es aquella que aparece en la lista disponible en
crea vecommons.org/compa blelicenses2 , aprobada por Crea ve Commons, como
una licencia esencialmente equivalente a esta Licencia Pública.
d. Derechos de Autor y Derechos Similares son todos aquellos derechos estrechamente
vinculados a los derechos de autor, incluidos, de manera enuncia va y no taxa va,
los derechos sobre las interpretaciones, las emisiones, las grabaciones sonoras y los
Derechos “Sui Generis” sobre Bases de Datos, sin importar cómo estos derechos se
encuentren enunciados o categorizados. A los efectos de esta Licencia Pública, los
derechos especificados en las secciones 2(b)(1)-(2) no se consideran Derechos de Autor
y Derechos Similares.
2
https://creativecommons.org/compatiblelicenses

95
ANEXO II: LICENCIA CC BY-SA 4.0

e. Medidas Tecnológicas Efec vas son aquellas medidas que, en ausencia de la debida
autorización, no pueden ser eludidas en virtud de las leyes que cumplen las obligacio-
nes del ar culo 11 del Tratado de la OMPI sobre Derecho de Autor adoptado el 20 de
diciembre de 1996, y/o acuerdos internacionales similares.
f. Excepciones y Limitaciones son el uso justo (fair use), el trato justo (fair dealing) y/o
cualquier otra excepción o limitación a los Derechos de Autor y Derechos Similares
que se apliquen al uso el Material Licenciado.
g. Elementos de la Licencia son los atributos que figuran en el nombre de la Licencia
Pública de Crea ve Commons. Los Elementos de la Licencia de esta Licencia Pública
son Atribución/Reconocimiento y Compar rIgual.
h. Material Licenciado es obra ar s ca o literaria, base de datos o cualquier otro material
al cual el Licenciante aplicó esta Licencia Pública.
i. Derechos Licenciados son derechos otorgados a Usted bajo los términos y condicio-
nes de esta Licencia Pública, los cuales se limitan a todos los Derechos de Autor y
Derechos Similares que apliquen al uso del Material Licenciado y que el Licenciante
ene potestad legal para licenciar.
j. Licenciante es el individuo(s) o la en dad(es) que concede derechos bajo esta Licencia
Pública.
k. Compar r significa proporcionar material al público por cualquier medio o procedi-
miento que requiera permiso conforme a los Derechos Licenciados, tales como la re-
producción, exhibición pública, presentación pública, distribución, difusión, comunica-
ción o importación, así como también su puesta a disposición, incluyendo formas en
que el público pueda acceder al material desde un lugar y momento elegido individual-
mente por ellos.
l. Derechos “Sui Generis” sobre Bases de Datos son aquellos derechos diferentes a los
derechos de autor, resultantes de la Direc va 96/9/EC del Parlamento Europeo y del
Consejo, de 11 de marzo de 1996 sobre la protección jurídica de las bases de datos,
en sus versiones modificadas y/o posteriores, así como otros derechos esencialmente
equivalentes en cualquier otra parte del mundo.
m. Usted es el individuo o la en dad que ejerce los Derechos Licenciados en esta Licencia
Pública. La palabra Su ene un significado equivalente.

Sección 2 – Ámbito de Aplicación.


a. Otorgamiento de la licencia.
1. Sujeto a los términos y condiciones de esta Licencia Pública, el Licenciante le
otorga a Usted una licencia de carácter global, gratuita, no transferible a terceros,
no exclusiva e irrevocable para ejercer los Derechos Licenciados sobre el Material
Licenciado para:
A. reproducir y Compar r el Material Licenciado, en su totalidad o en parte; y
B. producir, reproducir y Compar r Material Adaptado.

96 Ekaitz Zárraga
2. Excepciones y Limitaciones. Para evitar cualquier duda, donde se apliquen Excep-
ciones y Limitaciones al uso del Material Licenciado, esta Licencia Pública no será
aplicable, y Usted no tendrá necesidad de cumplir con sus términos y condiciones.
3. Vigencia. La vigencia de esta Licencia Pública está especificada en la sección 6(a).
4. Medios y formatos; modificaciones técnicas permi das. El Licenciante le autori-
za a Usted a ejercer los Derechos Licenciados en todos los medios y formatos,
actualmente conocidos o por crearse en el futuro, y a realizar las modificaciones
técnicas necesarias para ello. El Licenciante renuncia y/o se compromete a no ha-
cer valer cualquier derecho o potestad para prohibirle a Usted realizar las modi-
ficaciones técnicas necesarias para ejercer los Derechos Licenciados, incluyendo
las modificaciones técnicas necesarias para eludir las Medidas Tecnológicas Efec-
vas. A los efectos de esta Licencia Pública, la mera realización de modificaciones
autorizadas por esta sección 2(a)(4) nunca produce Material Adaptado.
5. Receptores posteriores.
A. Oferta del Licenciante – Material Licenciado. Cada receptor de Material Li-
cenciado recibe automá camente una oferta del Licenciante para ejercer los
Derechos Licenciados bajo los términos y condiciones de esta Licencia Pú-
blica.
B. Oferta adicional por parte del Licenciante – Material Adaptado. Cada recep-
tor del Material Adaptado por Usted recibe automá camente una oferta del
Licenciante para ejercer los Derechos Licenciados en el Material Adaptado
bajo las condiciones de la Licencia del Adaptador que Usted aplique.
C. Sin restricciones a receptores posteriores. Usted no puede ofrecer o imponer
ningún término ni condición diferente o adicional, ni puede aplicar ninguna
Medida Tecnológica Efec va al Material Licenciado si haciéndolo restringe
el ejercicio de los Derechos Licenciados a cualquier receptor del Material Li-
cenciado.
6. Sin endoso. Nada de lo contenido en esta Licencia Pública cons tuye o puede
interpretarse como un permiso para afirmar o implicar que Usted, o que Su uso
del Material Licenciado, está conectado, patrocinado, respaldado o reconocido
con estatus oficial por el Licenciante u otros designados para recibir la Atribu-
ción/Reconocimiento según lo dispuesto en la sección 3(a)(1)(A)(i).
b. Otros derechos.
1. Los derechos morales, tales como el derecho a la integridad, no están comprendi-
dos bajo esta Licencia Pública ni tampoco los derechos de publicidad y privacidad
ni otros derechos personales similares. Sin embargo, en la medida de lo posible,
el Licenciante renuncia y/o se compromete a no hacer valer ninguno de estos de-
rechos que ostenta como Licenciante, limitándose a lo necesario para que Usted
pueda ejercer los Derechos Licenciados, pero no de otra manera.
2. Los derechos de patentes y marcas no son objeto de esta Licencia Pública.
3. En la medida de lo posible, el Licenciante renuncia al derecho de cobrarle regalías a
Usted por el ejercicio de los Derechos Licenciados, ya sea directamente o a través
de una en dad de ges ón colec va bajo cualquier esquema de licenciamiento
voluntario, renunciable o no renunciable. En todos los demás casos, el Licenciante
se reserva expresamente cualquier derecho de cobrar esas regalías.

97
ANEXO II: LICENCIA CC BY-SA 4.0

Sección 3 – Condiciones de la Licencia.


Su ejercicio de los Derechos Licenciados está expresamente sujeto a las condiciones siguien-
tes.
a. Atribución/Reconocimiento.
1. Si Usted comparte el Material Licenciado (incluyendo en forma modificada), Usted
debe:
A. Conservar lo siguiente si es facilitado por el Licenciante con el Material Licen-
ciado:
i. iden ficación del creador o los creadores del Material Licenciado y de
cualquier otra persona designada para recibir Atribución/Reconocimiento,
de cualquier manera razonable solicitada por el Licenciante (incluyendo por
seudónimo si este ha sido designado);
ii. un aviso sobre derecho de autor;
iii. un aviso que se refiera a esta Licencia Pública;
iv. un aviso que se refiera a la limitación de garan as;
v. un URI o un hipervínculo al Material Licenciado en la medida razonablemente
posible;
B. Indicar si Usted modificó el Material Licenciado y conservar una indicación de
las modificaciones anteriores; e C. Indicar que el Material Licenciado está bajo
esta Licencia Pública, e incluir el texto, el URI o el hipervínculo a esta Licencia
Pública.
2. Usted puede sa sfacer las condiciones de la sección 3(a)(1) de cualquier forma ra-
zonable según el medio, las maneras y el contexto en los cuales Usted Comparta
el Material Licenciado. Por ejemplo, puede ser razonable sa sfacer las condicio-
nes facilitando un URI o un hipervínculo a un recurso que incluya la información
requerida.
3. Bajo requerimiento del Licenciante, Usted debe eliminar cualquier información
requerida por la sección 3(a)(1)(A) en la medida razonablemente posible.
b. Compar rIgual.
Además de las condiciones de la sección 3(a), si Usted Comparte Material Adaptado
producido por Usted, también aplican las condiciones siguientes.
1. La Licencia del Adaptador que Usted aplique debe ser una licencia de Crea ve
Commons con los mismos Elementos de la Licencia, ya sea de esta versión o una
posterior, o una Licencia Compa ble con la BY-SA.
2. Usted debe incluir el texto, el URI o el hipervínculo a la Licencia del Adaptador
que aplique. Usted puede sa sfacer esta condición de cualquier forma razona-
ble según el medio, las maneras y el contexto en los cuales Usted Comparta el
Material Adaptado.
3. Usted no puede ofrecer o imponer ningún término o condición adicional o dife-
rente, o aplicar ninguna Medida Tecnológica Efec va al Material Adaptado que

98 Ekaitz Zárraga
restrinja el ejercicio de los derechos concedidos en virtud de la Licencia de Adap-
tador que Usted aplique.

Sección 4 – Derechos “Sui Generis” sobre Bases de Datos.


Cuando los Derechos Licenciados incluyan Derechos “Sui Generis” sobre Bases de Datos
que apliquen a Su uso del Material Licenciado:
a. para evitar cualquier duda, la sección 2(a)(1) le concede a Usted el derecho a extraer,
reu lizar, reproducir y Compar r todo o una parte sustancial de los contenidos de la
base de datos;
b. si Usted incluye la totalidad o una parte sustancial del contenido de una base de da-
tos en otra sobre la cual Usted ostenta Derecho “Sui Generis” sobre Bases de Datos,
entonces ella (pero no sus contenidos individuales) se entenderá como Material Adap-
tado para efectos de la sección 3(b); y
c. Usted debe cumplir con las condiciones de la sección 3(a) si Usted Comparte la totali-
dad o una parte sustancial de los contenidos de la base de datos.
Para evitar dudas, esta sección 4 complementa y no sus tuye Sus obligaciones bajo esta
Licencia Pública cuando los Derechos Licenciados incluyen otros Derechos de Autor y De-
rechos Similares.

Sección 5 – Exención de Garan as y Limitación de Responsabilidad.


a. Salvo que el Licenciante se haya comprome do mediante un acuerdo por separado,
en la medida de lo posible el Licenciante ofrece el Material Licenciado tal como es y
tal como está disponible y no se hace responsable ni ofrece garan as de ningún po
respecto al Material Licenciado, ya sea de manera expresa, implícita, legal u otra. Esto
incluye, de manera no taxa va, las garan as de tulo, comerciabilidad, idoneidad para
un propósito en par cular, no infracción, ausencia de vicios ocultos u otros defectos,
la exac tud, la presencia o la ausencia de errores, sean o no conocidos o detectables.
Cuando no se permita, totalmente o en parte, la declaración de ausencia de garan as,
a Usted puede no aplicársele esta exclusión.
b. En la medida de lo posible, en ningún caso el Licenciante será responsable ante Usted
por ninguna teoría legal (incluyendo, de manera no taxa va, la negligencia) o de otra
manera por cualquier pérdida, coste, gasto o daño directo, especial, indirecto, inci-
dental, consecuente, puni vo, ejemplar u otro que surja de esta Licencia Pública o
del uso del Material Licenciado, incluso cuando el Licenciante haya sido adver do de
la posibilidad de tales pérdidas, costes, gastos o daños. Cuando no se permita la limi-
tación de responsabilidad, ya sea totalmente o en parte, a Usted puede no aplicársele
esta limitación.
c. La renuncia de garan as y la limitación de responsabilidad descritas anteriormente
deberán ser interpretadas, en la medida de lo posible, como lo más próximo a una
exención y renuncia absoluta a todo po de responsabilidad.

Sección 6 – Vigencia y Terminación.

99
ANEXO II: LICENCIA CC BY-SA 4.0

a. Esta Licencia Pública ene una vigencia de aplicación igual al plazo de protección de
los Derechos de Autor y Derechos Similares licenciados aquí. Sin embargo, si Usted
incumple las condiciones de esta Licencia Pública, los derechos que se le conceden
mediante esta Licencia Pública terminan automá camente.
b. En aquellos casos en que Su derecho a u lizar el Material Licenciado se haya terminado
conforme a la sección 6(a), este será restablecido:
1. automá camente a par r de la fecha en que la violación sea subsanada, siempre
y cuando esta se subsane dentro de los 30 días siguientes a par r de Su descu-
brimiento de la violación; o
2. tras el restablecimiento expreso por parte del Licenciante.
Para evitar dudas, esta sección 6(b) no afecta ningún derecho que pueda tener el Li-
cenciante a buscar resarcimiento por Sus violaciones de esta Licencia Pública.
c. Para evitar dudas, el Licenciante también puede ofrecer el Material Licenciado bajo
términos o condiciones diferentes, o dejar de distribuir el Material Licenciado en cual-
quier momento; sin embargo, hacer esto no pondrá fin a esta Licencia Pública.
d. Las secciones 1, 5, 6, 7, y 8 permanecerán vigentes a la terminación de esta Licencia
Pública.

Sección 7 – Otros Términos y Condiciones.


a. El Licenciante no estará obligado por ningún término o condición adicional o diferente
que Usted le comunique a menos que se acuerde expresamente.
b. Cualquier arreglo, convenio o acuerdo en relación con el Material Licenciado que no
se indique en este documento se considera separado e independiente de los términos
y condiciones de esta Licencia Pública.

Sección 8 – Interpretación.
a. Para evitar dudas, esta Licencia Pública no es ni deberá interpretarse como una re-
ducción, limitación, restricción, o una imposición de condiciones al uso de Material
Licenciado que legalmente pueda realizarse sin permiso del tular, más allá de lo con-
templado en esta Licencia Pública.
b. En la medida de lo posible, si alguna disposición de esta Licencia Pública se considera
inaplicable, esta será automá camente modificada en la medida mínima necesaria para
hacerla aplicable. Si la disposición no puede ser reformada, deberá ser eliminada de
esta Licencia Pública sin afectar la exigibilidad de los términos y condiciones restantes.
c. No se podrá renunciar a ningún término o condición de esta Licencia Pública, ni se
consen rá ningún incumplimiento, a menos que se acuerde expresamente con el Li-
cenciante.
d. Nada en esta Licencia Pública cons tuye ni puede ser interpretado como una limitación
o una renuncia a los privilegios e inmunidades que aplican al Licenciante o a Usted,
incluyendo aquellos surgidos a par r de procesos legales de cualquier jurisdicción o
autoridad.

100 Ekaitz Zárraga


101

También podría gustarte