Programar en Python
Programar en Python
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
4 Funciones 33
4.1 Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3
ÍNDICE GENERAL
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
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
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:
• pip: el gestor de paquetería de python. También se conoce como pip3 para diferenciarlo
del pip de python2.
• 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.
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
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.
Y si lo alteras, por ejemplo, con una operación matemá ca sencilla, devuelve el resultado
correspondiente:
>>> 2+2
4
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
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.
10 Ekaitz Zárraga
Programar en Python
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.
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.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.
La nada
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 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"
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
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
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
>>>
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
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
operador significado
+ Suma
19
CAPÍTULO 2. TRABAJANDO CON DATOS
operador significado
- Nega vo o resta
* Mul plicación
/ División
** Potencia
% Resto
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!'}
21
CAPÍTULO 2. TRABAJANDO CON DATOS
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!'}
22 Ekaitz Zárraga
Programar en Python
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.
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.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
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
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
Es rela vamente sencillo prever qué valores son truthy o falsey, normalmente los valores que
representan un vacío se consideran False.
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.
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
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
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.
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
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.
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.
Si la llamamos:
>>> inc(1)
2
>>> inc(10)
11
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.
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.
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.
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.
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.
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 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.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
39
CAPÍTULO 4. FUNCIONES
casos = {
"borrar": borrar,
"crear": crear,
"renombrar": renombrar
}
try:
casos[comando]()
except KeyError:
print("comando desconocido")
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"
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.
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
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.
44 Ekaitz Zárraga
Programar en Python
5 Orientación a Objetos
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.
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.
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.
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.name # Bobby
beltza.name # Beltza
bobby.type # canine
beltza.type # canine
47
CAPÍTULO 5. ORIENTACIÓN A OBJETOS
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
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.
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
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.
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'>
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)
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".
51
CAPÍTULO 5. ORIENTACIÓN A OBJETOS
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.
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.
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.
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.
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.
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
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)
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.
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__.
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.
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.
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.
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
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.
61
CAPÍTULO 5. ORIENTACIÓN A OBJETOS
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)
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
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.
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
...
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.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
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
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
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
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'>
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.
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.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.
71
CAPÍTULO 7. INSTALACIÓN Y DEPENDENCIAS
72 Ekaitz Zárraga
7.2. ENTORNOS VIRTUALES
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.
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.
Puedes lanzar IDLE desde el entorno virtual usando el siguiente truco en la shell de sistema:
pipenv run python -m idlelib.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.
74 Ekaitz Zárraga
7.4. LO QUE HAS APRENDIDO
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.
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
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'
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
80 Ekaitz Zárraga
8.6. PROTOCOLOS DE INTERNET
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] )
...
'
Abstract
81
CAPÍTULO 8. LA LIBRERÍA ESTÁNDAR
referred to as "HTTP/1.1".
'
>>>
82 Ekaitz Zárraga
8.10. LO QUE HAS APRENDIDO
Decimal('0.74')
>>> round(.70 * 1.05, 2)
0.73
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.
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.
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.
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
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
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.
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.
94 Ekaitz Zárraga
Programar en Python
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.
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
98 Ekaitz Zárraga
restrinja el ejercicio de los derechos concedidos en virtud de la Licencia de Adap-
tador que Usted aplique.
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 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.