Sei sulla pagina 1di 178

Fundamentos de Informtica

Departamento de Informtica

2 de septiembre de 2013
ndice general

Presentacin 5

I Introduccin 6

1 Introduccin 7
1.1 Visin general de la Informtica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.1.1 Conceptos y trminos fundamentales . . . . . . . . . . . . . . . . . . . . . . . 7
1.2 Estructura y funcionamiento de un ordenador . . . . . . . . . . . . . . . . . . . . . . 8
1.2.1 Arquitectura y diagrama de bloques de un computador . . . . . . . . . . . . 8
1.3 Representacin de la Informacin en un ordenador . . . . . . . . . . . . . . . . . . . 10
1.3.1 Sistema binario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.4 Las funciones lgicas y su representacin por medio de operadores lgicos . . . . . . 19
1.4.1 Operadores lgicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.4.2 El lenguaje y el uso los operadores lgicos . . . . . . . . . . . . . . . . . . . . 21
1.4.3 Las leyes de De Morgan y otras propiedades interesantes . . . . . . . . . . . . 22
1.4.4 Llevar de lenguaje natural a reglas formales . . . . . . . . . . . . . . . . . . . 23
1.4.5 Un ejemplo ejemplo: las reglas para determinar si un ao ser bisiesto . . . . 23
1.5 Ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.5.1 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

II Introduccin a la programacin 27

2 Introduccin a la programacin 28
2.1 Abstraccin de problemas para su programacin. Conceptos fundamentales . . . . . 28
2.1.1 Qu es un programa? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.1.2 Lenguajes de programacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.1.3 Programas y algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.1.4 Diseo de programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.5 Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2 Variables, expresiones, asignacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.1 Valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.2 Tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.3 Conversiones entre tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.2.4 Operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.2.5 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.2.6 Asignacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.2.7 Otras consideraciones sobre las variables . . . . . . . . . . . . . . . . . . . . . 40
2.2.8 Expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

1
NDICE GENERAL 2

2.3 Uso de entrada/salida por consola . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43


2.3.1 Entrada por teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.3.2 Salida por pantalla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.3.3 Salida con formato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.4 Manejo de estructuras bsicas de control de flujo . . . . . . . . . . . . . . . . . . . . 47
2.4.1 Estructura secuencial (BLOQUE) . . . . . . . . . . . . . . . . . . . . . . . . 48
2.4.2 Estructura alternativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.4.3 Estructuras repetitivas (bucles) . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.4.4 El bucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.4.5 Otras instrucciones para bucles: break y continue . . . . . . . . . . . . . . 59
2.4.6 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.5 Definicin y uso de subprogramas y funciones. mbito de variables . . . . . . . . . . 61
2.5.1 Definiciones y uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.5.2 Documentacin de funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2.5.3 Parmetros y argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.5.4 Flujo de ejecucin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.5.5 Mensajes de error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
2.5.6 Modificando el valor de los parmetros . . . . . . . . . . . . . . . . . . . . . . 68
2.5.7 mbito de parmetros y variables . . . . . . . . . . . . . . . . . . . . . . . . 70
2.5.8 Funciones que retornan valores . . . . . . . . . . . . . . . . . . . . . . . . . . 71
2.5.9 Ejercicios resueltos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.5.10 Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.6 Ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
2.6.1 Apertura y lectura de ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
2.6.2 Escritura en ficheros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
2.6.3 Un ejemplo prctico: agenda de direcciones . . . . . . . . . . . . . . . . . . . 81
2.6.4 Ejercicios propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
2.7 Tipos y estructuras de datos bsicas: listas y arrays . . . . . . . . . . . . . . . . . . 85
2.7.1 El tipo list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.7.2 Acceso a los elementos individuales de la lista . . . . . . . . . . . . . . . . . . 87
2.7.3 Listas que contienen listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
2.7.4 Bucles para recorrer listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
2.7.5 Listas y funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
2.7.6 Listas y cadenas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
2.7.7 Un caso frecuente en ingeniera: listas de listas rectangulares, matrices . . . . 107
2.7.8 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
2.7.9 Operaciones bsicas con arrays . . . . . . . . . . . . . . . . . . . . . . . . . . 115
2.7.10 Copia de arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
2.7.11 Recorrido de arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
2.7.12 Ejercicios resueltos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
2.7.13 Ejercicios Propuestos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

III Introduccin a las bases de datos 129

3 Introduccin a las Bases de Datos 130


3.1 Conceptos de bases de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
3.1.1 Definicin de Bases de Datos (BD) y de Sistema de Gestin de Bases de Datos
(SGBD). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
3.1.2 Funcionalidad de un SGBD . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
NDICE GENERAL 3

3.1.3 Aplicaciones sobre Bases de Datos. . . . . . . . . . . . . . . . . . . . . . . . . 131


3.2 Modelos de Datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
3.3 Modelo Relacional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
3.3.1 Conceptos Bsicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
3.3.2 Diseo de tablas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
3.4 Modelo Entidad-Relacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
3.4.1 Introduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
3.4.2 Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
3.5 Uso bsico del lenguaje SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
3.5.1 rdenes de definicin de datos (LDD) . . . . . . . . . . . . . . . . . . . . . . 137
3.5.2 rdenes de manipulacin de datos (LMD) . . . . . . . . . . . . . . . . . . . . 138
3.6 SGBD en entornos profesionales de la ingeniera . . . . . . . . . . . . . . . . . . . . . 139
3.6.1 Introduccin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
3.6.2 Bases de Datos espaciales y geogrficas . . . . . . . . . . . . . . . . . . . . . 140
3.6.3 Tipos de consultas espaciales . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

IV Componentes hardware y software de un sistema informtico 142

4 Componentes hardware y software de un sistema informtico 143


4.1 Estructura y funcionamiento de un computador . . . . . . . . . . . . . . . . . . . . . 143
4.1.1 Concepto de computador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.1.2 Arquitectura von Neumann . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
4.1.3 Ejecucin de programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
4.2 Dispositivos perifricos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
4.2.1 Perifricos de interfaz humana de entrada . . . . . . . . . . . . . . . . . . . . 148
4.2.2 Perifricos de interfaz humana de salida . . . . . . . . . . . . . . . . . . . . . 149
4.2.3 Perifricos de almacenamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
4.3 Interconexin de sistemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
4.4 Tipos de software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
4.4.1 Desarrollo de software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
4.5 Tipos de sistemas informticos y sus mbitos de aplicacin . . . . . . . . . . . . . . 157

V Introduccin a los sistemas operativos 159

5 Introduccin a los Sistemas Operativos 160


5.1 Concepto y funciones que desempea un sistema operativo . . . . . . . . . . . . . . . 160
5.1.1 Estructura de un sistema computarizado . . . . . . . . . . . . . . . . . . . . . 161
5.1.2 Arranque de un sistema computarizado . . . . . . . . . . . . . . . . . . . . . 161
5.1.3 Funciones de un sistema operativo . . . . . . . . . . . . . . . . . . . . . . . . 163
5.2 Funciones que el sistema operativo presta a los programas . . . . . . . . . . . . . . . 163
5.2.1 Administracin de procesos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
5.2.2 Administracin de memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
5.2.3 Administracin del sistema de ficheros . . . . . . . . . . . . . . . . . . . . . . 164
5.2.4 Administracin de dispositivos . . . . . . . . . . . . . . . . . . . . . . . . . . 166
5.3 Funciones que el sistema operativo presta a los usuarios . . . . . . . . . . . . . . . . 166
5.3.1 Interfaz usuario-ordenador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
5.3.2 Acceso a las Redes de Computadores . . . . . . . . . . . . . . . . . . . . . . . 167
5.3.3 Aplicaciones relativas a la seguridad del sistema . . . . . . . . . . . . . . . . 169
5.4 Sistemas operativos utilizados en entornos profesionales de ingeniera . . . . . . . . . 173
NDICE GENERAL 4

5.4.1 Sistemas operativos en tiempo real . . . . . . . . . . . . . . . . . . . . . . . . 173


5.4.2 Sistemas operativos empotrados . . . . . . . . . . . . . . . . . . . . . . . . . 174

VI Referencias 175
Presentacin

Este documento es un compendio cuyo objetivo no es otro que introducir al lector en los sistemas
informticos. Como se podr observar a travs de una primera lectura del ndice, cubre aspectos
desde el concepto de computador y cmo se representa el universo en el mismo hasta conceptos
fundamentales en el diseo de bases de datos, pasando por programacin de computadores, nociones
de hardware y software de sistemas computarizados y sistemas operativos.
Como tal, este documento es fruto del trabajo colaborativo de muchos profesores del Depar-
tamento de Informtica de la Universidad de Oviedo, quienes han prestado voluntariamente su
tiempo y esfuerzo al desarrollo del mismo. El fin ltimo no es otro que los alumnos de la asignatura
Fundamentos de Informtica dispongan de un material de referencia apropiado para la distribucin
de tiempo y crditos disponible para aquella.
Nos gustara que el lector reflexione sobre este objetivo, ambicioso a la vez que complejo. Esto
es as dado que la asignatura en cuestin es comn a todas las ingenieras que se imparten en
la Universidad de Oviedo: tanto ingenieros mecnicos, qumicos, de montes, informticos, etc. Y
todos ellos deben utilizar el mismo documento, los mismos contenidos. Esta tarea, la de adaptar
un documento a tal variedad de reas de conocimiento es un reto que, desde nuestra ptica, se ha
conseguido en este trabajo.
La organizacin de este documento es como sigue. Est organizado en captulos, cada uno de
ellos describe un tema de entre los contenidos de la asignatura. Cada captulo puede estar dividido
en uno o ms secciones, en un intento de facilitar la lectura y estudio de sus contenidos. Para cada
captulo se incluyen ejercicios resueltos y ejercicios propuestos al alumno para el trabajo autnomo
de ste.
Los materiales docentes relacionados con este documento estn disponibles a travs de www.
campusvirtual.uniovi.es de la Universidad de Oviedo; en los sitios web de cada uno de los
grupos de clases expositivas a impartir.

5
Parte I
Introduccin

6
CAPTULO 1

Introduccin

1.1. Visin general de la Informtica


Informtica, palabra cuyo origen proviene de la fusin de las palabras Informacin y de Au-
tomtica, est definida por la Real Academia de la Lengua Espaola (RAE) como Conjunto de
conocimientos cientficos y tcnicas que hacen posible el tratamiento automtico de la informacin
por medio de ordenadores. Entenderemos las palabras computador (o computadora) y ordenador
como sinnimos.
Pero, Qu es informacin? Cmo puede definirse la informacin? Las definiciones que ofrece
la RAE son: Accin y efecto de informar, Oficina donde se informa sobre algo, etc. No parece que
ayude mucho . . . Quizs una adecuada definicin de informacin sera Conjunto de smbolos que
representan hechos, objetos o ideas y se consideran como relevantes en un contexto o problema con-
creto. O lo que indica la Wikipedia: Secuencia ordenada de smbolos que almacenan o transmiten
un mensaje.
Lo mejor para entenderlo es poner ejemplos. En una transaccin econmica son relevantes los
siguientes hechos: los tems intercambiados, el coste unitario, cantidad de cada uno de los tems que
intervienen. Es tambin relevante cada uno de los actores (objetos) que intervienen. Sin embargo,
en un principio no es relevante el estado del tiempo metereolgico del da de la transaccin, luego
este dato no es informacin.
En este tema se pretende introducir algunos conceptos bsicos que sern tiles a lo largo del
curso. Posteriormente se vern los temas relacionados con la introduccin a la programacin, una
descripcin ms formal de los computadores y los sistemas operativos para, finalmente, introducir
los conceptos fundamentales de bases de datos.
1.1.1. Conceptos y trminos fundamentales
Podemos definir en este apartado una serie de conceptos que vamos a utilizar muy frecuentemente
en esta asignatura. Estos son solo los fundamentales, los necesarios para entender este tema de
introduccin, por lo que se trata de una lista corta. En los diferentes temas a tratar se irn incluyendo
el resto de conceptos a medida que surja la necesidad de utilizarlos.

computador o computadora es una mquina que genera una salida de informacin al aplicar
una secuencia de operaciones lgicas y aritmticas a un conjunto de datos inicial.

ordenador en muchos pases es un sinnimo de computador. Deriva del francs ordinateur, que
significa que ordena o pone en orden... Luego, qu sera ms correcto, el uso de la palabra
computador o, por contra, el uso de ordenador? Esta pregunta tiene una respuesta: son
sinnimos y no perdamos tiempo en tonteras!

7
1.2 Estructura y funcionamiento de un ordenador 8

algoritmo un procedimiento no ambiguo que resuelve un problema. Por procedimiento se entiende


la secuencia de operaciones bien definidas, cada una de las cuales requiere una cantidad finita
de memoria y se realiza en un tiempo finito.

programa es la secuencia ordenada de operaciones lgicas y aritmticas que se introduce en un


computador para que las realice. Est expresado en trminos que la mquina entienda.

programacin de computadores es parte de la Informtica dedicada al estudio de las distintas


metodologas, algoritmos y lenguajes para construir programas.

sistema operativo es el conjunto de programas que gestionan los recursos y procesos de un compu-
tador, permitiendo el uso y explotacin del mismo. El sistema operativo es el responsable de
la normal ejecucin de las diferentes aplicaciones.

aplicacin conjunto de programas que llevan a cabo una tarea al completo. Puede incluir la inte-
gracin de ms de un programa. Ejemplo, aplicacin informtica de venta en internet: utiliza
servidores web, sistemas gestores de bases de datos, etc.

1.2. Estructura y funcionamiento de un ordenador


En esta seccin se introducir de forma breve qu es un computador. Este punto de vista nos
permitir entender por qu se estudia la representacin binaria. Igualmente, nos permitir entender
la diferencia entre programa y cdigo del programa. Al desarrollo del cdigo del programa, cmo
llegar desde el enunciado de un problema al programa que lo resuelve, se dedicar el captulo II.
1.2.1. Arquitectura y diagrama de bloques de un computador
Los ordenadores estn diseados, en su mayora, siguiendo la conocida como Arquitectura
Von Neumann. El procesador (P) es el cerebro, es la responsable de controlar y ejecutar todas
las operaciones que se ejecutan dentro del ordenador. Para que el ordenador pueda trabajar necesita,
adems, otros componentes hardware: la memoria principal -donde se almacena la informacin-
, las unidades de entrada/salida -para acceso a los dispositivos periftricos- y los buses de
interconexin -para conectar todos los componentes del sistema entre s- (ver figura 1.1).
En la figura 1.2 se puede observar un microprocesador bastante antiguo (el 68000 de Motorola).
Este P tiene muchas patillas, cada una tiene una funcin concreta. Por todas estas patillas se
transmiten seales elctricas a travs de los buses hacia o desde los componentes conectados, en
este caso la memoria (ver la parte izquierda de dicha imagen).
Las seales elctricas que se utilizan slo tienen dos posibles valores, por ejemplo, 0 Voltios 5
Voltios (parte derecha de la figura 1.2). Esto se asocia a los estados ALTO y BAJO, y por extensin,
a los estados 1 y 0, o los estados CIERTO y FALSO. Es decir, se puede decir que el P se expresa
en binario. Para acceder a la direccin 25, por ejemplo, en las patillas del P correspondientes al
bus de direcciones debe aparecer la combinacin binaria que sea equivalente al valor 25. Pero el bus
de direcciones son cables . . .
Y, Cmo se puede representar un nmero con seales elctricas? Bien, cada cable puede llevar
en cada instante un valor, que puede ser un valor cercano a 0 voltios o bien distinto de cero. Es
decir, cada cable lleva informacin de estado: o es BAJO o es ALTO. Que significa esto? Que los
buses -al igual de el P- slo pueden gestionar por cada cable dos posibles valores: 0 1, BAJO o
ALTO. Es decir, que un computador slo puede gestionar informacin binaria. Cada una
de estas seales binarias se denomina bit (acrnimo de binary digit).
El ser humano no maneja este tipo de informacin (al menos no lo hace de buen gusto). El tipo
de informacin que utiliza el ser humano son nmeros (tanto reales como enteros), texto, imgenes,
vdeo, etc. Y sin embargo, somos capaces de interactuar con las mquinas y ellas con nosotros.
Cmo? La cuestin es que el computador almacena la informacin de forma binaria y la presenta
1.2 Estructura y funcionamiento de un ordenador 9

Procesador$

Bus$de$datos$
Bus$de$direcciones$
Bus$de$control$

Entrada/Salida$
Memoria$

Figura 1.1: Elementos de un computador y su interconexin.


Fuentes de
las imgenes: http://hardzone.es/2012/05/09/intel-core-i5-3570k-vs-core-i7-3770k-datos-de-
rendimiento-a-4-8ghz/, http://www.afsur.com/wp-content/uploads/2012/08/ddr3-vs-ddr2-ram.jpg,
http://img.hexus.net/v2/motherboards/intel/X58/XFX/MoboT.jpg.

Memoria)

Buses)
Procesador)

Figura 1.2: Ejemplo de un P antiguo, pero que debido a la baja densidad de integracin
se puede observar fcilmente a simple vista. A la izquierda se puede ver las conexiones en-
tre los diferentes dispositivos, mientras que en la parte derecha se puede observar la natura-
leza de las seales elctricas que se utilizan. Fuentes de las imgenes: http://retro.co.za/ccc/mac/,
http://computersbrain.blogspot.com.es/2012/03/ale-signal-of-80868088.html.
1.3 Representacin de la Informacin en un ordenador 10

al ser humano adecuadamente. Por ejemplo, el nmero 25 se almacena como 00011001, mientras
que lo visualiza como 25.

1.3. Representacin de la Informacin en un ordenador


Un computador representa la informacin utilizando dgitos binarios, es decir, en base 2. En esta
base slo se dispone de 2 valores diferentes: {0, 1}. El humano usa la base decimal, base 10, con
10 posibles valores diferentes: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}. Sin embargo, una combinacin binaria se
evala de igual manera que una combinacin decimal, como puede verse en la figura 1.3.

En#el#sistema#decimal## En#el#sistema#binario##
dgitos#{0,#1,#2,#3,#4,#5,#6,#7,#8,#9}# dgitos#{0,#1}#
53810#=#5*10 +#3*10 +#8*10
2# 1# 0# 1012#=#1*22#+#0*21#+#1*20#=#4+0+1#=#510#
5#est#en#la#posicin#2# 1#est#en#la#posicin#2#
3#est#en#la#posicin#1# 0#est#en#la#posicin#1#
8#est#en#la#posicin#0# 1#est#en#la#posicin#0#

Figura 1.3: Evaluacin de una combinacin decimal y de una binaria. Slo se diferencia en i) los
posibles dgitos y ii) la base. El mtodo es el mismo!

La representacin numrica utilizada por el ser humano


Los nmeros son una abstraccin del ser humano para expresar cantidades. El problema
aparece cuando hay que escribirlos. Cmo hacerlo? Desde el uso de nudos en cuerdas y
otros sistemas complejos hasta el uso de smbolos grficos (bien letras como los romanos,
bien signos especficos como los arbigos), el ser humano ha utlizado muy diferentes
sistemas para la representacin de los nmeros enteros. El problema se complica si se
intenta representar nmeros reales.
A continuacin se repasar el sistema ms habitual utilizado por el ser humano para
representar nmeros: utilizando dgitos arbigos y el sistema decimal. Primero se revisar
cmo el ser humano representa los nmeros enteros y luego se har lo propio con los
nmeros reales.
h La representacin numrica utilizada por el ser humano El sistema decimal
utiliza base 10, lo que significa que existen 10 dgitos posibles: {0, 1, 2, 3, 4, 5, 6,
7, 8, 9}. En general, cuando se utiliza un sistema numrico con base, digamos, X,
entonces tendremos X dgitos posibles y sus valores son:{0, 1, 2, . . . , X 1}.

Volviendo al sistema decimal o base 10, como se desee. Se dispone entonces de 10


dgitos. Para representar un nmero, por ejemplo cuatrocientos veintitres (cuatro-
cientos veinte y tres), pondremos el dgito correspondiente a las unidades (tres)
en primer lugar a la derecha, y el correspondiente a las decenas (dos) justo a su
izquierda, y finalmente el de las centenas (cuatro) a la izquierda del de las decenas.
Cada posicin hacia la izquierda va multiplicado por una potencia de 10 una unidad
mayor.

En otras palabras, lo que realmente se realiza es la siguiente suma de productos:


4 102 + 2 101 + 3 100 = 400 + 20 + 3 = 423. Dado lo acostumbrados que estamos los
humanos a realizar estos pasos nos parece del todo natural: no nos paramos a pensar
qu hacemos ni la naturaleza de la representacin numrica existente.
1.3 Representacin de la Informacin en un ordenador 11

Lo mismo ocurre cuando queremos extraer las unidades, decenas, centenas, etc.
Realmente, las operaciones a realizar son sucesivas divisiones entre la base (10),
quedndonos con el resto como dgito significativo.

Si queremos descomponer el nmero 423 en sus unidades, decenas y centenas lo que


se realiza es lo siguiente. Primero, se divide utilizando la divisin entera n = 423
entre 10 (la base): m = 423/10 = 42 y resto r = 3 representando las unidades. Como
m > 0, hacemos n = m y repetimos. Se divide utilizando la divisin entera n = 42
entre 10 (la base): m = 42/10 = 4 y resto r = 2 representando las decenas. Como
m > 0, hacemos n = m y repetimos. Se divide utilizando la divisin entera n = 4
entre 10 (la base): m = 4/10 = 0 y resto r = 4 representando las centenas. Como
m = 0 sabemos que se ha finalizado.

Como se puede apreciar, es muy sencillo: lo utilizamos habitualmente. Simplemente


hay unas reglas bsicas: i) los nmeros se escriben de derecha a izquierda, a ms
significativo sea un dgito ms a la izquierda aparecer; ii)cada posicin a la izquierda
significa una potencia de 10 mayor; y iii)para extraer las unidades, decenas, etc. se
realizan sucesivas divisiones enteras entre la base, reteniendo el resto.

h El sistema decimal y los nmeros reales En el caso de los nmeros reales, el


principio es el mismo. La parte entera se representa como se ha visto en la seccin
anterior. La parte fraccionaria se representa como potencias decrecientes de la base 10.

As, el nmero 423.1678 se puede expresar como 4 102 + 2 101 + 3 100 + 1 101 +
6 102 + 7 103 + 8 104 .

Una forma habitual de representar los nmeros reales es por medio de la notacin
cientfica, esto es, utilizando una mantisa M que multiplica a la base 10 elevada
a un exponente e. El exponente expresa el nmero de posiciones que hay que des-
plazar a la izquierda (si e es positivo) o a la derecha (si e es negativo) el punto decimal.

As, 423.1678 se podra expresar como 4.231678 102 , donde la mantisa es M =


4.231678 y el exponente e = 2. Igualmente, el nmero 0.009873 se podra expresar
como 9.873 103 , con M = 9.873 y e = 3.

1.3.1. Sistema binario


El sistema binario se basa en utilizar la base 2. Aplicando lo visto anteriormente, los posibles
dgitos son {0, 1}. Slo se dispone de estos dos posibles valores. La unidad de informacin que es
capaz de almacenar un dgito binario se denomina bit, que es la contraccin de binary digit como
se ha dicho previamente.
Utilizando bits tenemos que ser capaces de representar todo tipo de informacin si queremos que
un computador sea capaz de procesarlo. Recordemos que los computadores slo son capaces de ges-
tionar informacin binaria. En las siguientes subsecciones se presentar cmo se pueden representar
los diferentes tipos de informacin en formato binario.
Representacin de nmeros enteros positivos
Supongamos un computador de 8 bits -en vez de los megafantsticos actuales de 64 bits-. Con
8 bits debemos representar los enteros sin signo. Como se pudo ver en la figura 1.3, los enteros sin
1.3 Representacin de la Informacin en un ordenador 12

signo se representan mediante una combinacin ordenara de bits, donde cada posicin p tiene un
peso de basep = 2p .
Para convertir de binario a decimal solo se deben sumar las sucesivas multiplicaciones de d-
gito por peso y se obtendr el valor decimal equivalente. Luego el valor binario 010110012 =
07 16 05 14 13 02 01 10 = 0 27 + 1 26 + 0 25 + 1 24 + 1 23 + 0 22 + 0 21 + 1 20 =64 + 16 + 8 + 1 = 89.
Por el contrario, para llevar de decimal a binario se se realizan divisiones enteras sucesivas entre la
base, utilizando el resto de la divisin como dgito binario. Sea el nmero 12310 a expresar o codificar
en binario, el proceso se visualiza en la tabla 1.1. Observar el orden de los dgitos binarios: cada uno
lleva implcitamente asociado el nmero de divisiones necesarias para poder extraerlo. Adems, si
hacemos la analoga con lo realizado para nmeros decimales y cmo extraer sus unidades, se puede
deducir que es la misma.

Cociente Resto Posicin


123/2 = 61 123 %2 = 1 0
61/2 = 30 123 %2 = 1 1
30/2 = 15 123 %2 = 0 2
15/2 = 7 123 %2 = 1 4
7/2 = 3 123 %2 = 1 4
3/2 = 1 3 %2 = 1 5
1/2 = 0 1 %2 = 1 6
Nmero binario 16 15 14 13 02 11 10 011110112

Tabla 1.1: Conversin de un nmero codificado en decimal a su correspondiente codificacin binaria.


El operador % es el resto de la divisin entera o mdulo.
Ejemplos resueltos:

De decimal a binario 35:

1. 35/2 17 resto 1
2. 17/2 8 resto 1
3. 8/2 4 resto 0
4. 4/2 2 resto 0
5. 2/2 1 resto 0
6. 1/2 0 resto 1
7. El nmero es 1000112

De decimal a binario 52:

1. 52/2 26 resto 0
2. 26/2 13 resto 0
3. 13/2 6 resto 1
4. 6/2 3 resto 0
5. 3/2 1 resto 1
6. 1/2 0 resto 1
7. El nmero es 1101002

De binario a decimal 11011:

1. enumeramos las posiciones: 14 13 02 11 10


2. elevamos las posiciones a potencia de 2 y multiplicamos por el dgito correspondiente: 1 24 + 1 23 + 0 22 + 1
21 + 1 20
3. sumamos todos los elementos: 16 + 8 + 0 + 2 + 1 = 27

De binario a decimal 101101:


1.3 Representacin de la Informacin en un ordenador 13

1. enumeramos las posiciones: 15 04 13 12 01 10


2. elevamos las posiciones a potencia de 2 y multiplicamos por el dgito correspondiente: 1 25 + 0 24 + 1 23 + 1
22 + 0 21 + 1 20
3. sumamos todos los elementos: 32 + 0 + 8 + 4 + 0 + 1 = 45

Sistema hexadecimal
Ahora bien, Cul es el valor decimal del nmero binario 10001111101100? Lo puedes recordar
fcilmente? Menuda cantidad de operaciones o de memoria para poder gestionar esta combinacin
binaria . . . Sin embargo, existe un truco: Aprovechando que 24 = 16, es decir, que con 4 bits
podemos representar 16 valores, se propuso el sistema de nmeros hexadecimales o base 16.
Este sistema de representacin utiliza 16 dgitos: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A=10 , B=11 , C=12 ,
D=13 , E=14 , F=15 }. Su principal bondad es que permite acortar la representacin binaria, lo que
facilita la lectura por parte del ser humano.
La idea se basa en lo siguiente. Existe una tabla que relaciona directamente dgitos hexadecimales
con sus correspondientes combinaciones de 4 bits (ver tabla 1.2). Los dgitos hexadecimales suelen
llevar delante 0x para indicar que se utiliza la base 16.

Base 10 Base 16 Base 2 Base 10 Base 16 Base 2


0 0 0000 8 8 1000
1 1 0001 9 9 1001
2 2 0010 10 A 1010
3 3 0011 11 B 1011
4 4 0100 12 C 1100
5 5 0101 13 D 1101
6 6 0110 14 E 1110
7 7 0111 15 F 1111

Tabla 1.2: Correlacin entre los dgitos de los sistemas codificados en decimal (Base 10), hexadecimal
(Base 16 0x) y binario (base 2).

Supongamos se tiene el nmero binario 10011100110011, el cul es muy difcil de recordar.


Sin embargo, podemos agrupar sus bits de cuatro en cuatro, comenzando por la derecha, y dejarlo
como 10 0111 0011 0011, y si aadimos ceros por la izquierda para completar tambin cuatro bits
en el primer grupo, el nmero es el mismo: 0010 0111 0011 0011. Utilizando la tabla 1.2 podemos
decir que es el nmero 0x2733, que es ms facil de recordar y de llevar a decimal.
Para traducir de hexadecimal a decimal y viceversa se reutilizan las mismas operaciones que las
vistas para traducir de decimal a binario:

de hexadecimal a decimal: cada dgito hi expresa una potencia de 16, por lo 0x3A2 =
0x3pos=2 Apos=1 2pos=0 = 3 162 + A 161 + 2 160 = 3 256 + A 16 + 2 1 = 768 + 160 + 2 = 930.

de decimal a hexadecimal: divisiones sucesivas entre la base (16).


Veamos otros ejemplos:

Ej1 110110

agrupar de 4 en 4 bits, desde la derecha a la izda.: 11 0110


completar con 0s hasta tener grupos de 4 bits: 0011 0110
utilizar la tabla: 36 16 = 0x36
a decimal: 3 161 + 6 161 =48 + 6=54

Ej2 10001111101100
1.3 Representacin de la Informacin en un ordenador 14

agrupar de 4 en 4 bits, desde la derecha a la izda.: 10 0011 1110 1100


completar con 0s hasta tener grupos de 4 bits: 0010 0011 1110 1100
utilizar la tabla: 2 3 E C 16 = 0x23EC
a decimal: 2 163 + 3 162 + 15 161 + 12 161 =8192 + 768 + 240 + 12=9212

Representacin de nmeros enteros negativos


Retornando al tema de representar informacin en un computador, analizaremos ahora los n-
meros enteros negativos. Para representar nmeros enteros negativos se utiliza mayoritariamente el
denominado complemento a 2 dado que facilita el diseo de los circuitos integrados que deban
operar con nmeros enteros, positivos o negativos (los microprocesadores son circuitos integrados,
p.e.). Se define el complemento a 2 de un nmero binario n (negativo) como el resultado de la
operacin 2N |n|. Es decir, que si utilizo 8 bits (N = 8) y quiero representar n = 5, entonces,
realizar la operacin 28 5, cuyo resultado es 251, y representar en binario el nmero 251. Se deja
al lector el ejercicio de pasar a binario 251, y comprobar que el resultado es 11111011b .
Un atajo para llegar al mismo resultado consiste en seguir los siguientes pasos: i) representar
el nmero positivo en binario, ii) recorrer de derecha a izquierda la combinacin resultante, iii) a
partir del primer 1 -sin incluirlo-, cambiar los 0s por 1s y viceversa. Ejemplo: n = 5 en 8 bits.
Representacin de |n| en binario es 000001012 . Cambio los 0s y 1s a partir del primer 1 por la
derecha: 111110112 .
A la hora de realizar la suma final, ya que esta debe hacerse en binario, conviene conocer las
reglas de la suma binaria, que se resumen en:

0 + 0 vale 0
0 + 1 vale 1
1 + 0 vale 1
1 + 1 vale 0 y me llevo 1
1 + 1 + 1 vale 1 y me llevo 1

Rango de los nmeros enteros con y sin signo


Supongamos se utilizan N bits para representar enteros. La pregunta es Cuntos enteros sin
signo puedo representar con estos N bits?
Para entenderlo de forma sencilla, pongamos varios ejemplos.
N = 1 se puede representar 0 1. Luego puedo representar 2 valores, o lo que es igual,
21 .
N = 2 se puede representar 00, 01, 10 11. Luego puedo representar 4 valores, o lo que
es igual, 22 = 2 21 .
N = 3 se puede representar 000, 001, 010, 011, 100, 101, 110, 111. Luego puedo re-
presentar 8 valores, o lo que es igual, 23 = 2 22 .
. . . Cada vez que aadimos un dgito duplicamos el nmero de combinaciones, luego
por induccin se llega a que, para un N cualquiera, el nmero de combinaciones
son 2N = 2 2N 1 .
Luego, con 8 bits puedo representar 28 = 256 combinaciones binarias diferentes, o lo que es
igual, 256 enteros.
Qu pasa con los enteros con signo? Pues que debido a la forma de representar los nmeros
negativos el bit ms significativo discrimina el signo: si este bit vale 1 es un nmero negativo, positivo
en caso contrario. Por lo tanto, con N bits puedo representar desde 2N 1 hasta 2N 1 1. El que
se represente un entero menos en caso de nmero entero positivo (observar el 1 que resta a 2N 1 )
se debe a que el valor 0 est incluido entre los que tiene el bit de signo a 0... luego puedo representar
un entero positivo menos.
1.3 Representacin de la Informacin en un ordenador 15

Nomenclatura de los mltiplos y submltiplos


Como se ha dicho, un bit es la unidad bsica de informacin. Sin embargo, salvo en telecomuni-
caciones y contados casos ms, lo habitual es hablar de mltiplos de bit. As, se conoce como byte
la agrupacin de 8 bits para formar un valor. Se puede decir que 32 bits son 4 bytes y que 64 bits
son 8 bytes. Se puede indicar la unidad: b refiere a bits, mientras que B refiere a bytes.
Los mltiplos y submltiplos de bit (b) o de byte (B) se pueden expresar, siguiendo el Sistema
Internacional de Unidades, en trminos de potencias de la base 10 (observa que la abreviatura de
Kilo, lleva la k minscula):

Kilo expresa 103 : 1 kb son 1000 bits, 1 kB son 1000 bytes


Mega expresa 106 : 1 Mb son 1000 kb, 1 MB son 1000 kB
Giga expresa 109 : 1 Gb son 1000 Mb, 1 GB son 1000 MB
Tera expresa 1012 : 1 Tb son 1000 Gb, 1 TB son 1000 GB
Peta expresa 1015 : 1 Pb son 1000 Pb, 1 PB son 1000 TB

Representacin de nmeros reales


La representacin binaria de nmeros reales
utiliza la notacin cientfica -formato exponencial- expresando tanto la mantisa como el expo-
nente en base 2
el exponente se representa en
se usa un nmero de bits de la mantisa mayor que para el exponente
el exponente admite nmeros negativos en exceso a Z
la mantisa se representa en signo-magnitud
El formato en 32 bits es el indicado en la figura 1.4. Para el caso de 64 bits, el exponente se
expresa en 11 bits y la parte fraccionaria en 52. Se recomienda los siguientes Para saber ms a los
lectores interesados.

Figura 1.4: Representacin de nmeros reales en formato IEEE754 para 32 bits.

Para saber ms sobre la representacin de nmeros reales


La representacin en binario de los nmeros reales es, quizs, ms compleja para el ser
humano que el sistema decimal. Para representar nmeros reales se utiliza un formato
denominado coma flotante, porque dentro del patrn de bits que el computador al-
macena, no hay un lugar predeterminado para la coma que separa la parte entera de la
parte fraccin. En lugar de ello, se usan parte de los bits para almacenar la mantisa y
otra parte para almacenar el exponente. La posicin de la coma depende del valor del
exponente.
Tanto la mantisa como el exponente pueden ser positivos o negativos, por lo que cada
uno de estos campos ha de tener en cuenta la codificacin del signo. Por razones tcnicas,
1.3 Representacin de la Informacin en un ordenador 16

en los formatos de coma flotante no se suele usar complemento a 2 para almacenar el


signo, sino otros mecanismos que se salen de los objetivos de esta asignatura.
Puesto que no veremos como se almacena el signo, plantearemos un ejemplo con un
nmero positivo. Supongamos que se desea codificar en binario el nmero n = 8.7510 .
Lo primero es escribir ese nmero en binario, para lo cual tenemos que expresarlo como
una suma de potencias de dos. Esto no siempre resulta posible (porque la suma puede
tener infinitos trminos). En este caso s es posible, ya que 8.75 = 8 + 0.5 + 0.25 =
8 + 12 + 14 = 23 + 21 + 22 . Por tanto, usando el sistema posicional binario tendramos
que 8.7510 = 1000.11b .
Una vez tenemos la representacin binaria 1000.11b el siguiente paso es ponerla en forma
normalizada, lo que significa mover la coma hasta que a su izquierda quede un nico
bit, de valor 1. En este caso, habra que mover la coma dos posiciones hacia la izquierda
para obtener 1.00011b . Para que el nmero siga siendo el mismo, debe multiplicarse por 2
elevado al nmero de posiciones que hemos movido la coma (si la coma se movi hacia la
derecha, el exponente sera negativo). En este caso, por tanto: 1000.11b = 1.00011b 22 .
Puedes comprobar con una calculadora que esto es cierto, ya que 1.00011 es 1.09375 que
multiplicado por 8 (23 ) da 8.75.
Ya tenemos por tanto el nmero en notacin exponencial: 1.00011 22 y vemos que la
mantisa es 1.00011 y el exponente es 2. En un formato de coma flotante se almacenarn
separadamente los bits de la mantisa (100011) sin especificar dnde est la coma, que
se asume justo despus del primer uno1 , y la representacin binaria del exponente,
codificado en un cierto nmero de bits (por ejemplo, en 8 bits sera 2 = 0000 0010).

Para saber ms: representacin de fracciones en binario


El mecanismo general para pasar a binario un nmero con parte fraccionaria se sale de
los objetivos de esta asignatura. Para el lector interesado, se explica a continuacin el
algoritmo, sobre el ejemplo 8.7510 :
1. Se separa la parte entera de la parte fraccin. La parte entera es 8, la parte fraccin
es 0.75.
2. La parte entera se pasa a binario por el mtodo ya explicado en su momento, es
decir, dividiendo sucesivamente por 2 y quedndose con los restos. En este caso
sale 810 = 1000b .
3. La parte fraccin se pasa a binario multiplicando sucesivamente por 2 y quedndose
con lo que se obtiene en la parte entera, separando la parte fraccin para la siguiente
repeticin del algoritmo, hasta que esta parte fraccin sea cero.
En nuestro ejemplo tenemos 0.75 2 = 1.5, lo que nos da en la parte entera 1 (que
sera el primer bit de la respuesta), y en la parte fraccin 0.5, que usamos en la
iteracin siguiente.
Realizando ahora 0.5 2 = 1.0 obtenemos en la parte entera otro 1 (segundo bit
de la respuesta) y en la parte fraccin 0, luego hemos terminado.
Es decir 0.7510 = 0.11b .
4. El paso anterior puede no finalizar nunca, porque en la parte fraccin nunca apa-
rezca un cero. Sin embargo descubriremos que a partir de un punto el patrn de
1 y 0 comienza a repetirse. Es decir, hemos encontrado un nmero peridico en
binario. Prueba por ejemplo a convertir 0.2 para descubrir este fenmeno.
1.3 Representacin de la Informacin en un ordenador 17

Cuando esto ocurre, es necesario detenerse en algn punto, ignorando todos los
bits que vendran despus. Esto implica que estaremos despreciando decimales (en
binario) y por tanto cometiendo un error en la representacin. El nmero 0.2 no
puede representarse de forma exacta en binario, pues require infinitos decimales. Si
lo representamos con solo 4 decimales, sera igual a 0.0011b , que no es en realidad
el 0.2 sino el 0.1875 (23 + 24 ).
5. Una vez hallada la parte entera y la parte fraccin, ambas se concatenan, por lo
que 8.7510 = 1000.11b .

Los datos booleanos: POSITIVO o NEGATIVO


Siempre que el resultado de una operacin o de una pregunta sea CIERTO o FALSO estamos
hablando de datos booleanos. Por lo tanto, no es algo nuevo para nadie. Veamos unos ejemplos:

Ej1 Es el nmero 232 un nmero par? CIERTO

Ej2 5 > 8 FALSO

Ej3 Est el nmero 23 en el intervalo [10, 20]? esta pregunta es


equivalente a 23 >= 10 y 23 <= 20? FALSO

Normalmente los tipos de datos booleanos solo necesitan un bit para almacenarlos. En todo
caso, FALSO (False en ingls) se evala como 0. Todo aquello que no sea cero es CIERTO (True en
ingls).
Es interesante apuntar que en el ejemplo Ej3 anterior puede observarse cmo se puede plantear
una pregunta en trminos matemticos por medio de los operadores lgicos, en este caso, dos
comparaciones enlazadas mediante la conjucin Y. Dada la importancia de stos en la programacin
y, en general, en la vida diaria, la siguiente seccin (ver apartado 1.4) se explicarn los mismos.
Representacin de caracteres
Como ya se ha expuesto, los computadores slo almacenan combinaciones de bits, cada bit
representa un valor {0, 1} o binario. Por lo tanto, toda informacin a almacenar se debe representar
como una combinacin binaria.
Esto incluye a los caracteres. Un carcter (bien sea un espacio en blanco, un carcter alfabtico,
un dgito, un signo de puntuacin, etc.) se representa con una combinacin binaria. Pero no una
representacin binaria cualquiera, sino una representacin binaria bien conocida: se han definido
cdigos estndar.
Los cdigos estndar son tablas publicadas como si de estndares industriales se tratasen (es
decir, estn aceptadas por los fabricantes de programas y sistemas operativos), donde bsicamente
a cada carcter se le asigna un valor entero, lo que permite representarlo con un cdigo binario.
Uno de stos cdigos es el conocido como ASCII, que es el acrnimo de la American Standard
Code for Information Interchange. Esta tabla de cdigos (disponible en http://www.lookuptables.
com o en http://www.asciitable.com/) utiliza 7 bits, por lo que el nmero de combinaciones
diferentes es de 27 = 128 caracteres.
As, al carcter a se le asigna el valor 9710 = 6116 , mientras que al carcter A se le asigna
el 6510 = 4116 . Un observador habituado a trabajar con representaciones de enteros en formato
hexadecimal ver que la diferencia entre maysculas y minsculas es un bit (en este tema se presenta
el sistema numrico hexadecimal en el apartado 1.3.1). Esto no es fruto de la casualidad, sino
del trabajo de matemticos e ingenieros, permitiendo codificaciones que reduzcan la capacidad
computacional necesaria para trabajar con caracteres.
1.3 Representacin de la Informacin en un ordenador 18

De igual manera, las letras maysculas van seguidas una de otra en el orden alfabtico. Igual
ocurre con las letras minsculas y tambin con los dgitos. Esto permite operar con los caracteres,
como se opera con los enteros:
Si resto dos letras maysculas obtengo el nmero entero correspondiente al nmero de letras
que hay entre ambas, e.g., J-A 74 65 = 9.

dem con la letras minsculas, j-a= 9.

Los caracteres correspondientes a dgitos se pueden restar, resultando en la diferencia entre el


valor de ambos, 5-3= 53 51 = 2.
La extensin a 8 bits del cdigo ASCII es el conocido como CP852 (Code Page 852, utilizado
por IBM; conocido tambin como OEM 852, MS-DOS Latin 2, PC Latin 2, Slavic -Latin II-)
No obstante, el cdigo ASCII y otros cdigos similares presentan un grave problema: no pueden
representar todos los smbolos de todos los lenguajes. Si pensamos en la gran cantidad de lenguajes
existentes, cada uno con sus caracteres especficos (la , por ejemplo), se desprende que 128 son
pocos. . . El ASCII se extendi a 8 bits (256 posibilidades o combinaciones diferentes), pero el
problema continua existiendo para el ASCII extendido.
Por ello se han diseado otros sistemas de codificacin de caracteres, intentando universalizar
el cdigo. As nace el Unicode, cuya intencin fue la de permitir una representacin de caracteres
comn a travs de internet, y que contemple todos los caracteres de todos los alfabetos existentes.
Este estndar asigna un cdigo binario nico a cada posible letra de cada posible carcter. Para
almacenar o transmitir estos cdigos binarios se definen diferentes formatos (UTF-8, UTF-16 o
UTF-32). Nos centraremos en el UTF-8 al ser el estndar de facto en WWW, debido a que requiere
menos espacio de almacenamiento y menos ancho de banda.
Qu hace especial al UTF-8? Pues que utiliza de uno a 4 bytes de 8 bits para referenciar a
cada uno de los caracteres utilizados en la tabla Unicode Standard (http://www.unicode.org/
charts/). Las 128 primeras posiciones utilizan un byte y se corresponden con el ASCII estndar. A
medida que se va avanzando en la pgina de cdigos se van utilizando ms bytes, hasta un mximo
de 4 bytes. Cabe sealar que con 3 bytes bastan para codificar cualquier letra de cualquier alfabeto
vivo.
Cuatro bytes son slo necesarios para alfabetos muy raros y que no se usan hoy da para la
comunicacin escrita. En el caso del idioma espaol, la mayora de los caracteres requieren un solo
byte, por ser compatibles con ASCII, salvo las vocales acentuadas y la ee, que no forman parte del
ASCII y requieren 2 bytes en UTF-8. El signo del euro requiere tres bytes.

Adems de texto plano...


Hemos visto cmo se almacenan los datos de texto: los archivos de texto plano -que
no tienen formato, como cursiva, etc. se almacenan usando los cdigos ASCII o UTF
correspondientes a todos y cada uno de los caracteres que contiene. Pero, Qu pasa
con las imgenes, con los vdeos, con el audio? Cmo se representa en un ordenador?
La respuesta simplista: en binario. Bien, para representar cada tipo de informacin se
requiere de un formato de almacenado.
As como la industria se puso de acuerdo para el tema de los caracteres, con estndares
que permiten un uso eficaz del hardware del computador, lo mismo ocurre con los di-
ferentes medios audiovisuales: la industria adopta estndares que permiten un manejo
eficaz de los dispositivos.
As surgen los diferentes estndares para almacenamiento e intercambio de datos. A
modo de ejemplo se enumeran algunos de los ms conocidos.
1.4 Las funciones lgicas y su representacin por medio de operadores lgicos 19

Archivos comprimidos
zip que es onomatopeya de algo que pasa raudo, veloz. Es un compresor de archivos
sin prdidas cuyo algoritmo de compresin (PKZIP), desarrollado por Phil Katz y
dejado libre.
rar es un algoritmo de compresin de archivos sin prdidas desarrollado por Eugene
Roshal.
tar es un formato para embeber diferentes archivos en un slo ncleo de informacin
que pueda ser comprimido y/o almacenado eficazmente.
Archivos con imgenes
JPEG, JPG Joint Photographic Experts Group, utilizando un algoritmo de compresin
con prdidas parametrizable.
GIF Graphics Interchange Format, que presenta prdida de informacin, utilizando bit-
maps con 8 bits por pixel para especificar el color y compresin sin prdidas LZW.
TIFF Tagged Image File Format, permite contener en un solo archivo varias imgenes
en calidad JPEG conjuntamente con etiquetas, etc. Actualmente est bajo control
de Adobe. Se puede almacenar informacin con o sin prdidas.
PNG Portable Network Graphics. Formato grfico diseado para sustituir a otros de
similar funcionalidad (GIF, TIFF), pero sobre los que pesaban patentes. Almace-
na las imgenes con un algoritmo de compresin sin prdidas, y admite diferen-
tes sub-formatos con diferente nmero de bits por color. Tambin soporta colores
transparentes.
Documentos electrnicos
PDF Portable Document Format diseado por Adobe, soporta tanto texto como imge-
nes vectoriales y en mapas de bits. Es un formato definido para facilitar la impresin
y el intercambio de archivos.
PS PostScript es un lenguaje para la descripcin de pginas que es utilizado en muchos
sistemas de impresin as como para el intercambio de documentos entre mltiples
plataformas y en talleres de impresin profesional.
XML Extensible Markup Language es un conjunto de reglas para codificar documentos
(incluyendo texto, imgenes, etc., en general, informacin) de forma que puedan
ser intercambiados sin ambigedad entre mquinas y fcilmente presentables para
lectura al ser humano.
Archivos de audio/video
MPEG 1 a 4 Moving Pictures Experts Group-Audio para almacenado de audio sin dis-
torsin ni prdidas.
MPEG video Moving Pictures Experts Group para transferencia de video y audio.

1.4. Las funciones lgicas y su representacin por medio de operadores


lgicos
Hasta ahora se ha repasado la representacin de la informacin en el sistema binario con el
objetivo de almacenar los diferentes tipos de datos en un computador, de manera que ste pueda
realizar su clculos. Pero adems de los datos, es necesario hacer los programas que realicen todos
los clculos y tomas de decisiones. A modo de ejemplo muy simple, veamos el caso del cmputo
de la raz cuadrada de un valor real como un nmero real en una calculadora normal. En este
caso, si el valor es negativo la raz no tiene solucin real sino imaginaria, por lo que mostrar un
1.4 Las funciones lgicas y su representacin por medio de operadores lgicos 20

mensaje de error. Por lo tanto, el programa dentro de la calculadora tendr una regla del tipo: SI el
valor es menor que 0 ENTONCES mostrar mensaje de error, SINO realizar el clculo. Esta regla
est expresada en trminos humanos. Por lo tanto, Cmo son las decisiones humanas?Qu tipo
de reglas tiende el humano a utilizar?Cmo se interpretan estas reglas?Cmo se decide con las
reglas?
Estas preguntas se pretenden resolver en esta seccin. Necesitamos conocer: i) los operadores
lgicos -que se vern en la siguiente subseccin-, ii) representacin de condiciones de evaluacin de
una regla -apartado 1.4.2-, iii) reglas de simplificacin y equivalencia conocidas Leyes de De Morgan
-1.4.3 -, y iv) cmo expresar las condiciones desde el lenguaje natural a un lenguaje formal.
1.4.1. Operadores lgicos
Estos operadores requieren uno o dos operandos, los cules sern interpretados como booleanos.
El resultado de los operadores es tambin booleano.
Recordar que booleano significa que tiene dos posibles valores: {True, False}. El valor False se
suele asimilar al valor 0, todo lo que no valga 0 es True. As, el valor 25 es equivalente a True.
Cada operador equivale a una de las posibles operaciones lgicas que realiza el ser humano, pero
que tambin tienen un sentido matemtico formal.
Operador Lgico Y (AND)
Se interpreta como que ambas condiciones deben ser ciertas para que la conjucin sea cierta
(edad>=18 Y tiene_carnet_de_conducir).
Una operacin de este tipo sera a&b, y se lee a Y b.
Tanto a como b se traducen al correspondiente valor booleano.
Finalmente, se opera segn se indica en la tabla 1.3.

a b a&b
False False False
False True False
True False False
True True True

Tabla 1.3: Tabla de verdad del operador lgico AND.

El resultado es, por tanto, True o False.


Operador Lgico O (OR)
Se expresa tpicamente con el operador |.
Se interpreta como si cualquiera de las condiciones es cierta entonces la disyucin es cierta
(edad>=8 O tiene_carnet_de_conducir).
Una operacin de este tipo sera a|b, y se lee a O b.
Tanto a como b se traducen al correspondiente valor booleano.
Finalmente, se opera segn se indica en la tabla 1.4.

a b a|b
False False False
False True True
True False True
True True True

Tabla 1.4: Tabla de verdad del operador lgico OR.

El resultado es, por tanto, True o False.


1.4 Las funciones lgicas y su representacin por medio de operadores lgicos 21

Operador Lgico Negacin (NOT)


Se expresa tpicamente con el operador .
Una operacin de este tipo sera b, y se lee NO b o bien, la negacin de b.
Finalmente, se opera segn se indica en la tabla 1.5.

b b
False True
True False

Tabla 1.5: Tabla de verdad del operador lgico NOT.

El resultado es, por tanto, True o False.


Operador Lgico XOR
Se expresa tpicamente con el operador
Se interpreta como si las condiciones tienen distinto valor entonces la operacin es cierta.
Una operacin de este tipo sera a b, y se lee a XOR b, o exclusivo de a y b o bien a y b
son distintos.
Tanto a como b se traducen al correspondiente valor booleano.
Finalmente, se opera segn se indica en la tabla 1.6.

a b ab
False False False
False True True
True False True
True True False

Tabla 1.6: Tabla de verdad del operador lgico XOR.

El resultado es, por tanto, True o False.


1.4.2. El lenguaje y el uso los operadores lgicos
Todos los operadores anteriores, o casi todos, se utilizan habitualmente en programacin. Pero
sobre todo, se utilizan en el lenguaje oral y escrito.
Pongamos por caso la evaluacin de una asignatura con dos partes, la terica y la prctica. Para
la nota terica (NT) se deber superar dos exmenes parciales independientemente (obtenindose
las notas parciales NT1 y NT2). En el caso que ambas notas sean mayores o iguales a 5, la NT ser
la media de ambas. Igualmente, si ambas son menores que 5 la NT se obtiene como la media de
NT1 y NT2. En otro caso, es decir, cuando solo se aprueba una de los dos pruebas parciales, la NT
ser el mnimo de ambas notas parciales. Por lo tanto, para superar teora, la NT debe ser mayor
o igual a 5.
La prctica se evala con 2 pruebas; la nota de prcticas (NP) se obtiene como la media entre
las dos notas de las dos evaluaciones prcticas (NP1 y NP2). El alumno debe tener una NP mayor
o igual a 4 para poder compensar.
Un alumno aprueba la asignatura si la NT es mayor o igual a 5, la NP es mayor o igual a 4 y
la suma de ambas es mayor o igual a 5.
Bien, pues aqu tenemos muchas, muchas reglas y operadores lgicos. Vamos a separarlas una a
una.
L1 SI N T 1 >= 5 Y N T 2 >= 5 ENTONCES N T = (N T 1 + N T 2)/2
L2 SINO, SI N T 1 < 5 Y N T 2 < 5 ENTONCES N T = (N T 1 + N T 2)/2
L3 SINO N T = mn (N T 1, N T 2)
1.4 Las funciones lgicas y su representacin por medio de operadores lgicos 22

L4 N P = (N P 1 + N P 2)/2
L5 N F = (N T + N P )/2
L6 Si N T >= 5 Y N P >= 4 Y N F >= 5 ENTONCES alumno_aprobado =
CIERTO
Dado que las reglas en las lneas L1 y L2 tienen la misma consecuencia, podemos simplificar una
regla usando el operador OR (|). Nos quedara el siguiente conjunto de reglas, donde usaremos ya
los operadores lgicos:
L1 SI (N T 1 >= 5 & N T 2 >= 5) | (N T 1 < 5 & N T 2 < 5) ENTONCES N T =
(N T 1 + N T 2)/2
L2 SINO N T = mn (N T 1, N T 2)
L3 N P = (N P 1 + N P 2)/2
L4 N F = (N T + N P )/2
L5 Si N T >= 5 & N P >= 4 & N F >= 5 ENTONCES alumno_aprobado =
CIERTO
Es importante observar que el uso de parntesis para agrupar qu operadores se desea ejecutar
primero. Con estas reglas tenemos descrito cmo un alumno puede aprobar una asignatura, y como
se ha demostrado, del lenguaje natural se llega al uso de los operadores lgicos y unas condiciones.
La regla en la lnea L5 es lo que se conoce como regla SI-ENTONCES. La parte condicional,
es decir, la parte del SI incluye una serie de clausulas o condiciones (conocidos como antecedentes)
que se tienen que cumplir (o verificar) para que la regla se active o dispare o se ejecute. Si la
regla se activa entonces se ejecutan las consecuencias. Las lneas L1 y L2 forman una regla SI-
ENTONCES-SINO, es decir, tiene un consecuente para el caso CIERTO y un consecuente para
el caso FALSO.
A lo largo de este curso es necesario que se aprenda a expresar las reglas de funcionamiento o
de decisin que hara un ser humano en lenguaje natural para luego poder pasarlas a cdigo de un
programa. O lo que es lo mismo, realizar la serie de pasos vistos en este apartado para los problemas
a resolver.
1.4.3. Las leyes de De Morgan y otras propiedades interesantes
En las reglas anteriores no se ha mencionado para nada cmo se determina que un alumno no
ha superado la asignatura. La respuesta es obvia: un alumno NO ha superado la asignatura si
NO se cumplen las condiciones para que el alumno haya aprobado la asignatura.
En otras palabras, si no se cumplen las condiciones de la regla en la lnea L5. Por lo tanto, hay
que negar dicha regla, con los que nos quedara la siguiente nueva regla:
L6 SI NO(N T >= 5 & N P >= 4 & N F >= 5) ENTONCES alumno_suspende =
CIERTO
Claro, aprovechando el operador negacin podemos generar esta regla. Pero, Es necesariamente
tan compleja esta regla? Cmo podemos simplificar esta regla?
Las respuestas a estas preguntas son: No, no es necesario que sea tan compleja esta regla. La
podemos simplificar aplicando las Leyes de De Morgan.
Bsicamente, existen dos propiedades fundamentales o Leyes de De Morgan. Observe que la
negacin de una operacin booleana es la conjugada del operador utilizando los operandos negados.
La conjugada del operador Y lgico es el O lgico, y viceversa.
Primera Ley de De Morgan: (a&b) = a|b
Segunda Ley de De Morgan: (a|b) = a&b
1.4 Las funciones lgicas y su representacin por medio de operadores lgicos 23

(b) b (a < b) a >= b (a <= b) a > b


(a > b) a <= b (a >= b) a < b

Tabla 1.7: Algunas propiedades interesantes a utilizar en la simplificacin de reglas.

Tambin hay una serie de propieades que se cumplen que son interesantes recordar.
Si aplicamos las Leyes de De Morgan a la regla L6 llegamos a la siguiente expresin.

L6 SI ((N T >= 5)|(N P >= 4)|(N F >= 5)) ENTONCES alumno_suspende=CIERTO

Y simplificando nos queda finalmente la regla para determinar cundo suspende un alumno.

L6 SI ((N T < 5)|(N P < 4)|(N P < 5)) ENTONCES alumno_suspende = CIERTO

1.4.4. Llevar de lenguaje natural a reglas formales


Esto es algo que nos servir siempre. Sin embargo, no es tan obvio como parece. Basicamente,
seguiremos los siguientes pasos:

1. Identificar las reglas contenidas en el texto

2. Para cada regla identificada:

identificar sus condiciones o antecedentes


identificar sus consecuencias
escribir la regla de manera formal.

3. Verificar que la tabla de verdad de cada regla es correcta.

1.4.5. Un ejemplo ejemplo: las reglas para determinar si un ao ser bisiesto


Segn la Wikipedia, un ao es bisiesto si es divisible entre 4, a menos que sea divisible entre
100. Sin embargo, si un ao es divisible entre 100 y adems es divisible entre 400, tambin resulta
bisiesto. Obviamente, esto elimina los aos finiseculares (ltimos de cada siglo, que ha de terminar
en 00) divisibles slo entre 4 y entre 100.
Supongamos que tenemos un valor de aos -nos referiremos a ellos por el nombre aos- Podra
expresar las reglas para determinar si aos es bisiesto o no?
ANTES DE SEGUIR, INTENTE REALIZAR ESTE EJERCICIO POR SUS PRO-
PIOS MEDIOS!

Identificar las reglas Pueden ocurrir dos cosas: que ao sea divisible por cuatro o que no lo sea.
Si no lo es, ya sabemos que es bisiesto. Pero si es divisible ente 4, entonces puede ocurrir que
sea divisible entre 100 o no. Si no lo es, ya sabemos que ao es bisiesto. Pero si es divisible
entre 100, entonces puede ocurrir que sea divisible entre 400: si lo es ao es bisiesto, si no es
divisible entonces ao no es bisiesto.

escribir formalmente todas las reglas lo que nos deja las siguientes reglas anidadas

SI ao es divisible entre cuatro


SI ao es divisible por 100
SI ao es divisible por 400 ENTONCES ao es bisiesto es CIERTO
SINO ao es bisiesto es FALSO
SINO ao es bisiesto es CIERTO
SINO, SI ao es bisiesto es FALSO
1.5 Ejercicios resueltos 24

Comprobar con valores de aos para ver si las reglas y sus condiciones son vlidas. Se deben
proponer valores diferentes y a mano resolver si son bisiestos o no. Finalmente, evaluar las
reglas para ver si son vlidas.

25: no es divisible entre 4. Si analizo las reglas, se activara la lnea L6. correcto
28: es divisible entre 4, no lo es por 100. Luego es bisiesto. Si analizo las reglas, se
comprueba que entra por la regla de la lnea L1, luego por la L5. Luego es correcto,
100: es divisible entre 4 y 100, no por 400. Luego no es bisiesto. Si analizo las reglas veo
que se activan la L1, L2 y L4. El resultado final es que el ao no es bisiesto. Correcto.
1600: es divisible entre 4, 100 y 400: es bisiesto. Si analizo las reglas, veo que se asignan
la L1, L2 y L3. Luego es bisiesto y las reglas correctas.

1.5. Ejercicios resueltos


1. Expresar el nmero decimal 28 en binario
28/2 = 14, resto 0
14/2 = 7, resto 0
7/2 = 3, resto 1
3/2 = 1, resto 1
1/2 = 0, resto 1 11100

2. Expresar el nmero decimal 33 en binario usando 8 bits


33/2 = 16, resto 1
16/2 = 8, resto 0
8/2 = 4, resto 0
4/2 = 2, resto 0
2/2 = 1, resto 0
1/2 = 0, resto 1 33 es 100001 en binario
ahora hay que obtener el complemento a 2. Para ello:
rellenamos por la izquierda con ceros hasta completar 8 bits: 00100001
hallamos su complemento a 1 (cambiar unos por ceros y ceros por unos) 00100001
11011110
sumamos 1 al resultado anterior 11011110 + 1 = 11011111

3. Expresar el nmero binario 1101110 en decimal


16 15 04 13 12 11 00
1 26 + 1 25 + 0 24 + 1 23 + 1 22 + 1 21 + 0 20
32 + 16 + 0 + 8 + 4 + 2 + 0
62

4. Expresar el nmero binario 10110110111101 en hexadecimal


10 1101 1011 1101
0010 1101 1011 1101
2DBD

5. Expresar el nmero hexadecimal 3AFE416 en decimal


34 A3 F2 E1 40
3 164 + A 163 + F 162 + E 161 + 4 160
3 65536 + 10 4096 + 15 256 + 14 16 + 4
196608 + 40960 + 3840 + 224 + 4
1.5 Ejercicios resueltos 25

241636

6. Expresar el nmero hexadecimal 3AFE416 en binario


3AF E4
00111010111111100100

Simplificar las siguientes expresiones:

1. (((a&b)&c)|(d|a))

a) ((a&b)&c)&(d|a)
b) ((a&b)|c)&(d|a)
c) ((a&b)|c)&(d|a)
d) (a&b&d)|(a&b&a)|(c&d)|(c&a)
e) (a&b&d)|(c&d)|(c&a)
f ) (a&b&d)|(c&(d|a))

2. ((a < b&a < c)|a >= 0)

a) (a < b&a < c)&(a >= 0)


b) (a < b&a < c)&(a < 0)

3. ((c > a|a > d)&(c > b|b > d))

a) (c > a|a > d)|(c > b|b > d)


b) ((c > a)&(a > d))|((c > b)&(b > d))
c) ((c <= a)&a <= d))|((c <= b)&(b <= d))

1.5.1. Ejercicios propuestos


1. Complete la tabla 1.8 realizando las conversiones necesarias

Base 10 Base 16 Base 2


84
6F
11001111011
10101010101
3F5
556
100
FABADA
11111111000111000

Tabla 1.8: Completar la tabla con los valores que faltan en la correspondiente base.

2. Buscar el cdigo ASCII de la A, B, F y Z y determinar el nmero de letras que hay


entre la Z y el resto

3. Cmo llevara de letra minscula a mayscula usando el cdigo ASCII de los caracteres?

Simplifique las siguientes expresiones usando las leyes de De Morgan y otras propiedades.
26

(a&(b|c))
(x >= a|x <= b)
(b >= c|a <= d)

Encuentre las reglas que se incluyen en las siguientes expresiones:

La luz del led se enciende de la siguiente manera. Si la presin es mayor de 1.5 bar y la
temperatura es mayor de 25o C la luz es roja. En caso que la presin sea mayor de 2 bar
entonces la luz parpadear. Para el resto de situaciones, si la presin est por encima de
1 bar o la temperatura est en el rango comprendido entre 20 y 25 o C entonces la luz
estar ambar. En el resto de los casos, la luz estar verde.
Si la edad es menor de 3 aos es un beb, entre 3 y 5 es un infante, entre 5 y 12 es un
nio, entre 12 y 18 es un adolescente y a partir de los 67 puedes estar jubilado. En el
resto de los casos, es un adulto.
Tenemos dos tanques, cada uno con su bomba de achique. Arrancarn las bombas de
achique con el siguiente criterio. Si el nivel en ambos tanques es mayor al nivel de se-
guridad 1, arrancarn las bombas de achique de ambos tanques. En otro caso, cuando
el nivel en uno de los tanques sea mayor al nivel de seguridad 2 se arrancar la corres-
pondiente bomba. Las bombas se detendrn cuando el nivel de los tanques sea menor al
nivel mnimo. En el resto de las situaciones no se debe hacer nada.
Parte II
Introduccin a la
programacin

27
CAPTULO 2

Introduccin a la programacin

2.1. Abstraccin de problemas para su programacin. Conceptos fun-


damentales
2.1.1. Qu es un programa?
La habilidad ms importante del ingeniero es la capacidad para solucionar problemas. La
solucin de problemas incluye poder formalizar problemas, pensar en la solucin de manera creativa,
y expresar esta solucin en trminos que un ordenador pueda entender. La solucin de problemas
mediante el uso del ordenador se consigue a travs de los programas.
Definicin
Un programa es un texto con una secuencia de instrucciones que un ordenador puede
interpretar y ejecutar.

Los programas son, por tanto, el medio de comunicacin con el ordenador. Mediante su utiliza-
cin conseguimos que las mquinas aprovechen sus capacidades para resolver los problemas que nos
interesan. Sin los programas los ordenadores no son capaces de hacer nada.
2.1.2. Lenguajes de programacin
Los programas se escriben en lenguajes especializados llamados lenguajes de programacin.
Hay muchos lenguajes de programacin, pero para programar no es necesario conocerlos todos. En
esencia, la tcnica bsica necesaria para programar es comn a todos los lenguajes.
Definicin
Un lenguaje de programacin es un idioma formado por un conjunto de smbolos y reglas
sintcticas y semnticas que definen la estructura y el significado de las instrucciones de
que consta el lenguaje.

Cuando escribimos un programa utilizando un determinado lenguaje de programacin llamamos


cdigo fuente, o simplemente cdigo, al texto del programa. Cuando un ordenador lleva a cabo
una tarea indicada por un programa, decimos que ejecuta el cdigo.
Aunque no vamos a entrar en los detalles de cada uno, es necesario mencionar que a la hora
de programar se pueden seguir diversas tcnicas o paradigmas de programacin: programacin
imperativa, declarativa, estructurada, modular, orientada a objetos, etc. Los lenguajes de progra-
macin suelen soportar varios de estos paradigmas de programacin.

28
2.1 Abstraccin de problemas para su programacin. Conceptos fundamentales 29

Independientemente del lenguaje que se utilice, es importante que el alumno se acostumbre


a seguir los principios de la programacin modular, que consiste en dividir un programa en
mdulos o subprogramas con el fin de hacerlo ms legible y manejable.
En general, un problema complejo debe ser dividido en varios subproblemas ms simples, y estos
a su vez en otros subproblemas ms simples. Esto debe hacerse hasta obtener subproblemas lo sufi-
cientemente simples como para poder ser resueltos fcilmente con algn lenguaje de programacin.
En la actualidad los lenguajes de programacin, llamados de alto nivel, estn pensados para que
los programas sean comprensibles por el ser humano. Sin embargo, el cdigo fuente de los mismos
no es comprendido por el ordenador, ya que ste slo maneja el lenguaje binario o lenguaje
mquina.
Es necesario hacer una traduccin de los programas escritos en un lenguaje de programacin
de alto nivel a lenguaje mquina. Hay dos tipos diferentes de lenguajes dependiendo de la forma de
hacer esta traduccin:

Lenguajes compilados El Compilador realiza una traduccin completa del programa en


lenguaje de alto nivel a un programa equivalente en lenguaje mquina. Este programa resul-
tante, programa ejecutable, se puede ejecutar todas las veces que se quiera sin necesidad
de volver a traducir el programa original.

Lenguajes interpretados En este caso, el Intrprete va leyendo el programa en lenguaje de


alto nivel instruccin a instruccin, cada una de ellas se traduce y se ejecuta. No se genera un
programa directamente ejecutable.

El enfoque compilado genera cdigo ejecutable que utiliza directamente las instrucciones nativas de
la CPU. Esto suele implicar que el programa se ejecutar mucho ms velozmente que si se hiciera
en un lenguaje interpretado. A cambio, presenta el inconveniente de que el ejecutable resultante
de la compilacin slo sirve para ser ejecutado en una CPU concreta y un Sistema Operativo
concreto (aquellos para los que se compil), o bien versiones compatibles de la CPU y el operativo,
mientras que si se hiciera en un lenguaje interpretado podra ser ejecutado en cualquier arquitectura
y operativo para los que exista el intrprete.
2.1.3. Programas y algoritmos
Cuando se aprende el primer lenguaje de programacin se piensa que la parte difcil de resolver
un problema con un ordenador es escribir el programa siguiendo las reglas del lenguaje. Esto es
2.1 Abstraccin de problemas para su programacin. Conceptos fundamentales 30

totalmente falso. La parte ms difcil es encontrar el mtodo de resolucin del problema. Una
vez encontrado este mtodo, es bastante sencillo traducirlo al lenguaje de programacin necesario:
Python, C++, Java o cualquier otro.
Definicin
Se denomina algoritmo a una secuencia no ambigua, finita y ordenada de instrucciones
que han de seguirse para resolver un problema.

Importante
Un programa de ordenador es un algoritmo escrito en un lenguaje de programacin.

En un algoritmo siempre se deben de considerar tres partes:


Entrada: informacin dada al algoritmo.
Proceso: operaciones o clculos necesarios para encontrar la solucin del problema.
Salida: respuestas dadas por el algoritmo o resultados finales de los procesos realizados.
Los algoritmos se pueden expresar de muchas maneras: utilizando lenguajes formales, lenguajes
algortmicos (pseudocdigo) o mediante el lenguaje natural (como el castellano). Esta ltima es la
forma ms adecuada para la asignatura que nos ocupa.
Ejemplo: Algoritmo para calcular el rea de un tringulo
1. Obtener la base del tringulo
2. Obtener la altura del tringulo
3. Hacer la operacin (base altura)/2
4. Mostrar el resultado

Este algoritmo de resolucin del rea del tringulo es independiente del lenguaje de programacin
que vayamos a utilizar. Cualquier programa que quiera calcular el rea de un tringulo escrito en
cualquier lenguaje de programacin debe seguir estos pasos.
Terminologa
Dos programas distintos codificados en el mismo o en distinto lenguaje de programacin
y que resuelven el mismo problema con la misma secuencia de pasos, se dice que son
implementaciones del mismo algoritmo.

2.1.4. Diseo de programas


Aunque el diseo de programas es un proceso creativo, hay que seguir una serie de pasos. Nadie
empieza a escribir un programa directamente sin estudiar el problema que se quiere resolver.
Todo el proceso de diseo de un programa se puede dividr en dos fases:

Fase de resolucin de problemas. El resultado de esta primera fase es un algoritmo,


expresado en espaol, para resolver el problema.

Fase de implementacin. A partir del algoritmo obtenido en la fase anterior, se codifica y


se prueba el programa final.
2.1 Abstraccin de problemas para su programacin. Conceptos fundamentales 31

Importante
Muchos programadores noveles no entienden la necesidad de disear un algoritmo antes
de escribir un programa en un lenguaje de programacin. La experiencia ha demostra-
do que la resolucin de problemas en dos fases da lugar a programas que funcionan
correctamente en menos tiempo.

Esta forma de disear programas requiere la realizacin de una serie de tareas:

Anlisis del problema. A partir de la descripcin del problema, expresado habitualmente en


lenguaje natural, es necesario obtener una idea clara sobre qu se debe hacer (proceso), deter-
minar los datos necesarios para conseguirlo (entrada) y la informacin que debe proporcionar
la resolucin del problema (salida).

Diseo del algoritmo. Se debe identificar las tareas ms importantes para resolver el pro-
blema y disponerlas en el orden en el que han de ser ejecutadas. Los pasos en una primera
descripcin pueden requerir una revisin adicional antes de que podamos obtener un algoritmo
claro, preciso y completo.

Transformacin del algoritmo en un programa (codificacin). Solamente despus


de realizar las dos etapas anteriores abordaremos la codificacin de nuestro programa en
el lenguaje de programacin elegido.

Ejecucin y pruebas del programa. Se debe comprobar que el programa resultante est
correctamente escrito en el lenguaje de programacin y, ms importante an, que hace lo que
realmente debe hacer.

2.1.5. Python
Python es un lenguaje de alto nivel como pueden ser el C, C++ o el Java. Entonces, por qu
hemos escogido precisamente Phyton en este curso? Python presenta una serie de ventajas que lo
2.1 Abstraccin de problemas para su programacin. Conceptos fundamentales 32

hacen muy atractivo, tanto para su uso profesional como para el aprendizaje de la programacin.
Entre ellas podemos destacar las siguientes:

La sintaxis es muy sencilla y cercana al lenguaje natural, lo que facilita tanto la escritura
como la lectura de los programas.

Es un lenguaje muy expresivo que da lugar a programas compactos, bastante ms cortos que
sus equivalentes en otros lenguajes.

Es un lenguaje de programacin multiparadigma, que permite al programador elegir entre


varios estilos: programacin orientada a objetos, programacin imperativa (y modular) y pro-
gramacin funcional.

Es multiplataforma por lo que podremos utilizarlo tanto en Unix/Linux, Mac/OS o Microsoft


Windows.

Es un lenguaje interpretado y por tanto interactivo. En el entorno de programacin de Python


se pueden introducir sentencias que se ejecutan y producen un resultado visible, que puede
ayudarnos a entender mejor el lenguaje y probar los resultados de la ejecucin de porciones
de cdigo rpidamente.

Python es gratuito, incluso para propsitos empresariales.

Es un lenguaje que est creciendo en popularidad. Algunas empresas que utilizan Python son
Yahoo, Google, Disney, la NASA, Red Hat, etc.

Para saber ms
Python es un lenguaje de programacin creado por Guido van Rossum a principios de
los aos 90 cuyo nombre est inspirado en el grupo de cmicos ingleses Monty Python.
Toda la informacin necesaria sobre el lenguaje la puedes encontrar en http://www.
python.org/.

Python permite dos modos de interaccin con el lenguaje:


1. Escribir comandos directamente en el intrprete. En este modo, cada lnea que escribimos es
ejecutada al pulsar el retorno de carro, y el resultado de la ejecucin se muestra inmediatamen-
te, a continuacin. Es til para probar ejemplos simples y ver inmediatamente el resultado,
y para experimentar con diferentes expresiones para comprender mejor sus diferencias y su
funcionamiento.
El inconveniente es que todo lo que se va escribiendo, se pierde cuando se cierra el intrprete.
2. Escribir un programa completo en un editor de textos, guardar el programa en un fichero y
despus usar el intrprete para ejecutarlo.
En este caso no se ejecuta nada mientras se escribe, sino slo cuando se lanza el intrprete
para que ejecute el programa completo que est en el fichero. Entonces el intrprete ir leyendo
lnea a lnea del fichero y las ir ejecutando. No se muestra ningn resultado por pantalla,
a menos que el programa contenga la orden print que sirve precisamente para esto (como
veremos en su momento).
A lo largo de este documento, presentaremos ejemplos en ambos formatos. Si se trata de ejemplos
muy breves encaminados slo a demostrar alguna caracterstica del lenguaje, usaremos el intrprete
directo. Si se trata de ejemplos ms largos que tienen inters suficiente para merecer ser guardados
en un fichero, usaremos el editor.
2.2 Variables, expresiones, asignacin 33

El lector puede diferenciar si usamos el intrprete o el editor, porque el estilo en que se muestra
el cdigo es diferente en cada caso. Cuando se usa el intrprete, puede verse el smbolo >>> delante
de cada lnea que el usuario teclea, y la respuesta del intrprete en la lnea siguiente:
>>> "Ejemplo ejecutado en el interprete"
Ejemplo ejecutado en el iterprete

En cambio, cuando se muestra cdigo para ser escrito en el editor, no se ve el resultado de su


ejecucin. Adems las lneas estn numeradas para facilitar el referirse a ellas si es necesario (el
alumno no debe copiar estos nmeros cuando escriba el cdigo en el editor).
1 # Ejemplo para ser escrito en el editor
2 print "Ejemplo"

2.2. Variables, expresiones, asignacin


2.2.1. Valores
El principal motivo por el que se escriben programas de ordenador es para manipular la informa-
cin de una forma ms eficiente y segura. Desde el punto de vista de la informacin, los programas
manejan tpicamente los datos del siguiente modo:
1. Reciben datos de entrada por parte de los usuarios,
2. procesan esos datos, haciendo clculos y operaciones con ellos, y
3. producen resultados que son tiles para los usuarios.
Los resultados pueden ser tanto valores calculados (por ejemplo, en una aplicacin de clculo de
estructuras, obtener las dimensiones que debe tener una viga), como obtener un informe impreso.
Aunque la informacin que manejan los programas puede parecer muy amplia, ya que existen
aplicaciones informticas para propsitos muy diversos, en realidad la informacin est formada
habitualmente por la agregacin de tres tipos de de datos bsicos:
nmeros: 7, 3.14165
textos: Juan, Alonso, Universidad de Oviedo
valores lgicos: True, False
Combinando estos elementos se puede representar la informacin bsica que usan los programas.
Por ejemplo, si se quiere hacer una aplicacin para gestionar los datos de cada cliente de un banco,
necesitaremos guardar su nombre y apellidos (textos), el saldo de sus cuentas (nmeros) o si el cliente
es preferente o no (valor lgico). Los valores lgicos tal vez parezcan menos tiles, sin embargo es
casi lo contrario, no solamente permiten representar aquella informacin que puede ser cierta o falsa,
sino que adems son los datos fundamentales para controlar el flujo de ejecucin de los programas
(como se ver ms adelante, las sentencias condicionales y los bucles se basan en la manipulacin
de valores lgicos).
2.2.2. Tipos
Cada dato o valor que se maneja en un programa es de un tipo. Python detecta de qu tipo
es cada dato por su sintaxis. Una secuencia de dgitos que no contenga el punto (.) se considera
un entero. Si contiene el punto se considera un real (que python llama float). Una secuencia
arbitraria de caracteres delimitados por el carcter de comillas dobles ("), o de comillas simples ()
es considerado una cadena de texto1 . Las palabras especiales True y False se consideran datos de
tipo booleano.

7 es de tipo int (de integer), es un nmero entero

3.14165 es de tipo float, un nmero en coma flotante (real)


1
Para delimitar las cadenas se puede usar indistintamente la comilla simple o la doble, pero es forzoso usar el
mismo tipo de comilla para abrir y para cerrar.
2.2 Variables, expresiones, asignacin 34

"Juan", es de tipo str (de string), es una cadena de caracteres


True es de tipo bool (de booleano), un valor de verdad
Los tipos definen conjuntos de valores que los programas pueden manejar y las operaciones que
se pueden hacer con ellos. Por ejemplo, los programas pueden utilizar, gracias al tipo float, el
conjunto de los nmeros reales y podemos sumar dos reales. En concreto, el rango de los nmeros
reales que se pueden utilizar es de 1.7e308 que viene dado por el nmero de bytes (8) que se
utilizan para representarlos2 .
Para saber ms
Adems del tipo int, python posee otro tipo entero, long. Normalmente se manejan
los valores enteros como int ya que este tipo permite representar valores del orden de
millones de billones. Si alguna vez un programa necesita guardar un valor entero an
mayor, entonces se representar automticamente (sin que el programador deba hacer
nada) como un long. La capacidad de representacin de un long est slo limitada
por la cantidad de memoria libre, por lo que en la prctica puede representar valores
enteros extremadamente grandes.

Para saber el tipo de un valor, se puede utilizar la funcin type. Simplemente hay que indicar
el valor del que se quiere conocer su tipo:
>>>> type(7)
<type int>
>>> type(3.1416)
<type float>
>>> type("Juan")
<type str>
>>> type(True)
<type bool>

Como se puede apreciar, se imprime en la consola el tipo de cada uno de los valores. En realidad
esto no es muy til a la hora de escribir un programa, ya que normalmente el programador sabe de
qu tipo es cada uno de los datos que el programa maneja.
2.2.3. Conversiones entre tipos
A veces los programas reciben valores que son de un cierto tipo y necesitan convertirlos en
valores de otro tipo antes de hacer operaciones con ellos. Esta situacin se produce, por ejemplo, con
datos que se reciben como string pero que representan nmeros; antes de hacer clculos con ellos es
necesario convertirlos en un valor numrico. La forma de hacer esas conversiones es bastante sencilla:
primero hay que indicar el nombre del tipo al que se quiere convertir el valor, y posteriormente entre
parntesis el valor que se quiere convertir. Por ejemplo:
>>> int("7")
7
>>> str(7)
7
>>> float("3.1416")
3.1415999999999999
>>> str(3.1416)
3.1416
>>> int(3.1416)
3
>>> float(7)
7.0

2
Cuando un nmero real se sale de ese rango se considera
2.2 Variables, expresiones, asignacin 35

En el primer ejemplo se convierte en int la cadena de caracteres formada solamente por el


dgito 7. El valor que se devuelve es el entero 7, que obviamente no es lo mismo la cadena que
contiene el dgito 7, ni en cuanto al dato en s mismo, ni sobre todo a las operaciones que se van
a poder hacer con l (la cadena con el dgito 7 no se podr dividir por otro valor, mientras que el
valor entero s). El ejemplo contrario se da en la siguiente instruccin. En este caso se convierte en
cadena (str) el valor entero 7. El valor que se devuelve es ahora una cadena (est entre comillas)
formada por el dgito 7. Un caso anlogo se da cuando se convierte nmeros reales en cadenas
y viceversa. De nuevo no es lo mismo el nmero real que la cadena formada por los dgitos que
componen dicho nmero.
En los dos ejemplos finales, se ve cmo se pueden convertir nmeros reales en enteros y al revs.
Cuando se convierte un nmero real en entero, se devuelve la parte entera (equivale a truncar) y
cuando se convierte un entero en real, la parte decimal vale 0.
2.2.4. Operadores
Los programas usan los valores que manipulan para hacer clculos y operaciones con ellos. La
forma ms sencilla de hacer operaciones con los datos es empleando los operadores del lenguaje.
Cada uno de los tipos descritos anteriormente permite hacer operaciones diferentes con sus valores.
Antes de estudiar los operadores ms utilizados, es interesante ver unos ejemplos iniciales. En todos
estos ejemplos se usan operadores binarios (tienen dos operandos) y su sintaxis es siempre la misma:
operando operador operando:
>>> 7 + 4
11
>>> 3.1416 * 2
6.2831999999999999
>>> "Juan" + " Alonso"
Juan Alonso
>>> True and False
False

En las instrucciones anteriores se han usado operadores binarios: el operador suma (+) para
sumar dos enteros, el operador producto (*) para multiplicar un real por un entero, de nuevo el
operador + para concatenar dos cadenas, y por ltimo el operador y-lgico (and) para hacer dicha
operacin entre dos valores lgicos.
El primer detalle importante que se debe observar es que todas las operaciones producen un
valor: cuando sumamos 7 y 4 el resultado es el valor entero 11, o cuando concatenamos las cadenas
Juan y Alonso se produce la cadena Juan Alonso. El segundo aspecto fundamental es entender
qu hace cada operador. En los dos ejemplos anteriores el mismo operador + se comporta de manera
diferente si se suman enteros que si se utiliza para concatenar cadenas. Por ello, se deben conocer
los operadores que existen en el lenguaje y las operaciones que hace cada uno de ellos.
Aunque hay ms operadores de los que se van a citar a continuacin, los ms utilizados y con
los que se pueden hacer la gran mayora de los programas estn agrupados en tres grandes grupos:

Aritmticos: + (suma), - (resta), * (producto), / (divisin), % (resto) y ** (potencia). Tam-


bin hay un operador unario (que acta sobre un solo dato, en lugar de dos) que es el - para
cambiar de signo al dato que le siga.

Relacionales: == (igual), != (distinto), < (menor que), <= (menor o igual que), > (mayor que)
y >= (mayor o igual que)

Lgicos: and (y-lgico), or (o-lgico) y not (no-lgico)

Los operadores aritmticos se emplean habitualmente con los tipos numricos y permiten hacer
las operaciones matemticas tpicas. El nico operador que tiene un comportamiento diferente segn
2.2 Variables, expresiones, asignacin 36

los operandos sean int o float es el operador divisin (/): cuando recibe enteros hace una divisin
entera, el cociente ser un valor entero, y con valores reales la divisin es real. Es un buen ejemplo
de que el resultado de una expresin que use un operador depende de los operandos que se empleen,
en este caso basta con que uno de los dos operandos sea un nmero real para que la divisin sea
real.
Para saber ms
Existen dos variantes del lenguaje Python. La que explicamos en esta asignatura se
denomina Python 2, la otra (ms reciente pero an menos extendida) se denomina
Python 3.
En Python 3, el operador / se comporta de forma diferente a como se ha descrito, ya
que siempre realiza la divisin real (flotante), incluso si los operandos son enteros. Para
el caso en que se quiera realizar la divisin entera se tiene el operador // (que tambin
existe en Python 2). Esto suele resultar ms claro para los principiantes.
Si quieres que Python 2 se comporte como Python 3 en lo que respecta a la divisin,
puedes poner al principio de tus programas una lnea que diga:
1 from __future__ import division

Sin entrar a explicar la curiosa sintaxis de esta lnea, basta saber que si la pones, entonces
el operador / realizar siempre la divisin real, al igual que en Python 3.

Algunos operadores aritmticos, en concreto el operador + y el operador *, se pueden utilizar


tambin con cadenas de caracteres3 . Lo que producen son, respectivamente, la concatenacin de dos
cadenas, y la concatenacin de una misma cadena varias veces (luego se ver algn ejemplo de esta
operacin).
Los operadores relacionales sirven para determinar si es cierta o no una relacin de orden entre
dos valores, o si stos son iguales o distintos. Por ejemplo, podemos comprobar si 3 <= 5. Intui-
tivamente es natural pensar que una relacin de orden o igualdad puede ser cierta o no, es decir,
el resultado de esa operacin ser un valor lgico siempre, independientemente de si los valores son
nmeros o cadenas de caracteres. Los valores de tipo str tambin se pueden comparar, el valor que
se produce depende de su ordenacin alfabtica, distinguindose entre maysculas y minsculas.
Por ltimo, se pueden hacer las tpicas operaciones lgicas y, o y no. De nuevo en este
caso el valor que se produce es de tipo bool ya que la operacin podr ser cierta o falsa. Estos
operadores se emplean fundamentalmente al escribir las condiciones de las sentencias condicionales
y los bucles que se estudiarn ms adelante.
La mejor forma de comprender los operadores es jugar con ellos usando el intrprete, introdu-
ciendo valores de distintos tipos y viendo el resultado que producen las expresiones resultantes.
Algunos ejemplos descriptivos podran ser los siguientes:
>>> 2 / 3
0
>>> 2 % 3
2
>>> 2.0 / 3
0.66666666666666663
>>> 2 ** 3
8
>>>> "Pe" * 4
PePePePe
>>> not True
3
Tambin con listas, como se indicar en el apartado dedicado a ellas
2.2 Variables, expresiones, asignacin 37

False
>>> 2 > 3
False
>>> 3 <= 3.1416
True
>>> 2 == 3
False
>>> 2 != 3
True
>>> "Antonio" < "Juan"
True

En el primer ejemplo se hace una divisin entre dos enteros, el resultado es el cociente, en
ese caso 0. Si hacemos el resto ( % ) de esa misma divisin, el valor obtenido es 2. Cuando uno
de los operandos es un nmero real, como pasa en el tercer ejemplo, entonces la divisin es real,
produciendo un cociente que es un valor float. Aunque en otros lenguajes no existe este operador,
en python es posible calcular la potencia de dos nmeros con el operador **. Una operacin ms
extraa es la que se muestra en el quinto ejemplo. Se utiliza el operador * con una cadena de
caracteres y un nmero entero. Lo que hace es producir una cadena en la que se repite la cadena
que acta como primer operando tantas veces como indica el valor entero del segundo operando.
En el ejemplo, la cadena Pe se repite 4 veces, produciendo la cadena PePePePe.
El resto de operaciones son todas con operadores relacionales y lgicos, y por ello todas producen
un valor bool. La primera es la nica que utiliza un operador unario4 , esto es, un operador que
solamente necesita un operando. En el ejemplo se hace la operacin not con el valor True, y produce
el valor lgico contrario, es decir, False. El resto de operaciones manejan operadores relacionales
y producen un resultado cierto o falso en funcin de que la relacin de orden o igualdad se cumpla
o no: 2 no es mayor que 3 (falso), 3 s es menor o igual que 3.1426 (cierto), 2 no es igual que 3
(falso) y 2 s es distinto de 3 (cierto). Tambin el orden puede comprobarse entre cadenas, como
muestra el ltimo ejemplo. Se trata de un orden alfabtico en este caso, la cadena Antonio va
antes, y por tanto es menor que la cadena Juan, si ordenramos ambas cadenas alfabticamente.
Importante
Todas las operaciones que se hacen con operandos siempre producen un resultado. Ese
resultado ser un valor de un cierto tipo. El programador debe conocer siempre el tipo
que producir una expresin sabiendo el tipo de sus operandos y la operacin que realiza
el operador.

2.2.5. Variables
Como se dijo al principio de esta seccin, los programas se escriben para, dados unos datos de
entrada, hacer clculos con ellos, y producir unos resultados de salida. Para que los programas sean
tiles necesitamos un mecanismo que nos permita representar esa informacin que va a cambiar: los
datos de entrada que sern diferentes en cada ejecucin y los datos de salida que tomarn valores
distintos en funcin de los datos de entrada recibidos. No nos sirve en este caso con usar valores;
los valores concretos, como 7 o 3.1416 no cambian. La forma de representar toda esa informacin
que vara es a travs de variables.
Supongamos que necesitamos hacer un programa que sirva para calcular el rea de un rectngulo,
dados los valores de su base y su altura. Sabemos que el clculo del rea de un rectngulo se realiza
mediante la ecuacin:
area = base altura
4
Tambin el operador - puede actuar como operador unario, cambiando el signo del operador numrico que le siga
2.2 Variables, expresiones, asignacin 38

Los usuarios de nuestro programa quieren poder ejecutarlo las veces que deseen, introducir de alguna
forma (generalmente con el teclado) los valores de la base y la altura, y que el programa muestre
el resultado del rea. Por ejemplo, si el usuario quiere calcular el rea de un rectngulo de base 5
y altura 4, introducir esos dos datos y nuestro programa debera responder que el rea es 20. Sin
embargo, dentro de las instrucciones de nuestro programa no debemos escribir la operacin 5*4
porque no sabemos qu valores va a introducir el usuario cuando lo ejecute. Adems, queremos que
nuestro programa calcule el rea de cualquier rectngulo. Si el usuario introdujera 6 y 3, entonces
el rea sera 18.
La forma de generalizar la operacin de calcular el rea dentro del programa es idntica a la
manera en la que se expresa la ecuacin que explica su clculo. En lugar de usar valores concretos,
emplearemos nombres de variables para referirnos a esos valores que cambian. Disearemos nuestro
programa usando al menos dos variables, base y altura, que tomarn distintos valores en las
diferentes ejecuciones, pero la forma de calcular el rea del rectngulo que representan es siempre
la misma:
>>> base * altura

cuando base o altura cambien de valor, tambin cambiar el producto de ambas y con ello el
valor del rea que calcula nuestro programa.
Definicin
Una variable es el nombre que se utiliza en un programa para representar un dato o
valor que puede cambiar.

Veamos el funcionamiento de las variables con un ejemplo prctico. En primer lugar, damos un
valor a nuestras dos variables base y altura, en concreto los valores 5 y 4 respectivamente:
>>> base = 5
>>> altura = 4

Hemos usado dos asignaciones. En el siguiente apartado explicaremos con detalle cmo funciona
una asignacin. Intuitivamente, lo que hace la asignacin es cambiar el valor de una variable. Es
decir, ahora en nuestro ejemplo cuando usemos el nombre base, su valor ser 5 y cuando usemos
altura 4. Las variables vienen a ser una forma de referirnos a un valor que est en la memoria
usando un nombre. En memoria tenemos los valores 5 y 4, el 5 es el valor de la base del rectngulo
y el 4 su altura:

base 5 Memoria

altura 4

Cuando queremos utilizar estos datos para hacer alguna operacin simplemente tenemos que
poner su nombre. As para calcular el rea escribiremos:
>>> base * altura
20

El resultado es naturalmente 20 en funcin del los valores que en ese momento tienen la base y
la altura. Sin embargo, a lo mejor el usuario del programa quiere calcular el rea de otro rectngulo
distinto, por ejemplo uno que tenga base 5 y altura 2. Cambiaramos el valor de la altura, pero
la operacin para calcular el rea sera exactamente la misma, produciendo el resultado deseado:
2.2 Variables, expresiones, asignacin 39

>>> altura = 2
>>> base * altura
10

El dato altura ha cambiado y con l el resultado del rea. En memoria, la variable altura
representa el valor 2 en lugar del valor 4. Ahora nuestro programa est usando los valores 5 y 2, el
4 ya ha dejado de usarse (por eso aparece en gris en la figura siguiente).

base 5 Memoria

altura 4

Cada vez que se utiliza un valor nuevo en un programa en python, se reserva un nuevo espacio
en la memoria para guardarlo. El valor de nuestro dato altura ha cambiado, est en otro sitio en
la memoria, pero la forma de referirnos a l es la misma, usando el nombre de la variable.
Importante
Una variable es un nombre con el que representamos un valor, y por tanto, ser de un
tipo. Ese valor adems se guardar en una posicin de la memoria.

La variable base representa el valor 5, es de tipo int y dicho valor est en una posicin de
la memoria concreta. Con el nombre de la variable podremos acceder al valor tantas veces como
queramos y la variable podr cambiar de valor tantas veces como se desee. Para conocer el tipo del
valor que representa la variable, algo que habitualmente no es necesario, se puede utilizar la funcin
type exactamente como se haca con los valores anteriormente.
Para saber ms
La posicin de la memoria donde se encuentra el valor que representa una variable
es intrascendente para la ejecucin del programa; en ejecuciones distintas, el valor se
situar en posiciones de la memoria diferentes. Si se quiere conocer la posicin del valor
que representa una variable se debe usar la funcin id, indicando entre parntesis el
nombre de la variable, p.e., id(base).

2.2.6. Asignacin
Una de las instrucciones ms importantes para la construccin de programas es la asignacin.
La asignacin es la instruccin que nos permite cambiar el valor de una variable. La sintaxis es
sencilla, primero se indica el nombre de la variable, despus el operador = y por ltimo la expresin
del valor que se desea asignar:

variable = expresion
El efecto que tiene una asignacin es diferente en funcin de cmo sea la expresin que aparece
en la parte derecha de la asignacin. Hay dos opciones:

1. si se asigna un valor (o en general, el resultado de una operacin), entonces se reserva un


nuevo espacio en la memoria para contenerlo
2.2 Variables, expresiones, asignacin 40

2. si se asigna otra variable, entonces las dos variables se referirn al mismo valor

Es decir, a efectos de la memoria que ocupan los datos del programa hay diferencias entre ambas
situaciones. Vamos a verlo con un par de ejemplos, utilizando de nuevo el problema del clculo del
rea de un rectngulo, nuestras dos variables base y altura y una nueva variable area con la
que guardaremos mediante asignaciones el valor del rea del rectngulo que vayamos calculando.
Analicemos en primer lugar las siguiente asignaciones:
>>> base = 5
>>> altura = base
>>> area = base * altura
>>> area
25

En la primera de ellas se asigna a la variable base el valor 5. Como se est asignando un nuevo
valor, en memoria se reserva el espacio para contener el valor 5, valor al que nos referiremos usando
la variable base. A continuacin se asigna a la variable altura la variable base. Ahora estamos
en el segundo caso antes descrito, se est asignando una variable. Por tanto, no se reserva un nuevo
espacio en memoria, sino que las dos variables se refieren al mismo valor, 5. Por ltimo, a la variable
area se le asigna el resultado de calcular el rea del rectngulo, base * altura. Como es una
operacin, produce un nuevo valor, 25, y estamos de nuevo en el primer caso. Por ello se crea una
nueva posicin de memoria para contener el valor 25. Grficamente la situacin de la memoria tras
estas asignaciones sera la siguiente:

Memoria
base 5

altura

area 25

Supongamos que ahora se hicieran las asignaciones siguientes:


>>> altura = 4
>>> area = base * altura
>>> area
20

En el primer caso, a la variable altura se le asigna el valor 4. Como es un nuevo valor, se crea
el espacio de memoria para contenerlo y la variable altura ser el nombre con el que podamos
acceder a ese dato. A continuacin, se recalcula el rea del nuevo rectngulo. que en este caso
produce el valor 20. Como se asigna un nuevo valor, ste se guarda en una nueva posicin de la
memoria, a la que se podra acceder usando la variable area. En esta ocasin el valor 25 ha dejado
de ser usado, por lo que aparece en gris en la imagen. Los valores que en ese momento tendra
nuestro programa guardados en la memoria seran 5, 4 y 20.
2.2.7. Otras consideraciones sobre las variables
Hay dos aspectos importantes a la hora de trabajar con las variables que tendrn nuestro pro-
gramas que a los programadores principiantes les cuesta decidir. La primera es elegir un nombre
adecuado para cada variable del programa y la segunda seleccionar qu variables necesitamos usar.
El nombre de una variable puede estar formado por letras (a, b, c,. . . ), dgitos (0,1,2,. . . ) y el
carcter guin bajo o subrayado (_). Adems deben tenerse en cuenta las siguientes restricciones:
2.2 Variables, expresiones, asignacin 41

Memoria
base 5

altura 4

area 25

20

el nombre no puede empezar por un dgito

el nombre no puede ser igual que una palabra reservada del lenguaje

las letras maysculas y minsculas son diferentes

Es decir, no podemos usar como nombre de una variable 9numeros ya que empieza por un
dgito. Los nombres Numero y numero son diferentes, ya que no es lo mismo la letra N que la n.
Y nunca se pueden usar las palabras de las que se compone el lenguaje python y que detallan en
el recuadro anexo. Todas estas reglas son bastante similares en cualquier lenguaje de programacin
actual.
Curiosidad: Palabras reservadas
Las palabras reservadas de python son 31. No es necesario memorizarlas, se van apren-
diendo a medida que se usan al programar y algunas de ellas no se usarn nunca en los
programas de la asignatura.

and as assert break class


continue def del elif else
except exec finally for from
global if import in is
lambda not or pass print
raise return try while with
yield

Pero sin duda el aspecto ms importante a la hora de elegir el nombre de una variable es que
el nombre sea descriptivo del dato que la variable representa dentro del programa. De esa forma,
al leer el programa, tanto por nosotros mismos como autores, como por otros programadores que
pudieran leerlo, se entender mejor la utilidad que tiene la variable dentro del programa. Siempre
hay que utilizar nombres lo ms descriptivos posibles, aunque sean largos y formados por varias
palabras. El convenio que seguiremos en la asignatura es utilizar palabras en minsculas separadas
por guiones bajos. Por ejemplo: nombre, velocidad_final, interes, codigo_postal
El otro aspecto a tener en cuenta sobre las variables, es cundo hay que usar una variable en
un programa? La idea fundamental que se debe tener presente es la siguiente:
Importante
Las variables son las herramientas que usan los programas para almacenar informacin
en la memoria del ordenador.
2.2 Variables, expresiones, asignacin 42

Desde esa perspectiva, siempre que en un programa se desee guardar alguna informacin para
luego acceder a ella, entonces es necesario crear una variable. Eso hace que no solamente creemos
variables para los datos de entrada y salida del programa, sino tambin para todos aquellos valores
intermedios que el programa calcule y de los que queramos mantener el resultado en memoria para
acceder a ellos posteriormente. Las variables permiten a los programadores reservar espacio en la
memoria para manipular datos. La ventaja de guardar datos calculados previamente es aumentar la
velocidad de los programas al no tener que recalcularlos. Otras veces, se guardan datos en memoria
desde otros dispositivos como los discos. Por ejemplo, imagina un programa de tratamiento de
imgenes que cargue en memoria una imagen desde un archivo. Si la imagen se mantiene en memoria,
el programa podr tratarla de forma rpida ya que no necesitar leer su informacin de disco. Los
datos que estn en memoria siempre se pueden tratar de una forma ms rpida que si necesitamos
acceder a la misma informacin en un dispositivo secundario.
2.2.8. Expresiones
El objetivo de esta seccin es explicar cmo se ejecutan las operaciones que escribimos en los
programas y en las que aparecen valores, variables y operadores, especialmente cuando aparecen
varios operadores juntos. Es lo que se denomina una expresin.
Definicin
Una expresin es una combinacin de operadores y operandos (valores, variables) que
produce un resultado (valor) de un cierto tipo.

Varias cosas en esta definicin. Primero, las expresiones se forman al mezclar los operadores con
sus operandos. Los operadores son los que definen las operaciones que se van a hacer. En segundo
lugar, las expresiones producen siempre un valor. Ese valor ser, como es lgico, de algn tipo.
Tanto el valor producido, como su tipo, dependern de los operandos y de los operadores que se
usen.
La mayor dificultad que entraan las expresiones con varios operadores es saber el orden en
que stos se ejecutarn. Eso lo determina lo que se denomina la precedencia de los operadores. La
precedencia es la propiedad que sirve para decidir qu operador debe aplicarse primero cuando en
una expresin aparecen varios operadores de distintos grupos. Vamos a verlo con dos ejemplos, las
expresiones 4+5*7 y (4+5)*7. En ambas aparecen dos operadores, la suma (+) y el producto (*),
con los mismos valores, sin embargo el resultado ser diferente por la presencia de los parntesis.
En el caso de la expresin 4+5*7, la primera operacin que se hace es el producto ya que el
operador * tiene ms precedencia que el operador +. La expresin 5*7 produce el valor 35, al que
posteriormente se le suma el valor 4. El resultado final de la expresin es 39. Grficamente:

4 + 5 * 7

4 + 35

39

En cambio en la expresin (4+5)*7, tenemos los mismos valores y operadores, pero adems
se han incluido unos parntesis que delimitan la operacin de suma. Los parntesis sirven para
agrupar las operaciones que se quieren hacer primero. En este caso, lo que se indica es que se debe
2.3 Uso de entrada/salida por consola 43

hacer antes la suma que el producto. Primero se realiza 4+5, produciendo el valor entero 9, y a
continuacin se hace el producto de dicho valor por 7, con lo que el resultado final de la expresin
es 63:

(4 + 5) * 7

9 * 7

63

Puedes consultar la tabla de precedencia de operadores en python en mltiples pginas web,


por ejemplo en http://docs.python.org/reference/expressions.html. Sin embargo
memorizarse la tabla es difcil, y en realidad tampoco es necesario. Como se ha visto en los dos
ejemplos anteriores, usando los parntesis adecuadamente se pueden cambiar el orden en que se eje-
cutan los operadores de una expresin. Adems, el uso de los parntesis hace que algunas expresiones
se entiendan mejor al leerlas.
En todo caso, las tablas de precedencia de todos los lenguajes suelen seguir una serie de reglas
que si se conocen pueden permitirnos escribir expresiones complejas sin abusar tanto del uso de los
parntesis. Citaremos las cuatro reglas ms bsicas:

1. lo que est entre parntesis se hace primero


2. los operadores aritmticos tienen ms precedencia que los relacionales, y los relacionales ms
que los lgicos
3. los operadores unarios de un grupo ms que los binarios de ese mismo grupo
4. ** ms que los multiplicativos (*, /, %), y stos ms que los aditivos (+, -). Esta regla
tambin se da con los lgicos (and ms precedencia que or)

La primera regla es la ms importante de todas, ya la hemos comentado suficientemente. En el


caso de la segunda, se comprende si se piensa en una expresin como x-1<=10. Lo lgico al leer
esa expresin en matemticas es que queremos comprobar si al restarle 1 a x el valor resultante es
menor o igual que 10. La expresin puede escribirse tal cual, ya que el operador aritmtico (-) tiene
ms precedencia que el relacional (<=). La tercera regla se puede entender al analizar una expresin
como a*-b. En ese caso lo que se quiere es que se multiplique la variable a por el valor resultante
de cambiar el signo de la variable b, esto es, -b. Como el operador - es en este caso unario, se hace
antes que el operador *. La nica excepcin a la regla tercera se da en el caso de el operador binario
** que tiene ms precedencia que los operadores unarios aritmticos, como el -, lo que explica que
-1**2 de como resultado -1, mientras que (-1)**2 da como resultado 1. Para finalizar, la ltima
regla se ha visto en los dos ejemplos utilizados para explicar el concepto de precedencia y el uso de
parntesis, las multiplicaciones se hacen antes que las sumas.

2.3. Uso de entrada/salida por consola


Una caracterstica muy importante de los programas es que sean capaces de interaccionar con
el usuario, es decir, que sean capaces de pedir informacin al usario por teclado (entrada estndar)
y de mostrar los resultados por pantalla (salida estndar).
El siguiente programa en Pyhton calcula el rea de un tringulo, pero la base y la altura siempre
son las mismas y no se informa del rea calculada.
2.3 Uso de entrada/salida por consola 44

1 base=5.0
2 altura=3.0
3 area=(base*altura)/2

Evidentemente, sera mucho ms til si se pudiera aplicar a cualquier tringulo y, por supues-
to, si se informa al usuario del resultado final. Para ello es necesario conocer las operaciones de
entrada/salida por consola que nos ofrece Python. Mediante su aplicacin, el programa anterior
quedara de la forma siguiente:
1 base = float (raw_input("Dame la base:"))
2 altura = float (raw_input("Dame la altura:"))
3 area =(base*altura)/2
4
5 print area

2.3.1. Entrada por teclado


La forma ms sencilla de obtener informacin por parte del usuario es mediante la funcin
raw_input. Esta funcin devuelve una cadena con los caracteres introducidos por el usuario me-
diante el teclado.
Atencin
Cuando se llama a esta funcin, el programa se para y espera hasta que el usuario teclea
algo. Cuando el usuario presiona Return o Enter, el programa contina y raw_imput
retorna lo que ha tecleado el usuario como cadena de caraceteres (string).

>>> entrada = raw_input()


_

>>> entrada = raw_input()


Hola
>>> print entrada
Hola

Antes de pedir un dato por teclado al usuario, es una buena idea sacar un mensaje informando de
lo que se espera. Por este motivo, raw_input puede llevar como parmetro una cedena de caracteres
que se saca por la pantalla justo antes de pedir la entrada al usuario (indicador o prompt en ingls).
>>> entrada = raw_input("Introduce tu nombre: ")
Introduce tu nombre:

>>> entrada = raw_input("Introduce tu nombre: ")


Introduce tu nombre: Jorge Javier
>>> print entrada
Jorge Javier

Si necesitamos un nmero como entrada, un entero o un flotante, en lugar de una cadena,


podemos utilizar las funciones int y float para convertir la cadena al tipo numrico correspondente.
>>> base = float (raw_input("Introduce la base de un tringulo:\n"))
Introduce la base de un tringulo:
7

Aunque hay que tener en cuenta que si lo que introduce el usuario no es un nmero vlido se
genera un error al no poder realizar la conversin.
2.3 Uso de entrada/salida por consola 45

>>> base = float (raw_input("Introduce la base de un tringulo:\n"))


Introduce la base de un tringulo:
A
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for float(): A

Como se comentar mas adelante, el carcter especial \n al final del mensaje del raw_imput
(prompt) causa un salto de lnea.
2.3.2. Salida por pantalla
La forma ms sencilla de mostrar algo en la salida estndar es mediante el uso de la sentencia
print, como hemos visto en varios ejemplos anteriores. En su forma ms bsica a la palabra clave
print le sigue una cadena de caracteres, que se mostrar en la pantalla del ordenador al ajecutarse
la sentencia. Si se omite la cadena de caracteres se produce un salto de lnea.
>>> print

>>> print "Hola mundo"


Hola mundo

Atencin
Las comillas que se usan para identificar una cadena de caracteres no aparecen en la
salida por pantalla.

Por defecto, la sentencia print muestra algo por la pantalla y se posiciona en la lnea siguiente.
Si queremos mostrar ms de un resultado en la misma lnea, basta con separar con comas todos los
valores que deseamos mostrar. Esto es debido a que Python interpreta la coma como un espacio
de separacin.
>>> print "Hola mundo", "de la programacin"
Hola mundo de la programacin

Tambin se puede usar print para imprimir por pantalla valores que no sean cadenas de
caracteres, como nmeros enteros o flotantes.
>>>print "Te costar entre", 30, "y", 49.5, "euros"
Te costar entre 30 y 49.5 euros

Las cadenas de caracteres que muestra la sentencia print pueden contener caracteres especiales.
Se trata de caracteres que van precedidos por la barra invertida \ y que tienen un significado
especfico. Los ms utilizados son \n, el carcter de nueva lnea, y \t, el de tabulacin. Por ejemplo,
la siguiente sentencia imprime la palabra "Hola" seguida de un rengln vaco y en la lnea siguiente
(debido a los dos caracteres de nueva lnea, \n) la palabra "mundo" indentada (debido al carcter
tabulador, \t).
>>>print "Hola\n\n\tmundo"
Hola

mundo

2.3.3. Salida con formato


La sentencia print, o ms bien las cadenas que imprime, permiten tambin utilizar tcnicas
avanzadas de formateo de la salida. Veamos un ejemplo bastante simple:
2.3 Uso de entrada/salida por consola 46

>>>print "Tengo %d aos" % 25


Tengo 25 aos

Lo nuevo de este ejemplo es la utilizacin una secuencia de formato: %d. Las secuencias de
formato ms sencillas estn formadas por el smbolo %, llamado operador de formato, seguido de
una letra que indica el tipo con el que formatear el valor proporcionado a continuacin:

Secuencia Formato
%s Cadena
%d Entero
%f Flotante

Volvamos al ejemplo anterior. Lo que hace es construir la cadena introduciendo los valores a la
derecha del smbolo % (el valor entero 25) en las posiciones indicadas por la secuencia de formato
( %d).

Podemos formatear una cadena de carateres utilizando varias secuencias de formato. En este
caso, los valores asociados a cada una de las secuencias deben ir entre parntesis separados por
comas. El nmero de secuencias de formato y el nmero de valores asociados debe coincidir para
que no se produzca un error. Igualmente, los tipos de los valores (o expresiones) deben coincidir con
lo que esperan las secuencias de formato. Veamos un ejemplo un poco ms complicado:
>>>print "Tengo %d aos, mido %f m. y soy de %s" % (25, 1.95, "Gijn")
Tengo 25 aos, mido 1.950000 m. y soy de Gijn

Cada una de las secuencias de formato se sutituye por los valores que aparecen entre parntesis,
tomados de izquierda a derecha:

En el ejemplo anterior se muestra la altura (1.95) con una serie de ceros de ms (1.950000). Esto
es debido a que por defecto, el formato para los nmeros de coma flotante imprime seis decimales.
Sin embargo, para tener ms control sobre el formato de salida, podemos introducir un nmero
entre el % y el carcter que indica el tipo al que formatear.
Para cadenas y enteros, indica el nmero mnimo de caracteres que queremos que ocupe la
cadena generada. Si se precisan menos caracteres de los indicados, se aaden espacios en blanco por
la izquierda. En el caso de que el nmero sea negativo, ocurrir exactamente lo mismo, slo que los
espacios se aadirn a la derecha de la cadena.
>>>print " %10s mundo" % "Hola"
Hola mundo -->Se aaden 6 espacios a la izquierda
>>>print " %-10s mundo" % "Hola"
Hola mundo -->Se aaden 6 espacios a la derecha
>>>print "Tengo %5d aos" % 25
Tengo 25 aos -->Se aaden 3 espacios a la izquierda
2.4 Manejo de estructuras bsicas de control de flujo 47

Para formatear nmeros flotantes, podemos introducir dos nmeros a continuacin del % sepa-
rados por un .: el primero hace referencia a la longitud total y el segundo a la longitud de la parte
decimal (se puede indicar slo la longitud de la parte decimal). A continuacin se presentan varios
ejemplos para distintos tipos de datos:
>>>print "Mido %.2f m." % 1.95
Mido 1.95 m. -->2 cifras decimales
>>>print "Mido %.3f m." % 1.95
Mido 1.950 m. -->3 cifras decimales (se rellena con 0)
>>>print "Mido %.1f m." % 1.95
Mido 2.0 m. --> 1 cifra decimal (se redondea)
>>>print "Mi coche pesa %10.2f Kg." % 1324.728
Mi coche pesa 1324.73 -->10 caracateres en total, 2 la parte decimal
-->(se aaden 3 espacios y se redondea)

Importante
Los caracteres especiales y las secuencias de formato no slo se pueden utilizar con la
sentencia print, se pueden usar con cualquier variable de tipo cadena.
1 salida = "\nEl area un triangulo de base %d y altura %d es %.2f \n" \
2 % (5, 3, (base*altura)/2)
3 print salida

La salida del programa anterior es:

El area un triangulo de base 5 y altura 3 es 7.50

Ahora ya estamos en disposicin de entender, incluso de mejorar, el programa que calcula el


rea de un tringulo con el que empezamos esta seccin:
1 base = float (raw_input("Dame la base:"))
2 altura = float (raw_input("Dame la altura:"))
3 area =(base*altura)/2
4 salida = "\nEl area un triangulo de base %.1f y altura %.1f es %.2f \n" \
5 % (base, altura, area)
6 print salida

2.4. Manejo de estructuras bsicas de control de flujo


Existen 3 estructuras de control fundamentales:

Secuencial (BLOQUE)

Aternativa simple (SI-ENTONCES) o doble (SI-ENTONCES-SI_NO)

Repetitiva (Existen 2 tipos: MIENTRAS y REPETIR-HASTA)

Estas estructuras se representan grficamente en la figura 2.1. Obsrvese que todas ellas tienen
un nico punto de entrada y un nico punto de salida marcado con el rectngulo en lnea de trazos,
lo que permitir ms adelante componer unas con otras, enlazndolas por dichos puntos de entrada
y salida.
Bhm y Jacopini demostraron en los aos 60 que todo programa puede realizarse a base de las 3
estructuras anteriores: La secuencial, la alternativa, y una cualquiera de las 2 repetitivas, as como
de anidamientos de unas estructuras en otras.
Existen 3 estructuras de control fundamentales:
o Secuencial
2.4 Manejo de estructuras bsicas (BLOQUE
de control de) flujo 48
o Aternativa (SI-ENTONCES-SI_NO)
o Repetitiva (Existen 2 tipos: MIENTRAS y REPETIR-HASTA)

sent.1
V F
cond. F
cond.
sent. 2 sent.
V

sent.1 sent. 2 sent. F


cond.
sent. n
V

BLOQUE SI-ENTONCES-SI_NO MIENTRAS REPETIR-HASTA

Tema 4. Introduccin a la programacin 4-4

Figura 2.1: Estructuras de control fundamentales

2.4.1. Estructura secuencial (BLOQUE)


Consiste en ejecutar una sentencia a continuacin de otra.
Se pueden agrupar varias sentencias para formar una nica sentencia, denominada sentencia
compuesta. En otros lenguajes se usan delimitadores de bloque (p.ej: llaves).
Implementacin En Python, lo que delimita el bloque es que todas tengan el mismo nivel de
indentacin, es decir, el mismo nmero de espacios por la izquierda. Aunque el nmero de espacios
puede ser cualquiera que se desee, ha de ser el mismo para todas las sentencias que componen el
bloque secuencial. Es costumbre que este nmero de espacios sea mltiplo de 4.
Por ejemplo, en la figura 2.2 se muestra la implementacin en lenguaje Python del bloque
correspondiente, asumendo que sent1, sent2, etc. son diferentes sentencias Python, (asignaciones,
expresiones, etc).

sent.1
1 sent1
sent. 2 2 sent2
3 ...
4 sentN

sent. n

Figura 2.2: Bloque secuencial

Hay que tener en cuenta que el bloque principal en python ha de tener cero espacios de inden-
tacin, y que slo los bloques que aparezcan dentro de otras estructuras de control irn indentados.
En los ejemplos que hemos visto hasta este momento, todos los programas tienen un solo bloque, que
es el principal y por tanto todos llevan cero espacios de indentacin. En las secciones siguientes
en las que usaremos bloques dentro de otras estructuras de control podremos ver ejemplos en los
que la indentacin juega su papel fundamental.
Se puede usar punto y coma para separar sentencias si estn en la misma lnea, pero en
esta asignatura no usaremos esa caracerstica y pondremos siempre cada sentencia en una lnea
separada. Hacindolo as, no es necesario poner un punto y coma para separarlas, y en particular
no es necesario poner punto y coma al final de cada lnea (decimos esto porque en otros lenguajes
como el C o Java s es obligatorio terminar cada lnea con punto y coma).
2.4.2. Estructura alternativa
Permite elegir entre dos alternativas, segn sea verdadera o falsa, la condicin que se evala.
2.4 Manejo de estructuras bsicas de control de flujo 49

Existen dos subtipos


Aternativa simple (if)

Aternativa doble (if-else)


En la estructura alternativa simple se proporciona una condicin y una sentencia (o un
bloque de ellas). Si la condicin es verdadera se ejecuta la sentencia. Si no, no se ejecuta
ninguna accin.

V F Pseudocdigo:
cond
SI condicin
ENTONCES sentencia
sent
Implementacin en python:
1 if cond:
2 sent

Figura 2.3: Estructura alternativa simple (if)

Esta estructura de control se puede representar grficamente como se muestra en la figura 2.3.
En esta misma figura se muestra cmo leer el grfico, en forma de pseudocdigo, y la implementacin
en el lenguaje python.
Sobre la implementacin, observar los siguientes detalles:
La condicin (que se representa por cond en la figura) ser una expresin booleana cuyo resul-
tado ser True o False. La condicin no necesita ir encerrada entre parntesis (a diferencia
de otros lenguajes como C o Java).

Tras la condicin, se ponen dos puntos (:), finalizando as la lnea.

La sentencia a ejecutar (representada por sent en la figura) debe ir indentada, habitualmente


cuatro espacios como ya hemos dicho antes. Si se trata de un bloque en lugar de una sola
sentencia, todo el bloque ir indentado la misma cantidad de espacios.

Aunque el pseudocdigo dice SI . . . ENTONCES, lo cierto es que en la implementacin


python se escribe solo if, pero no se escribe then. El papel del then lo hacen los dos puntos.
Ejemplo Suponiendo que la variable nota contiene la calificacin de un alumno, el siguiente frag-
mento de programa determina si ha superado la prueba.
1 # El programa obtiene la nota por algn medio
2 if nota >= 5.0:
3 print "Prueba superada"

En la estructura alternativa doble (if-else) se proporcionan dos posibles sentencias, a


elegir una segn el resultado de la condicin, como se muestra en la figura 2.4. Si la condicin es
verdadera se ejecuta la sentencia1. Si no, se ejecuta la sentencia2.
Sobre la implementacin, observar los siguientes detalles:
La condicin sigue las mismas observaciones que para el caso anterior.
2.4 Manejo de estructuras bsicas de control de flujo 50

Pseudocdigo:
V F SI condicin
cond
ENTONCES sentencia1
SI_NO sentencia2

sent1 sent2 Implementacin en python:


1 if cond:
2 sent1
3 else:
4 sent2

Figura 2.4: Estructura alternativa doble (if-else)

La sentencia a ejecutar para el caso True (representada por sent1 en la figura) debe ir
indentada, habitualmente cuatro espacios como ya hemos dicho antes. Si se trata de un bloque
en lugar de una sola sentencia, todo el bloque ir indentado la misma cantidad de espacios.
Lo mismo cabe decir sobre la sentencia (o bloque) para el caso False, representada por
sent2 en la figura.

La palabra else ha de finalizarse con dos puntos y ha de tener el mismo nivel de indentacin
que la palabra if, de este modo se ve a qu if corresponde el else.

Ejemplo El siguiente fragmento de programa determina si la variable num de tipo entero contiene
un nmero par o impar.
1 # El programa inicializa num por algn medio
2 if num %2 == 0:
3 print "Es par"
4 else:
5 print "Es impar"

Las estructuras alternativas pueden anidarse, esto es, donde debera ir sent1 o sent2 en
el diagrama anterior, podemos poner otra estructura alternativa. La figura 2.5 muestra un ejemplo
de esto. El anidamiento puede complicarse ms, si en lugar de s1, s2, s3 o s4 en dicha figura,
inclumos otra estructura alternativa. El lenguaje no pone lmite al nivel de anidamiento, que puede
ser tan profundo como se quiera. En la prctica, sin embargo, utilizar ms de dos niveles resulta
difcil de leer, y suele ser un sntoma de que se poda haber diseado el algoritmo de otra forma, o
de que parte de l puede ser extrado a una funcin (concepto que veremos ms adelante).
Como se ve en la figura, la implementacin en python hace visible el anidamiento de estas
estructuras mediante el nivel de indentacin de las lneas. Las lneas que usan el mismo nivel de
indentacin, estn al mismo nivel de anidamiento. Es importante que cada else vaya anidado con
su if.
Finalmente, python proporciona una estructura multialternativa (if-elif-else), que per-
mite elegir entre varias alternativas segn el resultado de diferentes expresiones booleanas. En reali-
dad, puede implementarse mediante una serie de if-else anidados en cascada, pero la sintaxis
con if-elif-else resulta ms legible, al reducir el anidamiento.
La idea general se leera como si se cumple cond1 haz sent1, si no, si se cumple cond2 haz
sent2, si no, si se cumple cond3 haz sent3, etc.. y si no se cumple ninguna, haz sentencia,
y la implementacin en Python sera la siguiente:
1 if cond1:
2.4 Manejo de estructuras bsicas de control de flujo 51

F
V
c1 Implementacin en python:
1 if c1:
2 if c2:
3 s1
V F V F
c2 c3 4 else:
5 s2
6 else:
s1 s2 s3 s4 7 if c3:
8 s3
9 else:
10 s4

Figura 2.5: Estructuras alternativas anidadas

2 sent1
3 elif cond2:
4 sent2
5 elif cond3:
6 sent3
7 ...
8 elif condN:
9 sentN
10 else:
11 sentencia #cualquier otro caso no contemplado

Observaciones sobre la implementacin:

La palabra elif es una contraccin de else if.

Cada uno de los elif ha de ir forzosamente alineado con el if inicial, as como el else final.

Se pueden poner tantos elif como se necesiten.

El else final es opcional. Si no se pone, y ninguna de las condiciones se ha cumplido, entonces


no se ejecutar ninguna sentencia.

Como siempre, cualquiera de las sent del cdigo anterior puede ser un bloque de sentencias.
Basta escribir cada una en una lnea y todas con el mismo nivel de indentacin.

Ejemplo El siguiente ejemplo pide al usuario una nota numrica y escribe la correspondiente nota
con letra. Otro uso tpico de la estructura multialternativa es para crear mens en los que el
usuario puede elegir una opcin entre varias que se le presentan.
1 nota = int(raw_input("Introduzca la nota del examen: "))
2 if (nota >= 0) and (nota < 5):
3 print "Suspenso"
4 elif (nota >= 5) and (nota < 7):
5 print "Aprobado"
6 elif (nota >= 7) and (nota < 9):
7 print "Notable"
8 elif (nota >= 9) and (nota <= 10):
9 print "Sobresaliente"
10 else:
11 print "Nota no vlida"
2.4 Manejo de estructuras bsicas de control de flujo 52

2.4.3. Estructuras repetitivas (bucles)


Una estructura repetitiva es un bloque de sentencias (denominado cuerpo del bucle) que se va
a ejecutar varias veces. El bucle incluye una condicin, que regula si se seguir repitiendo o no.
Las instrucciones dentro del bloque generalmente modifican o pueden modificar las condiciones que
forman parte de la condicin, haciendo que en algn momento la evaliuacin de esa condicin cambie
y por tanto el bucle ya no se repita ms.
Dependiendo de si la condicin se evala antes de entrar al bloque, o despus de haber ejecutado
el bloque, podemos clasificar los bucles en dos tipos:

Bucle con condicin inicial.

Bucle con condicin final.

Observar que en el bucle con condicin inicial, si la condicin es falsa de partida, el cuerpo del
bucle no se ejecutar ni siquiera una vez. En cambio en los bucles con condicin final, el cuerpo se
ejecutar al menos una vez, antes de evaluar la condicin que regula si se ejcutar ms veces.
El bucle con condicin inicial generalmente se denomina MIENTRAS. . . HACER (o en
ingls bucle while), se puede representar grficamente como se muestra en la figura 2.6. La
condicin es lo primero que se evala y si el resultado es False, se abandona el bucle sin ejecutar
su sentencia sent. Si la condicin es True, entonces se ejecuta sent y tras ello se vuelve otra vez
a la condicin, para evaluarla de nuevo. Mientras la condicin siga siendo cierta, la sentencia sent
se ejecutar una y otra vez. Se entiende que sent modifica alguna variable, de modo que cond
pueda pasar a ser falsa, y de este modo se terminara el bucle.

Pseudocdigo:
F
cond
MIENTRAS condicin
V sentencia
sent
Implementacin en python:
1 while cond:
2 sent

Figura 2.6: Estructura repetitiva MIENTRAS (while)

Si hubiera ms de una sentencia dentro del bucle, se deber formar una nica sentencia
compuesta usando el mismo nivel de indentacin, como se ve en el siguiente ejemplo.
Ejemplo El siguiente bucle acumula (calcula) la suma de todos los nmeros introducidos por
teclado. Finaliza al meter el cero.
1 suma = 0
2 num = int(raw_input("Introduzca un numero (cero para acabar): "))
3 while num != 0:
4 suma = suma + num
5 num = int(raw_input("Siguiente numero: "))
6 print "La suma vale ", suma

Observar que el bucle while resulta muy adecuado en este caso, ya que no sabemos de antemano
cuntos nmeros va a introducir el usuario antes del primer cero. Puede que el cero sea el primer
2.4 Manejo de estructuras bsicas de control de flujo 53

nmero que introduzca, en cuyo caso no hay que calcular nada (el bucle no se ejecutara). Si el
primer nmero es distinto de cero, se aadir su valor a lo que haba en suma y se le pide otro.
Despus se vuelve a la condicin del while para evaluar de nuevo si este segundo nmero es cero
(saldra del bucle), o distinto de cero (lo aadira a suma y pedira otro), etctera. Cuando el
usuario introduzca finalmente un cero, la variable suma contendr la suma de todos los nmeros
introducidos hasta ese momento.
El bucle con condicin final puede ser de dos tipos:

El bucle ha de repetirse mientras que una condicin sea verdadera, y abandonarse cuando la
condicin sea falsa. Este tipo de bucle es similar al recin visto while, pero con la condicin
al final. Podramos llamarlo HACER. . . MIENTRAS QUE (do-while).

Lo contrario del anterior, es decir, el bucle debe repetirse mientras que una cierta condicin
sea falsa, y dejar de repetirse cuando esa condicin pase a ser verdadera. Podramos denominar
a este bucle REPETIR. . . HASTA QUE (repeat-until).

Algunos lenguajes como el C y Java, tienen palabras reservadas para el primer tipo de bucle
(do-while), pero no para el segundo (repeat-until). Otros lenguajes como PASCAL tienen
para el segundo tipo, pero no para el primero.
En el caso del Python no hay instrucciones especiales para implementar ninguno de estos dos
tipos de bucle. Tan slo tiene para el bucle while visto anteriormente en el que la condicin se
evala al principio. Sin embargo, veremos en la pgina ?? algunos trucos para implementar en
python las estructuras de control do-while y repeat-until.
Al margen de que python tenga o no estas estructuras, desde el punto de vista de la algortmica
existen por derecho propio, por lo que en las figuras 2.7 y 2.8 se muestran sus diagramas de flujo y
su pseudocdigo. Observar que el diagrama de flujo es casi idntico, slo que las salidas T y F de la
condicin estn intercambiadas.

Pseudocdigo:
sent HACER
sentencias
MIENTRAS condicin
V
cond
Implementacin:
F
1 # A diferencia del C, python no tiene el bucle do/while

Figura 2.7: Estructura repetitiva HACER-MIENTRAS (do-while)


2.4 Manejo de estructuras bsicas de control de flujo 54

Pseudocdigo:
sent REPETIR
sentencias
HASTA QUE condicion
F
cond
Implementacin en python:
V
1 # Python no tiene (tampoco) el bucle repeat/until

Figura 2.8: Estructura repetitiva REPETIR-HASTA QUE (repeat-until)

Implementacin en python de las estructuras HACER-MIENTRAS y REPETIR-HASTA


Como se ha dicho antes, Python no proporciona niguna construccin especial para este
tipo de bucles cuya condicin se evala al final. Tan slo provee el bucle while visto en
la pgina 52 que evala la condicin al principio. Entonces cmo implementar un bucle
con condicin al final?
Un caso tpico en que se necesita este tipo de bucles es en los programas en los que se
tiene una interaccin con el usuario y, una vez finalizada sta, se le pregunta si quiere
repetir. Por ejemplo, un juego que una vez terminado le pide al usuario si quiere jugar
otra vez o no. Si el usuario responde S, todo lo anterior deber repetirse. Es un caso
tpico de bucle con condicin al final.
El caso concreto de bucle (si es HACER-MIENTRAS o REPETIR-HASTA) no importa
mucho, ya que podemos expresar la idea de cualquiera de las dos formas. Podemos decir
HACER el juego MIENTRAS la respuesta del usuario sea SI, o tambin podemos
decir REPETIR el juego HASTA QUE la respuesta del usuario sea NO. Pero lo que
s parece claro es que la condicin se debe evaluar al final, una vez que el usuario ha
jugado al menos una vez.
En realidad, un bucle con condicin al final se puede programar tambin como un bucle
con condicin al principio, haciendo uso de una variable booleana, que indique si el bucle
debe ejecutarse o no, y modificando esa variable al final del bucle.
As, para implementar un bucle HACER-MIENTRAS (do-while) como el que existe
en lenguaje C, la solucin sera la siguiente:
1 repetir=True # Indica que el bucle debe ser repetido
2 while repetir:
3 sent1
4 sent2
5 ...
6 sentN
7 if not condicion: # aqui evaluamos realmente la condicion de permanencia
8 repetir=False # si no se cumple, cambiamos la booleana

Es decir, tendramos una variable booleana que inicialmente valdra True, y que se usa
como expresin de un bucle while. Tras ejecutar el bucle una vez, al final del mismo se
mira la condicin que causara otra repeticin. Si la condicin no se cumple, la variable
booleana se cambia a False. De este modo, cuando python vuelva a la sentencia while
2.4 Manejo de estructuras bsicas de control de flujo 55

para repetir el bucle, al encontrar que la expresin es False, saldr del bucle y no lo
repetir ms.

Ejemplo El siguiente bucle fuerza al usuario a meter un nmero comprendido entre 1


y 5 (ambos inclusive). Es decir, en pseudocdigo el problema es:
HACER
pedir numero al usuario
MIENTRAS numero < 1 o numero > 5

Traducido a python, necesitamos una variable booleana que se mantenga a True mien-
tras el bucle deba repetirse, es decir, mientras el usuario insista en meter nmeros err-
neos. Un buen nombre para esta variable puede ser numero_erroneo. Es preferible
una nombre as, que expresa el significado de su cometido, que no un nombre genrico
como repetir, o seguir, o similar. Piensa como sera la implementacin en python
usando esta idea, y comprueba despus si la solucin que se te ha ocurrido es como esta:
1 numero_erroneo = True # Antes de leer el numero, suponemos que es erroneo
2 while numero_erroneo: # mientras el usuario siga metiendo numeros erroneos
3 num = int(raw_input("Introduzca un numero entre 1 y 5: ")
4 if not (num < 1 or num > 5):
5 numero_erroneo=False

Observar que, en lugar de la expresin if not (num<1 or num>5) podemos usar


tambin if num>=1 and num<=5 que es equivalente, y quizs ms fcil de leer y
entender.
La implementacin del bucle REPETIR-HASTA QUE usa una idea similar, si bien ahora
la variable booleana comienza valiendo False y el bucle debe repetirse HASTA QUE
se ponga a True. La idea es por tanto:
1 salir=False # Indica si hay que salir del bucle
2 while not salir: # atencion al not
3 sent1
4 sent2
5 ...
6 sentN
7 if condicion: # aqui evaluamos realmente la condicion de permanencia
8 salir=True # si no se cumple, cambiamos la booleana

A la mayora de alumnos les resulta ms fcil pensar en trminos de repetir hasta


que, que en trminos de hacer mientras, aunque cualquiera de estos bucles se puede
convertir en el otro. Si planteamos de nuevo el problema de pedir al usuario un nmero
comprendido entre 1 y 5, pero pensndolo ahora como un repetir hasta que, vemos
que la condicin sera ahora la contraria, es decir, en pseudocdigo:
REPETIR
pedir numero al usuario
HASTA QUE (numero>=1 Y numero<=5)

Para traducirlo a python, pesamos que hay que repetir HASTA QUE el nmero sea
correcto, por lo que un buen nombre para la variable booleana seria numero_correcto,
que inicializaremos con False y que cambiaremos a True cuando el usuario meta un
nmero correcto. Piensa cmo implementaras esto y comprueba tu solucin.
1 numero_correcto = False # Aunque aun no hemos leido el numero, suponemos que es erroneo
2 while not numero_correcto: # mientras el usuario NO meta uno correcto
2.4 Manejo de estructuras bsicas de control de flujo 56

3 num = int(raw_input("Introduzca un numero entre 1 y 5: ")


4 if num >= 1 and num <=5:
5 numero_correcto = True

Observa cmo el elegir un buen nombre para la variable booleana ayuda mucho a pensar
qu condicin debe evaluarse en el if y por qu debe aparecer un not en el while.
Mejora del estilo
Un detalle de estilo de programacin que ha aparecido en los ejemplos ante-
riores y que puede mejorarse es el siguiente.
En lugar de hacer un if en el que se evala una condicin booleana, para
seguidamente asignar una variable con el valor True o False, se podra
haber asignado directamente a la variable el resultado de la expresin.
Es decir, en lugar de:
1 if num >=1 and num <=5:
2 numero_correcto = True

podramos haber escrito directamente:


1 numero_correcto = num >=1 and num <=5

Observa que a la derecha de la asignacin hay una expresin booleana, cuyo


resultado ser True o False. Si es True, la variable numero_correcto
tomar este valor, exactamente igual que en el caso del if. Este estilo no solo
es ms conciso (ocupa una lnea, frente a dos), sino tambin ligeramente ms
eficiente, y hasta ms claro una vez te acostumbres a l.

2.4.4. El bucle for


Aunque con los tipos de bucle antes vistos se puede implementar ya cualquier algoritmo, es muy
frecuente que aparezca la necesidad de realizar un bucle controlado por un contador. Esto es, un
bucle en el que una variable vaya tomando valores enteros sucesivos, partiendo de un valor inicial y
hasta alcanzar un valor final.
Por ejemplo, si queremos calcular el factorial de un nmero N , necesitamos ir generando los
nmeros 1, 2, . . . , N e ir multiplicndolos todos. Obviemos de momento el problema de ir multipli-
cndolos para obtener el factorial, y centrmonos en el problema de cmo ir generando la secuencia
de nmeros 1, 2,. . . , N . De momento, vamos simplemente a escribir esta secuencia de nmeros, uno
en cada lnea.
Usando la estructura de control MIENTRAS vista anteriormente, el problema se resovera en
la forma siguiente. Necesitamos una variable que vaya tomando los valores sucesivos 1, 2, etc.
Llamemos a esta variable i (es un nombre habitual, inicial de la palabra index o ndice). Esta
variable comenzar con el valor 1. En el bucle se imprimir el valor de esta variable y despus se
incrementar en 1, para repetir de nuevo el bucle. Esta repeticin se mantiene MIENTRAS i sea
menor o igual que N. El pseudocdigo es por tanto:
i = 1
MIENTRAS i <= N
IMPRIMIR el valor de i
INCREMENTAR el valor de i

Lo cual se traduce de forma directa al siguiente cdigo en Python, en el cual damos a N un valor
de 10, para que se pueda ejecutar.
2.4 Manejo de estructuras bsicas de control de flujo 57

1 i = 1
2 while i <= 10:
3 print i
4 i = i + 1

Observar que el valor inicial de la i no tiene por qu ser necesariamente 1. De hecho son muy
comunes los bucles en los que i comienza con el valor 0. Depende del problema que queramos
resolver. Asimismo, el valor que sumamos a i en cada iteracin del bucle no tiene por qu ser 1.
Podramos querer contar de 2 en 2, o de 3 en 3, etc. A veces es incluso necesario contar hacia
atrs, de modo que la i se va decrementando en cada iteracin del bucle. En este caso el valor
inicial sera mayor que el valor final y la condicin del while sera que i >= valor_final.
Como vemos, todas estas variantes se pueden implementar con facilidad modificando ligeramente
la estructura while que acabamos de presentar.
Sin embargo, ya que este tipo de bucles aparece muy a menudo en todos los programas, la
mayora de los lenguajes de programacin incluyen una sintaxis especfica para implementarlos, que
permite simplificar ligeramente el cdigo y reducir el nmero de lneas necesarias. La mayora de
los lenguajes (por ejemplo, C, Java) utilizan la palabra reservada for para este tipo de bucles.
En Python tambin existe el bucle for y puede ser usado para implementar esta idea de bucle
controlado por contador. Como veremos en la seccin 2.7.4, el for de Python es mucho ms verstil,
y puede usarse no solo para hacer que la i vaya tomando el valor de una serie de enteros sucesivos,
sino para que vaya tomando una secuencia de valores arbitraria, a travs de las listas.
Pero no nos adelantemos. En esta seccin veremos nicamente cmo for puede usarse para
implementar el bucle controlado por contador.
Para este cometido, Python proporciona la funcin range() que genera una secuencia de enteros
entre un valor inicial y final que se le suministre y separados entre s una cantidad que tambin
se le puede suministrar. Es sobre esta secuencia de enteros sobre la que la variable i ir tomando
valores.
La sintaxis general de range es range(inicial, final, paso), siendo:

inicial el valor del primer entero de la secuencia. Puede omitirse, y entonces recibir autom-
ticamente el valor cero.

final el valor del primer entero fuera de la secuencia. Este valor ya no formar parte de la
secuencia de enteros generada, que se detendr en el entero anterior a ste.

paso es la distancia entre los enteros que se van generando. Puede omitirse y entonces recibir
automticamente el valor uno.

Por ejemplo, si ponemos range(5), estaramos suministrando nicamente el valor final, por lo
que inicial y paso recibiran automticamente los valores 0 y 1 respectivamente, y as se generara
la secuencia de cinco enteros empezando en 0 y terminando en 4:
>>> range(5)
[0, 1, 2, 3, 4]

Importante observa como en el resultado de range(5) no aparece el 5. La secuencia se detiene


en el valor anterior al final especificado.
Si especificamos dos parmetros, se entender que se trata de los valores inicial y final, aunque
al igual que en el caso anterior, el valor final no estar includo en la secuencia. El paso tomar por
defecto el valor 1. Por ejemplo:
>>> range(4,10)
[4, 5, 6, 7, 8, 9]
2.4 Manejo de estructuras bsicas de control de flujo 58

Finalmente, si queremos especificar el paso, necesitamos especificar entonces los tres valores,
inicial, final y paso. La cantidad paso puede ser positiva o negativa, permitiendo as hacer rangos
que cuentan hacia adelante o hacia atrs. Un ejemplo de rango ascendente, que recorre los impares
menores de 10:
>>> range(1,10,2)
[1, 3, 5, 7, 9]

En el bucle ascendente, el ltimo nmero que se incluye en el rango es el mayor que cumpla ser
menor que el valor final. Es decir, el cuanto se encuentra que el valor es mayor o igual que el valor
final, el rango se detiene y ese ya no sera includo.
Qu parmetros tendramos que pasarle a range para generar un rango que incluya los nmeros
pares comprendidos entre 1 y 10, incluyendo al 10? Se deja como ejercicio para el lector.
Finalmente, si el paso es negativo, el valor inicial tendr que ser mayor que el valor final, de lo
contrario se nos generara un rango vaco. Un par de ejemplos:
>>> range(1,10,-1)
[]
>>> range(10,1,-1)
[10, 9, 8, 7, 6, 5, 4, 3, 2]

Observa como en el primer caso el rango que se obtiene est vaco, debido a que por error
hemos puesto un valor inicial que es menor que el valor final. En el segundo caso el rango se genera
correctamente, pero observa que, al igual que en los rangos ascendentes, el valor final especificado (el
1) no forma parte de la secuencia que se genera. Es decir, en este caso range va generando nmeros
hasta que encuentra uno que es menor o igual que el final especificado y entonces se detiene y este
ltimo no forma parte del resultado.
Qu parmetros habra que pasarle a range para que genere todos los mltiplos de 3 positivos
y menores de 100? Se deja como ejercicio para el lector.
Una vez hemos comprendido como range puede usarse para generar listas de nmeros, slo
queda decir cmo usar la sintaxis for para hacer que una variable i vaya tomando valores sobre
esa lista. La sintaxis es la siguiente:
for i in range(...):
sentencia1
sentencia2

Esto crea un bucle formado por sentencia1 y sentencia2 que se repetir un nmero de
veces que depende de los parmetros que pongamos en range, y en cada una de esas repeticiones,
la variable i va tomando un valor de los generados por range. Por ejemplo, si queremos imprimir
los nmeros del 1 al 10:
1 for i in range(1,11):
2 print i

Ya que range(1,11) genera una secuencia de 10 enteros, el bucle se repetir 10 veces. En


cada iteracin del bucle la i tendr un valor diferente, que va pasando por la secuencia de valores
generada por range. Este bucle por tanto es equivalente al que vimos en la pgina 57, aunque como
vemos la sintaxis es mucho ms compacta.
Es importante sealar que para que el 10 forme tambin parte de la secuencia, debemos espe-
cificar 11 como valor final.
Esto puede resultarte chocante, pero es que, si bien las personas, cuando queremos contar N
nmeros solemos hacerlo desde 1 hasta N, ambos inclusives, en informtica sin embargo es mucho
ms frecuente el caso de que los N nmeros deban ir desde 0 hasta N-1, lo cual es justamente lo que
obtenemos si ponemos range(N).
Otra forma de imprimir los nmeros entre 1 y 10, por tanto, podra ser:
2.4 Manejo de estructuras bsicas de control de flujo 59

1 for i in range(10):
2 print i+1

En ocasiones, los valores que tome la variable i no nos importan. Si queremos, por ejemplo,
imprimir una secuencia de 20 asteriscos en pantalla, nos da igual si la i va entre 1 y 20 o entre 0 y
19, con tal de que haya 20 repeticiones del bucle. En ese caso range(20) es perfectamente vlido
y ms legible incluso que range(1,21). Por ejemplo:
1 for i in range(20): # Repetir 20 veces
2 print "*", # imprimir asterisco

Ejemplo final Vamos a escribir un programa que pida al usuario un nmero entero y positivo
(debe insistir en que sea positivo, repitiendo la pregunta si el usuario mete uno negativo). Una vez
tenemos ese nmero, se calcula el factorial del mismo5 , y se imprime en pantalla el resultado.
El cdigo siguiente muestra una posible implementacin:
1 # Para forzar a que el numero introducido sea positivo, haremos un bucle
2 # REPETIR-HASTA QUE sea positivo
3 es_positivo = False # Inicialmente suponemos que no lo es
4 while not es_positivo:
5 n = int(raw_input("Introduce un numero positivo o cero: "))
6 if n >= 0:
7 es_positivo = True
8
9 # Ahora calcularemos el factorial. Para ello hay que multiplicar
10 # todos los numeros entre 1 y n. Usaremos una variable "fact"
11 # que inicialmente sea 1 y en cada iteracion del bucle multiplique
12 # su valor anterior por el i correspondiente a esa iteracion
13
14 fact = 1
15 for i in range(1,n+1):
16 fact = fact * i
17
18 # Al salir del bucle tenemos la respuesta, la imprimimos
19 print n, "!=", fact

Algunos comentarios sobre el listado anterior:

Observa los parmetros que hemos pasado a range(). Para que la i vaya tomando valores
entre 1 y n, ambos inclusive, ha sido necesario poner range(1, n+1).

Se trata de un bucle ascendente, pero podra haberse implementado tambin en forma de


bucle descendente. Intntalo.

Qu ocurre si n es cero? Funciona el programa, o se rompe su ejecucin? Y si funciona


produce la respuesta correcta? (nota, el factorial de 0 es igual a 1 por definicin).

Pongamos por caso que vamos a calcular el factorial de 6. Fijate que en la primera itera-
cin del bucle, en la que i vale 1 y fact tambin vale 1, estamos haciendo simplemente el
producto 1 * 1, lo cual podra haberse omitido. Si en vez de range(1, n+1) ponemos
range(2, n+1) nos saltamos esta primera multiplicacin y el algoritmo es un poco ms
veloz. Pero seguir funcionando correctamente para n=0 y para n=1? Pinsalo.

2.4.5. Otras instrucciones para bucles: break y continue


Hay un par de instrucciones que permiten controlar el flujo de control en los bucles.
Las ms importante es "break" que permite finalizar el bucle (salir de l) inmediatamente. Puede
5
El factorial de N se denota por N ! y se calcula como el producto de todos los enteros positivos menores o iguales
aN
2.4 Manejo de estructuras bsicas de control de flujo 60

usarse tanto en los bucles "for" como en los bucles "while".


La otra es "continue" aunque se usa menos. Permite volver inmediatamente al inicio del bucle para
realizar el siguiente ciclo del mismo.
Ambas van, casi siempre, dentro de un condicional interno al bucle.
Existen tambin en otros lenguajes como Java o C++.
La instruccin break El siguiente ejemplo ilustra el uso de la primera de las dos instrucciones.
1 for i in range(5):
2 if i==3:
3 break
4 print i

La salida de este programa es 0, 1 y 2, uno en cada lnea. Al ejecutarse la instruccin "break" el


bucle se interrumpe y finaliza en vez de seguir con los valores 3 y 4.
La instruccin continue El siguiente ejemplo ilustra el uso de la segunda.
1 for i in range(5):
2 if i==3:
3 continue
4 print i

La salida de este programa es 0, 1, 2 y 4, uno en cada lnea. Al ejecutarse la instruccin "conti-


nue" cuando "i" vale 3, no se ejecuta el resto del bucle para ese valor y se vuelve al principio para
continuar con el siguiente valor de "i".

Ejemplo de uso El siguiente programa ilustra la utilidad de las instrucciones anteriores. Se trata
de un programa que determina si un nmero es primo.
1 # se pide el numero entero por teclado
2 n=int(raw_input("numero a comprobar"))
3
4 # suponemos inicialmente que es primo pero en cuanto
5 # encontremos un divisor exacto anotaremos que no lo es
6 es_primo=True
7
8 # bucle (poco eficiente por cierto) para buscar divisores exactos
9 for i in range(2,n):
10 if n %i==0:
11 es_primo=False
12 break
13
14 # ya hemos salido del bucle bien porque acabo con su valor "i" superior
15 # o bien porque se ejecuto la instruccion "break"
16 if es_primo:
17 print n,"es primo"
18 else:
19 print n,"no es primo"

Para saber ms
El "exit()" permite terminar la ejecucin de un programa. Funciona como si se hubiera
llegado al final del mismo y ya no hubiera ms instrucciones para ejecutar.
Se emplea cuando sabemos que se va a producir un error y que no debe continuar la
ejecucin del programa.
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 61

1 ...
2 ...
3 # calculamos el cociente si se puede
4 if divisor==0:
5 print "no se puede dividir por cero, fin del programa"
6 exit()
7 # se puede calcular, prosigue el programa
8 cociente=valor/divisor
9 ...
10 ...

2.4.6. Ejercicios propuestos


Ejemplo

1. Se denomina semi-factorial 6 de un entero N , y se denota por N !!, al producto de N por N 2,


por N 4, etc. hasta llegar a 2 1.
Dicho de otra forma, si N es impar, N !! es el producto de todos los impares menores o iguales
que N , mientras que si N es par, N !! es el producto de todos los pares menores o iguales que
N.
Escribe un programa que pida al usuario el valor de N , forzando a que sea positivo, e imprima
el resultado del clculo del semi-factorial.

2. Probablemente para resolver el ejercicio anterior has mirado con un if si N era par o impar,
haciendo un bucle diferente en cada caso. Piensa cmo podras calcular N !! con un solo bucle
que funcione tanto si N es par como si es impar. Pista: intenta con un bucle descendente.

2.5. Definicin y uso de subprogramas y funciones. mbito de variables


Podemos pensar que un programa se compone de varias partes, como por ejemplo, obtener
los datos de entrada por parte del usuario, realizar ciertos clculos con los mismos y mostrar el
resultado de esos clculos en la pantalla. Un buen plan de ataque para realizar un programa consiste
en descomponer la tarea a realizar en unas cuantas subtareas, que a su vez pueden descomponerse
en subtareas ms pequeas o ms simples y as sucesivamente. Llegar un momento en que dichas
subtareas sern lo suficientemente pequeas como para que sea sencillo programarlas. Este mtodo se
conoce como diseo descendente y da lugar a la programacin modular. La mayora de los lenguajes
de programacin cuentan con recursos que les permiten dividir un programa en partes ms pequeas
(subprogramas). En el caso del Python estos subprogramas se conocen como funciones.
Importante
Un subprograma es un fragmento de cdigo de un programa que resuelve un subproblema
con entidad propia. En Python estos subprogramas se implementan mediante funciones

2.5.1. Definiciones y uso


En el contexto de la programacin una funcin es una secuencia de sentencias que ejecuta una
operacin deseada y tiene un nombre. Esta operacin se especifica en una definicin de funcin. La
sintaxis para una definicin de funcin en Python es:
6
En la literatura inglesa es ms frecuente el trmino double factorial, aunque ambos trminos son vlidos.
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 62

def NOMBRE( LISTA DE PARAMETROS ):


SENTENCIAS

Sigue la siguiente estructura:


1. Un encabezado, que empieza con una palabra reservada (def), contina con el nombre que
se quiere dar a la funcin, sigue con la lista de parmetros entre parntesis y termina con dos
puntos.

2. Un cuerpo consistente en una o ms sentencias de Python, cada una de ellas con la misma
sangra a partir del margen izquierdo. En esta asignatura usaremos un sangrado estndar de
cuatro espacios.

Importante
Se pueden inventar los nombres que se deseen para las funciones, siguiendo las mismas
reglas que para los nombres de variable (vase pgina 40).

La lista de parmetros especifica qu informacin, si es que la hay, se debe proporcionar a fin de


usar la nueva funcin. La lista de parmetros puede estar vaca o contener varios parmetros. Ms
adelante se ampliar la informacin acerca de los parmetros.
La primera funcin que escribiremos no tiene parmetros, por lo que la implementacin tiene el
siguiente aspecto:
1 def nueva_linea():
2 print # la sentencia print sin parametros muestra una nueva linea

Esta funcin se llama nueva_linea. Los parntesis vacos indican que la funcin no tiene
parmetros. Su cuerpo contiene una nica sentencia, cuya salida es una lnea vaca (eso es lo que
ocurre cuando se usa la sentencia print sin argumentos).
Importante
Definir una funcin no hace que la funcin se ejecute. Para que una funcin se ejecute
se necesita una llamada a la funcin.

Las llamadas a las funciones contienen el nombre de la funcin a ejecutar seguida por la lista,
entre parntesis, de los valores que son asignados a los parmetros en la definicin de funcin.
Nuestra primera funcin tiene una lista vaca de parmetros, por lo que la llamada a la funcin
no tiene ningn argumento. Ntese, sin embargo, que en la llamada a la funcin se requieren los
parntesis:
1 def nueva_linea():
2 print # la sentencia print sin parametros muestra una nueva linea
3
4 print "Primera Linea."
5 nueva_linea()
6 print "Segunda Linea."

Primera Lnea.

Segunda Lnea.

El espacio extra entre las dos lneas es el resultado de la llamada a la funcin nueva_linea.
Qu pasa si deseamos ms espacio entre las lneas? Podemos llamar la misma funcin repetida-
mente:
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 63

1 def nueva_linea():
2 print # la sentencia print sin parametros muestra una nueva linea
3
4 print "Primera Linea."
5 nueva_linea()
6 nueva_linea()
7 nueva_linea()
8 print "Segunda Linea."

Primera Lnea.

Segunda Lnea.

O podemos escribir una nueva funcin llamada tres_lineas que muestre tres lneas vacas:
1 def nueva_linea():
2 print # la sentencia print sin parametros muestra una nueva linea
3
4 def tres_lineas(): # llama 3 veces a nueva_linea()
5 nueva_linea()
6 nueva_linea()
7 nueva_linea()
8
9 print "Primera Linea."
10 tres_lineas()
11 print "Segunda Linea."

Esta funcin contiene tres llamadas a la funcin nueva_linea. Cada una de estas llamadas
ejecutar una vez el cdigo asociado a la funcin, con lo que obtendremos la misma salida en este
ejemplo que en el anterior.
Importante
Dentro de una funcin se puede llamar a cualquier otra funcin que haya sido definida
previamente.

Hasta este punto, puede que no parezca claro por qu hay que tomarse la molestia de crear todas
estas funciones. De hecho, hay muchas razones, y el ejemplo que acabamos de ver muestra dos:

1. Crear una nueva funcin nos permite agrupar un cierto nmero de sentencias y darles un
nombre. Las funciones pueden simplificar un programa escondiendo un clculo complejo detrs
de un nico comando que usa palabras en lenguaje natural.

2. Crear una nueva funcin puede recortar el tamao de un programa eliminando el cdigo
repetitivo. Por ejemplo, una forma ms corta de mostrar nueve lneas consecutivas consiste
en llamar la funcin tres_lineas tres veces.

2.5.2. Documentacin de funciones


Las funciones en python se pueden documentar con lo que se conocen como cadenas de docu-
mentacin o docstrings. Ejemplo:
1 def nueva_linea():
2 """Esta funcion muestra en pantalla una linea vacia"""
3 print # imprime una linea en blanco
4
5 def tres_lineas():
6 """Esta funcion muestra en pantalla tres lineas vacia"""
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 64

7 nueva_linea() # llama 3 veces a la funcion nueva_linea


8 nueva_linea()
9 nueva_linea()
10
11 print "Primera Linea."
12 tres_lineas()
13 print "Segunda Linea."

Todo lo que hay entre las tres comillas es la cadena de documentacin de la funcin, que explica
lo que hace sta. Una cadena de documentacin, si existe, debe ser lo primero que se define en
la funcin (es decir, lo primero que aparece tras los dos puntos). No es tcnicamente necesario
incluir una cadena de documentacin, pero es recomendable hacerlo siempre. Estas cadenas estn
delimitadas por tres comillas al principio y tres comillas al final, pudiendo ocupar varias lneas.
Muchos entornos de programacin de Python utilizan la cadena de documentacin para pro-
porcionar ayuda sensible al contexto, de modo que cuando se escribe el nombre de una funcin, su
cadena de documentacin se muestra como ayuda. Otra forma de ver la cadena de documentacin
de una funcin es utilizando la funcin help desde el intrprete .
>>> help(nueva_linea)
Help on function nueva_linea in module main:

nueva_linea()
Esta funcion muestra en pantalla una linea vacia

Importante
La idea de las cadenas de documentacin es describir el comportamiento externo de la
funcin, mientras que el funcionamiento interno se describe utilizando comentarios

Importante
Escribir cadenas de documentacin y comentarios es una buena prctica de programa-
cin. Sern ms tiles cuanto mejor expliquen qu hace la funcin y cmo lo hace

2.5.3. Parmetros y argumentos


Ya hemos definido un par de funciones cuyo objetivo es escribir lineas vacas. Estas funciones
tienen su utilidad, sin embargo, podra sernos ms til tener un cdigo capaz de escribir una lnea
a modo de separador, por ejemplo una lnea con 10 asteriscos:

**********
o una lnea con 20 guiones:

--------------------

Para cubrir esta necesidad, podemos implementar dos funciones: una que imprima 10 asteriscos
y otra que imprima 20 guiones. Pero, no sera ms til tener una nica funcin capaz de cubrir las
dos necesidades? Para ello podramos implementar la funcin pinta_linea, que se utilizara de
la siguiente manera:
>>> pinta_linea(10,"*")
**********
>>> pinta_linea(20,"-")
--------------------
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 65

Podemos observar que el nombre de la funcin es el mismo. Lo que cambia son los argumentos
que se pasan a la funcin y, por tanto, el resultado de su ejecucin. Podramos leer el cdigo
anterior como "pinta una lnea de 10 asteriscos" y "pinta una lnea de 20 guiones". Veamos cmo se
implementara esta funcin:
1 def pinta_linea(veces, car):
2 """Muestra en la pantalla una linea con un determinado numero de caracteres
3 Tiene 2 parametros:
4 - veces, numero de veces que aparecera el caracter en la linea
5 - car, caracter que se quiere mostar"""
6 i=1
7 cadena="" # se crea una cadena vacia
8 while i <= veces:
9 cadena = cadena + car # se aniade un caracter en cada iteracion
10 i = i + 1
11 print cadena
12
13
14 pinta_linea(10,"*")
15 pinta_linea(20,"-")

Vemos que, en esta ocasin, el espacio dedicado a la lista de parmetros no est vaco. Entre los
parntesis se indican dos parmetros:

el primero, veces, se utiliza para almacenar el nmero de veces que queremos que aparezca
repetido el caracter que se pasa como segundo parmetro

el segundo, car, sirve para almacenar el carcter que se quiere mostrar como separador

Observa que el orden de los parmetros (en la definicin) se corresponde con el orden de los argu-
mentos (en la llamada a la funcin). Si al llamar a la funcin escribisemos pinta_linea("*",10)
no se producira el resultado esperado.
Importante
A la hora de definir una funcin se debe indicar, entre parntesis, la lista de parmetros
(parmetros formales) que esta funcin necesita. Cuando se quiere utilizar una funcin
se le pasarn, entre parntesis, los argumentos (parmetros reales) necesarios para su
ejecucin.

2.5.4. Flujo de ejecucin


Con el fin de asegurar que una funcin se defina antes de su primer uso es importante conocer el
orden en el que las sentencias se ejecutan. Este orden de ejecucin se denomina flujo de ejecucin.
La ejecucin siempre empieza con la primera sentencia del programa y las sentencias se ejecutan
una a una, desde arriba hacia abajo.
Importante
Las definiciones de funcin no alteran el flujo de ejecucin del programa, pero recuerda
que las sentencias que estn dentro de las funciones no se ejecutan hasta que stas sean
llamadas.

Las llamadas a funciones son como un desvo en el flujo de ejecucin. En lugar de continuar
con la siguiente sentencia, el flujo salta a la primera lnea de la funcin llamada, ejecuta todas las
sentencias de la funcin, y regresa para continuar donde estaba previamente. Esto suena sencillo,
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 66

hasta que caemos en la cuenta de que una funcin puede llamar a otra, lo que conllevara un nuevo
salto en el flujo de ejecucin hasta el cdigo de la funcin que acaba de ser llamada.
Afortunadamente, todos los lenguajes de programacin son capaces de realizar todos estos saltos
de forma transparente al programador, as que cada vez que una funcin termina, el programa regresa
al punto desde donde fue llamada. Cuando llega al fin del programa, la ejecucin termina.
Para comprender esto mejor, vamos a continuar con el ejemplo anterior extendindolo para pintar
rectngulos. Para ello vamos a definir una nueva funcin pinta_rectangulo que, apoyndose en
pinta_linea es capaz de dibujar un rectngulo:
1 def pinta_linea(veces, car):
2 i=1
3 cadena=""
4 while i <= veces:
5 cadena = cadena + car
6 i = i + 1
7 print cadena
8
9 def pinta_rectangulo(alto, ancho, car):
10 i=1
11 while i <= alto:
12 pinta_linea(ancho,car)
13 i = i + 1
14
15 altura = 5
16 base = 20
17 simbolo = "*"
18 pinta_rectangulo(altura,base,simbolo)

La salida de este programa es la siguiente:


********************
********************
********************
********************
********************

Mediante un diagrama de pila7 podremos observar el valor de cada variable o parmetro y la


funcin a la que pertenecen. Veamos cmo se va actualizando el diagrama de pila a medida que
se ejecuta el programa anterior. El programa se inicia en la lnea 15 con la creacin de la variable
altura, la variable base (lnea 16) y la variable simbolo (lnea 17); en ese momento tendramos
el siguiente diagrama de pila:

<module>
5
altura

base 20

simbolo
"*"

Vemos que el diagrama contiene un recuadro cuyo nombre es <module> y en su interior aparecen
las variables base, altura y simbolo apuntando a sus valores correspondientes. <module> es
7
Los diagramas de pila no slo muestran el valor de cada variable, sino que adems muestran la funcin a la cual
pertenece cada variable. El funcionamiento de este diagrama es como el de una pila de elementos: si queremos aadir
un elemento a la pila, este elemento se aadir en la cima de la pila y si queremos retirar un elemento de la pila,
este debe ser necesariamente el de la cima de la pila, ya que si tratsemos de retirar un elemento que no estuviese en
la cima, entonces la pila se desmoronara. Pensad en una pila de ropa o una pila de cajas para comprender mejor el
funcionamiento de este diagrama. En este caso lo que se apilan son llamadas a funciones.
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 67

un nombre especial que hace referencia al mdulo que define el programa: el cdigo que est fuera
de todas las funciones.
En la lnea 18 se llama a la funcin pinta_rectangulo, con lo que pasa a ejecutarse la lnea
9 (creando los tres parmetros) y la lnea 10 (creando la variable i). En ese momento el diagrama
de pila queda de la siguiente manera:

pinta_rectangulo
i 1

alto 5

ancho 20

car "*"

<module>
altura

base

simbolo

Podemos observar que <module> contina en la pila y sobre l aparece la funcin pinta_rectangulo
conteniendo todos los parmetros y variables que se definen en la misma. Los parmetros alto,
ancho y car toman, respectivamente, los valores de altura, base y simbolo, mientras que la
variable i toma inicialmente el valor 1. Despus se entra en un bucle (lnea 11) que ejecutar alto
veces las lneas 12 y 13. La lnea 12 hace una llamada a la funcin pinta_linea. Despus de
llamar a esta funcin, se ejecuta la lnea 1, que crea los dos parmetros (veces y car), y las lneas
2 y 3, que crean un par de variables (i y cadena):

pinta_linea

cadena

veces

car
""
pinta_rectangulo
i 1

alto 5

ancho 20

car "*"

<module>
altura

base

simbolo

Los parmetros y variables creados en esta funcin apuntan a los valores correspondientes, es
decir, veces y car apuntan, respectivamente, a los valores de ancho y car, mientras que la
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 68

variable i apunta inicialmente al valor 1 y la variable cadena apunta a un str vaco. Se entra
entonces en el bucle de la lnea 4 que tendr veces iteraciones. En cada iteracin aadir un carcter
a la cadena (lnea 5) e incrementar el valor de la i (lnea 6). Al finalizar el bucle imprimir en la
pantalla la cadena resultante y la funcin finalizar, pasando a ejecutarse la lnea 13 en la funcin
pinta_rectangulo.
Cuando una funcin llega a su fin se elimina del diagrama de pila. Llegar un momento en que no
haya funciones apiladas en el diagrama de pila, es decir, se estar ejecutando el cdigo del mdulo
principal <module>. Cuando el cdigo de este mdulo se finalice, el programa finalizar.
2.5.5. Mensajes de error
Si durante la ejecucin de una funcin ocurriese un error, Python mostrar el nombre de
la funcin que ha fallado, de la que la ha llamado y as sucesivamente hasta llegar al mdulo
principal. Vamos a modificar el programa anterior introduciendo un error (ponindole como nombre
pinta_rect_mal.py) para ver el mensaje que nos muestra en intrprete:
1 def pinta_linea(veces, car):
2 i=1
3 cadena=""
4 while i <= veces:
5 cadena = cadena + car
6 i = i + car # error <- intento sumar a un int un str
7 print cadena
8
9 def pinta_rectangulo(alto, ancho, car):
10 i=1
11 while i <= alto:
12 pinta_linea(ancho,car)
13 i = i + 1
14
15 altura = 5
16 base = 20
17 simbolo = "*"
18 pinta_rectangulo(altura,base,simbolo)

La salida de este programa es la siguiente:


Traceback (most recent call last):
File "pinta_rect_mal.py", line 18, in <module>
pintar_rectangulo(altura,base,simbolo)
File "pinta_rect_mal.py", line 12, in pinta_rectangulo
pinta_linea(ancho,car)
File "pinta_rect_mal.py", line 6, in pinta_linea
i = i + car
TypeError: unsupported operand type(s) for +: int and str

En el mensaje de error podemos leer que en la lnea 18 del programa principal (<module>) se llama
a la funcin pinta_rectangulo. En la lnea 12, que es una instruccin de esa funcin, se realiza
una llamada a la funcin pinta_linea. Finalmente, en la linea 6, en la funcin pinta_linea
se ejecuta la instruccin i=i+car, que es la instruccin que produce un error, concretamente:
"operador + no soportado para los tipos int y str". Debis prestar atencin al hecho de que en el
mensaje de error se nos indican las funciones implicadas en el orden en el que han sido llamadas,
es decir, desde la base de la pila hasta la cima de la misma.
2.5.6. Modificando el valor de los parmetros
Ya sabemos definir parmetros y pasar argumentos a las funciones. Sin embargo, hay un tema
que no est claro, qu sucede cuando se modifica el valor de un parmetro dentro de una funcin?
se modificar el valor de la variable que se utiliza como argumento en la llamada de la funcin?
Veamos un ejemplo:
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 69

1 def decrementa(val):
2 val = val - 1
3 print val
4
5 x = 7
6 print x
7 decrementa(x)
8 print x

En el cdigo se define una funcin que decrementa en una unidad el valor que se le pasa como
parmetro. Veamos lo que sucede durante la ejecucin del programa. Al ejecutarse la lnea 5 se
crea la variable x apuntando al valor 7. En la siguiente lnea se imprime el valor apuntado por la
variable.
<module>

x 7

En la lnea 7 se llama a la funcin decrementa, con lo que se ejecuta la linea 1 crendose as el


parmetro val que apuntar al mismo valor que apunta la variable x:
decrementa

val

<module>

x 7

La ejecucin de la lnea 2 implica que el parmetro val deja de apuntar al 7 pasando a apuntar
al 6, con lo que el parmetro val y la variable x quedan desligados. La lnea 3 imprimir un 6, el
valor apuntado por val.
decrementa

val
6
<module>

x 7

Finaliza la funcin y se ejecuta la ltima lnea. La ejecucin completa del programa producir la
siguiente salida en la pantalla:
7
6
7

Por tanto, la modificacin de un parmetro (val) dentro de la funcin no afecta al argumento (x)
con el que se ha llamado a la funcin.
Esto es cierto para todos los tipos de variables que hemos visto hasta el momento, sin embargo,
ms adelante, se dedicar una seccin a explicar el tipo de dato lista. Su comportamiento como
parmetro de una funcin es diferente y se comentar en la seccin 2.7.5.
Conclusin
Cuando tenemos un parmetro de tipo int, float, str o bool, las modificaciones
hechas sobre ese parmetro (parmetro formal) no se ven reflejadas en el argumento
(parmetro real) que se ha utilizado para llamar a la funcin.
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 70

2.5.7. mbito de parmetros y variables


En el ltimo diagrama de la seccin 2.5.4 podemos apreciar cmo cada funcin tiene sus propias
variables o parmetros. De esta forma, durante la ejecucin de cada funcin solo se podrn utilizar los
identificadores (variables o parmetros) contenidos en su recuadro correspondiente ms los definidos
en <module>, que son accesibles desde todas las funciones del propio programa.
Cuando se crea una variable dentro de una funcin, esa variable puede ser utilizada nicamente
dentro de esa funcin. Lo mismo sucede con los parmetros, solo pueden utilizarse dentro de la
funcin donde estn definidos. As, desde la funcin pinta_linea se podr acceder a los identi-
ficadores (variables o parmetros) cadena, i, veces, car, altura, base y simbolo. Desde la
funcin pinta_rectangulo se podr acceder a los identificadores i, alto, ancho, car, altura,
base y simbolo. Finalmente, desde <module> se tendr acceso, nicamente, a altura, base y
simbolo.
En los diagramas que se muestran en este epgrafe se ha cambiado un poco la representacin
para incluir el mbito de los identificadores: la funcin definida en el siguiente trozo de cdigo
(decrementa_e_imprime) aparece incluida dentro del recuadro de <module> mostrando que
el mdulo ms especfico (decrementa_e_imprime) es capaz de acceder a todas las variables
mientras que el ms general (<module>) solo accede a las ms generales.
Importante
Las variables y parmetros declarados dentro de una funcin se consideran locales, ya que
solo se puede acceder a ellos desde la propia funcin. Las variables que estn declaradas
fuera de las funciones se consideran globales y se pueden utilizar en todo el programa.

A veces nos encontramos en situaciones en las que al utilizar una variable o parmetro puede
parecer que hay una ambigedad al haber varias variables con el mismo nombre. Veamos un ejemplo:
1 def decrementa_e_imprime(x):
2 x = x - 1
3 print x
4
5 x = 10
6 y = 1
7 decrementa_e_imprime(y)

Una variable (x) del programa o mdulo principal tiene el mismo nombre que el parmetro de la
funcin. Cuando en la lnea 2 de la funcin se hace x=x-1 a qu valor apunta la x? a 1 o a 10?
Vamos a verlo en el diagrama de pila. Al ejecutarse las lneas 5 y 6 se crean las variables x e y que
apuntan, respectivamente, a los valores 10 y 1:

y 1

x 10

<module>

A continuacin se ejecuta la llamada a la funcin decrementa_e_imprime pasndole como ar-


gumento la variable y. Como se puede observar en el cdigo, la funcin crea un parmetro llamado
x y que, en esta ocasin, apuntar al mismo valor que la y:
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 71

decrementa_e_imprime

y 1

x 10

<module>

Entonces, nos encontramos en una situacin en la que desde la funcin decrementa_e_imprime


tenemos acceso a tres identificadores: uno local (el parmetro x) y dos globales (la x y la y). Como
se puede ver, dos de ellos comparten el mismo nombre. Al ejecutar la lnea 2 qu identificador se
modificar? Puede parecer que existe una ambigedad, sin embargo, tal ambigedad no existe, ya
que cuando hay un conflicto de este tipo el intrprete entiende que se est haciendo referencia al
identificador local. Por tanto, tras ejecutar la lnea 2 estaremos en la siguiente situacin:

decrementa_e_imprime

x
0

y 1

x 10

<module>

y se imprimir un 0 en la pantalla.
Importante
Para evitar este tipo de situaciones que pueden confundirnos, una buena prctica de
programacin es asignar a las variables y a los parmetros nombres descriptivos y a la
vez diferentes

Para saber ms
Cuando desde una funcin se quiere acceder a una variable global se debe escribir la
sentencia: global nombre_variable

2.5.8. Funciones que retornan valores


Hasta ahora hemos implementado funciones que realizaban unas ciertas acciones que finalizaban
mostrando en pantalla el resultado de las mismas: pintar lneas, rectngulos o decrementar un valor
y mostrarlo por pantalla. Sin embargo, la verdadera potencia de las funciones radica en el hecho de
que el producto de esas acciones o clculos puede ser guardado en una variable y ser usado, a su
vez, para realizar clculos ms complejos.
Vamos a ver un ejemplo de funcin que retorna algo:
1 def potencia(x,y):
2 return x**y
3
4 resultado = potencia(2,10)
5 print resultado
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 72

La funcin potencia retorna x elevado a y. En la lnea 4 vemos que el resultado de la funcin puede
ser asignado a una variable y, por tanto, podr ser utilizado para realizar cualquier otra operacin
que nos interese. Pero, cul es la diferencia respecto a las funciones que hemos visto hasta el
momento? La respuesta es sencilla: la sentencia return. Esta sentencia hace que la funcin finalice
en ese mismo instante produciendo como resultado lo que est a continuacin del return. Hay que
ser cuidadosos, ya que cualquier instruccin que situemos en las siguientes lneas no se ejecutar si
antes se ha ejecutado el return.
Importante
Cuando una funcin ejecuta la sentencia return el flujo de ejecucin vuelve inmedia-
tamente al punto en el que se realiz la llamada a la funcin

A estas alturas del curso, todos sabemos que la operacin 10/2 calcula el resultado de la divisin
de 10 entre 2. Y tambin sabemos que la operacin 10/0 va a producir un error de divisin por 0:
>>> 10/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

Podemos utilizar las funciones como un mecanismo para controlar este tipo de errores. Podramos
implementar la funcin divide que al encontrarse con 0 como denominador, no haga la divisin y
nos avise de este hecho:
1 def divide(num,den):
2 if den == 0:
3 return None
4 else:
5 return num/den
6
7 resultado = divide(10,0)
8 if resultado == None:
9 print "Hay un 0 en el denominador"
10 else:
11 print "El resultado es:",resultado

None es un valor especial que tiene ciertas utilidades como la que acabamos de ver. Adems, aunque
no nos hayamos dado cuenta, todas las funciones retornan algn valor, incluso las que no tienen la
sentencia return. Estas funciones retornan, por defecto, None.

Para saber ms
Funciones que retornan varios valores
En ocasiones, puede resultarnos necesaria una funcin que retorne ms de un valor. Por
ejemplo, podra resultarnos til una funcin que dados dos nmeros retorne primero el
mayor y luego el menor. La implementacin sera tan sencilla como:
1 def max_min(x,y):
2 if x > y:
3 return x, y
4 else:
5 return y, x
6
7 mx, mn = max_min(3,7)
8
9 print "El maximo es el",mx,"y el minimo el",mn
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 73

Vemos que lo nico que hay que hacer es colocar a continuacin del return los valores
que se deseen retornar. Eso si, cuando se llame a la funcin, se necesitar colocar en
la parte izquierda de la asignacin tantas variables como valores se retornen. De esta
forma, tras la ejecucin de la funcin max_min, en mx estar almacenado el valor mayor
y en mn el menor.
En realidad, incluso en este caso en que parece que la funcin puede retornar ms de
un valor, est retornando uno solo, si bien es un valor de un tipo de dato que no hemos
explicado. Se trata del tipo tupla que permite agrupar, separados por comas, varios
valores o variables.
Por tanto, cuando escribimos return x, y la funcin est retornando una tupla (solo
una), que est compuesta por dos variables. Es habitual poner parntesis alrededor de
las tuplas, para hacerlas ms evidentes, como por ejemplo return(x, y).
En el programa principal, en la lnea 7 en que aparecen dos valores a la izquierda de
la asignacin, se trata otra vez de una tupla, formada por dos variables. Por tanto esa
asignacin asigna una tupla a otra tupla. Ambas tuplas deben tener el mismo nmero
de elementos para que la asignacin funcione.

Para saber ms
Mdulos
A medida que vayamos realizando programas nos iremos dando cuenta de que en muchos
de ellos necesitaremos utilizar las mismas funciones. Por ejemplo, la funcin divide po-
dra resultarnos de utilidad en varios programas que no tengan nada en comn. Para
tratar de evitar el tener que implementar esta funcin en cada programa podemos utilizar
lo que se conoce como mdulos. Un mdulo es un fichero que contiene la implementa-
cin de varias funciones. Lo ms razonable es que un mdulo contenga funciones que
compartan la misma temtica. La versin de Python que utilizamos ya viene con un
montn de mdulos que podemos utilizar. Ms adelante veremos algunos ejemplos.
Creacin de mdulos
Crear mdulos es muy sencillo. Vamos a meter en el fichero mod_pintar.py unas
cuantas funciones que pintan en la pantalla:
1 def pinta_linea(veces, car):
2 i=1
3 cadena=""
4 while i <= veces:
5 cadena = cadena + car
6 i = i + 1
7 print cadena
8
9 def pinta_rectangulo(alto, ancho, car):
10 i=1
11 while i <= alto:
12 pinta_linea(ancho,car)
13 i = i + 1
14
15 def pinta_cuadrado(lado, car):
16 pinta_rectangulo(lado,lado,car)
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 74

y ya est creado el mdulo! Ahora tenemos que aprender a utilizarlo.


Utilizar las funciones de un mdulo
Existen varias maneras de importar funciones de un mdulo para poder utilizarlas en
nuestro programa. La primera es utilizando simplemente la sentencia import seguida del
nombre del mdulo. A partir de ese punto, las funciones del mdulo ya estarn accesibles.
No obstante la sintaxis para usar esas funciones no es tan directa como cuando estn
definidas en el propio programa. Cuando se llama a la funcin, es necesario escribir
delante del nombre de la funcin y separado por un punto el nombre del mdulo al que
pertenece. Observa el siguiente ejemplo:
>>> import mod_pintar
>>> mod_pintar.pinta_linea(10,"*")
**********

Despus de la sentencia import se escribe el nombre del mdulo, de forma que se


importan todas las funciones contenidas en el mismo. A la hora de importar un mdulo
no hay que poner la extensin .py. La extensin del fichero no forma parte del nombre
mdulo. Para utilizar una funcin del mdulo, fjate en que se debe indicar el nombre del
mdulo seguido de un punto y finalmente el nombre de la funcin. Esto puede resultar
un poco engorroso cuando se van a utilizar mucho estas funciones, as que tenemos una
alternativa:
>>> from mod_pintar import *
>>> pinta_linea(10,"*")
**********

En este caso tambin se importan todas las funciones, pero ahora, para utilizarlas no es
necesario poner el nombre del mdulo ni el punto.
Sin embargo, no siempre necesitamos importar todas las funciones de un mdulo, puesto
que nuestro programa, seguramente, no va a utilizarlas todas. Cuando estamos en esta
situacin, tenemos la opcin de poder elegir las funciones que queremos importar:
>>> from mod_pintar import pinta_linea, pinta_rectangulo
>>> pinta_linea(10,"*")
**********
>>> pinta_rectangulo(4,10,"*")
**********
**********
**********
**********

Como norma general, sin embargo, no se recomienda el uso de from para importar
nombres de funcin, como se acaba de ver, sino el uso del import del mdulo aunque
despus haya que repetir el nombre del mdulo delante de cada llamada a la funcin.
Esto es as por una razn. Es posible que diferentes mdulos implementen funciones
con el mismo nombre (aunque hagan diferentes cosas). Por ejemplo, puede haber un
mdulo especializado en el procesamiento de ficheros con grficos (llammosle el mdulo
grafico), y otro para ficheros de audio (llammosle el mdulo audio). Es probable
que ambos mdulos tengan una funcin cargar para leer del disco datos (imgenes
o sonidos, respectivamente). Sin embargo estas funciones son diferentes, ya que una
se especializa en formatos grficos y la otra en formatos de audio. Usando la sintaxis
modulo.funcion no hay equvoco posible, ya que una se llamara imagenes.cargar
y la otra audio.cargar.
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 75

Cuando importamos un mdulo, Python crea un fichero que se llama como el mdulo
pero con la extensin .pyc. Este fichero es una versin que python ha creado la primera
vez que ha cargado ese mdulo, tras comprobar que no contiene errores sintcticos. El
fichero .pyc contiene un cdigo binario especial, que python puede cargar ms rpida-
mente pues no necesita comprobar de nuevo la correccin sintctica. Si lo eliminamos
no pasar nada y la siguiente vez que se cargue el mdulo se volver a crear.
Mdulos existentes
Como ya se ha comentado son muchos los mdulos existentes para trabajar en Python.
Por ejemplo, el mdulo math contiene las funciones matemticas clsicas y random
funciones que generan nmeros pseudoaleatorios.
Hay otros mdulos que son ms especficos y se centran en problemas concretos, como
por ejemplo:

Interfaces grficas wxPython, pyGtk, pyQT, . . .


Bases de datos MySQLdb, pySQLite, cx_Oracle, . . .
Imagen PIL, gdmodule, VideoCapture, . . .
Ciencias scipy, numarray, NumPy, . . . Este ltimo, el NumPy lo estudiaremos ms
adelante, ya que nos permite trabajar con vectores multidimensionales de una forma
muy cmoda
Videojuegos Pygame, Soya 3D, pyOpenGL, . . .
Sonido pySonic, pyMedia, pyMIDI, . . .

Existen tambin mdulos de geolocalizacin, de puertos (USB, serie, paralelo, . . . ), pa-


ra programacin de dispositivos mviles, Web, programas de mensajera y casi para
cualquier cosa que podamos imaginarnos.

2.5.9. Ejercicios resueltos


[Ejercicio 1] Implementar una funcin que retorne cierto cuando un nmero sea primo y falso
en caso contrario.
1 def primo(num):
2 """esta funcion recibe un numero y retorna True si el
3 numero es primo y False si no lo es"""
4 es_primo = True
5 if num < 2: # el primer primo es el 2
6 es_primo = False
7 div = 2
8 # se debe buscar hasta la raiz cuadrada de num
9 while div <= int(num**0.5) and es_primo:
10 if num % div == 0: # si se encuentra un numero que lo divide
11 es_primo = False # entonces no es primo
12 div = div + 1
13 return es_primo

[Ejercicio 2] Utilizando la funcin implementada en el ejercicio anterior, implementar una


funcin que reciba los extremos de un intervalo de nmeros naturales y muestre en pantalla todos
los nmeros primos contenidos en ese intervalo. Adems, la funcin retornar la cantidad de nmeros
primos que hay en el intervalo o None si el intervalo no es correcto.
1 div = div + 1
2 return es_primo
2.5 Definicin y uso de subprogramas y funciones. mbito de variables 76

3
4 def muestra_primos(ini, fin):
5 """recibe los extremos de un intervalo de numeros naturales y retorna
6 cantidad de numeros primos contenidos en el intervalo. Ademas, muestra en
7 pantalla los numeros primos encontrados. En caso de que el intervalo no
8 este bien definido retornara None"""
9 if ini > fin or ini < 1:
10 return None # si no son naturales o el intervalo no esta bien
11 else:
12 cont = 0
13 i = ini
14 while i <= fin: # para cada elemento del intervalo
15 if primo(i): # se comprueba si es primo
16 cont = cont + 1

[Ejercicio 3] Se pide una funcin que, dada la longitud de los tres lados de un tringulo, retorne
1 si es equiltero, 2 si es issceles o 3 si es escaleno.
1 def tipo_triangulo(a,b,c):
2 """dada la longitud de los lados de un triangulo la funcion
3 retorna: 1) si es equilatero
4 2) si es isosceles
5 3) si es escaleno"""
6 if (a==b) and (b==c):
7 return 1
8 elif (a==b) or (a==c) or (b==c):
9 return 2
10 else:
11 return 3

[Ejercicio 4] Implementar una funcin que retorne el factorial de un nmero natural.


1 def factorial(n):
2 """Esta funcion retorna el factorial del numero que se
3 le pasa como parametro"""
4 resultado = 1
5 i = 1
6 while i <= n:
7 resultado = resultado * i
8 i = i + 1
9 return resultado

2.5.10. Ejercicios
[Ejercicio 1] Implementar una funcin que pinte un rectngulo hueco.
>>> pinta_rectangulo_hueco(4,10,"*")
**********
* *
* *
**********

[Ejercicio 2] Implementar una funcin que calcule el valor absoluto de un nmero.


>>> valor_absoluto(-10)
10
Pm 2
[Ejercicio 3] Implementar una funcin que calcule s = i=n i
>>> suma_cuadrados(2,4)
29
2.6 Ficheros 77

[Ejercicio 4] Para calcular el Binomio de Newton se utiliza la siguiente frmula:


! !
n n! 5
= , por ejemplo = 10 (2.1)
k k!(n k)! 3

implementa una funcin que lo resuelva.


>>> binomio_newton(5,3)
10

[Ejercicio 5] Implementar una funcin que muestre en pantalla la tabla de multiplicar de un


determinado nmero.
>>> tabla_multiplicar(3)
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
3 x 10 = 30

2.6. Ficheros
Los datos utilizados por los programas que hemos hecho hasta el momento no se conservan
indefinidamente, sino nicamente durante el tiempo de ejecucin. Cuando termina la ejecucin del
intrprete que lee y ejecuta nuestro programa esos datos dejan de existir desde un punto de vista
prctico as que, si necesitamos usarlos ms tarde, tendremos que volver a calcularlos de nuevo. Sin
embargo, existe la posibilidad de conservar esos datos de forma permanente, incluso tras apagar el
ordenador. Para ello los programas pueden hacer uso de ficheros que permiten guardar los datos
fuera de la memoria del ordenador, tpicamente en un dispositivo como un disco duro, un lpiz de
memoria, etc. De esta manera un programa puede salvar los datos que se deban conservar entre
ejecuciones, e incluso puede hacer uso de los datos guardados por otros programas; el uso de ficheros
es una de las formas ms obvias y sencillas de intercambio de informacin entre programas.
Los datos pueden almacenarse en ficheros utilizando su representacin interna (en binario),
aunque en estos apuntes nos limitaremos a presentar el manejo de ficheros de texto, es decir,
aquellos que contienen la informacin en forma de cadenas de caracteres y que, por tanto, pueden
leerse perfectamente en cualquier editor simple de textos, como Textedit, gEdit, o el bloc de notas.
2.6.1. Apertura y lectura de ficheros
Podemos pensar en los ficheros como si fuesen cuadernos de notas. As, para poder usar un
cuaderno primero lo debemos abrir, a continuacin podemos leer y/o escribir en l y, cuando
hayamos terminado, lo debemos cerrar.
De igual forma, para que un programa pueda acceder al contenido de un fichero, ste debe ser
previamente abierto. Para ello se debe utilizar la funcin open(), a la que hay que suministrar dos
parmetros, que sern dos cadenas de caracteres indicando:

El nombre del fichero al que queremos acceder

El modo en el que vamos a abrir el fichero. Esta cadena puede tener los siguientes valores

"r" para abrir un fichero con permiso de lectura. Si el fichero no existe se produce un
error.
2.6 Ficheros 78

"w" para abrir un fichero con permiso de escritura. Si el fichero no existe se crea uno
vaco y si ya existe se reescribe su contenido.
"a" para abrir un fichero con permiso de escritura, de forma que lo que escriba el
programa se aade al contenido previo del fichero.

Para saber ms. . .


Hay ms modos de apertura, como por ejemplo para permitir el acceso de lectura y
escritura simultneas a un fichero, pero su utilidad excede los requisitos de este curso.

Lo que retorna la llamada a la funcin open() debe asociarse a una variable que, en caso de
que la operacin de apertura tenga xito, hace referencia al fichero recin abierto. Un ejemplo de
uso puede verse a continuacin:
>>> f = open("datos.txt","r")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: datos.txt

En este caso el intrprete muestra un error puesto que el fichero que pretendamos abrir para
leer no existe. Para poder presentar las operaciones de lectura supongamos que hemos creado con
el bloc de notas un fichero con el nombre "datos.txt", que contiene un par de lneas de texto tal
como muestra la figura.

Una vez creado el fichero podemos abrirlo en modo lectura y, a continuacin leer la primera
lnea y mostrarla en la consola. Esto es lo que hace el cdigo que se muestra a continuacin:
>>> f = open("datos.txt", "r")
>>> lin = f.readline()
>>> print "Texto:", lin
Texto: En un lugar de la Mancha

>>>

Con readline() se lee toda una lnea completa del fichero, incluyendo el carcter de salto de
lnea final (\n), si existe. Por esa razn al imprimir en consola la cadena asociada a lin aparece a
continuacin del texto una lnea en blanco, debida a la impresin del carcter de salto de lnea. Lo
que en realidad se est imprimiendo es la cadena "En un lugar de la Mancha\n".
Cuando se abre un fichero el sistema establece un indicador de posicin que se sita al principio
de su contenido. Las sucesivas operaciones de lectura hacen que ese indicador vaya avanzando a
2.6 Ficheros 79

medida que se va leyendo el resto de la informacin. As, si repetimos la operacin de lectura con
readline() obtenemos la segunda lnea del texto8 :
>>> lin = f.readline()
>>> print "Texto:", lin
Texto: de cuyo nombre no quiero acordarme
>>> f.close()
>>>

Finalmente, cerramos el fichero con close(), algo que siempre debemos hacer cuando ter-
minamos de usar un fichero, de igual forma que cerraramos un cuaderno de notas tras haberlo
utilizado.
El bucle for para leer ficheros por lneas
Una forma ms compacta de leer un fichero lnea a lnea es mediante la iteracin sobre variable
del fichero con un bucle for. El cdigo que se muestra a continuacin define una funcin que, dado
un nombre de fichero, cuenta y retorna el nmero de lneas en blanco que contiene:
1 def cuenta_lineas_blanco(nombre_fichero):
2 contador = 0
3 f=open(nombre_fichero, "r")
4 for l in f:
5 if len(l.strip()) == 0:
6 contador = contador + 1
7 return contador
8
9 print "Lineas en blanco:", cuenta_lineas_blanco("datos.txt")

El bucle for asigna en cada iteracin una lnea del fichero a la variable l. El algoritmo imple-
mentado podra leerse como para cada lnea del fichero, si su longitud es cero, entonces es que se
trata de una lnea en blanco y, por tanto, hay que aumentar en una unidad el contador de lneas
en blanco. Como curiosidad cabe destacar que esta funcin contar como lneas en blanco aquellas
cuyos nicos caracteres sean espacios, aunque realmente su longitud no sea 0. Esta funcionalidad se
consigue utilizando strip() sobre la cadena leda, l, ya que as eliminamos los espacios iniciales
y finales, as como el salto de lnea de la cadena (lnea 5). Una vez eliminados, si la longitud es 0
significa que no haba ningn otro carcter y, efectivamente, era una lnea en blanco que debe ser
contada.
Lectura de caracteres
Python dispone de otros mecanismos de lectura que nos permiten dosificar la cantidad de infor-
macin que queremos leer en cada acceso al fichero. Para ello podemos utilizar read(), que lleva
un parmetro opcional indicando el nmero de caracteres que deseamos leer.
1 def cuenta_espacios(fichero):
2 contador = 0
3 f = open(fichero, "r")
4 c = f.read(1)
5 while c != "":
6 if c == " " :
7 contador = contador + 1;
8 c=f.read(1)
9 f.close()
10 return contador
11
12 print "Total:", cuenta_espacios("datos.txt"), "espacios"

8
En este ejemplo el ltimo carcter del fichero es la letra e, es decir, la ltima lnea del fichero no termina con un
salto de lnea y por eso no aparece en la consola la lnea en blanco que apareca al imprimir la primera lnea.
2.6 Ficheros 80

La funcin cuenta_espacios() lee carcter a carcter el fichero cuyo nombre se pasa como
parmetro y cada vez que se encuentra un espacio aumenta un contador cuyo valor retorna al final
del proceso. La lectura debe detenerse cuando se llegue al final del fichero, que se detecta porque la
funcin de lectura devuelve la cadena vaca (lnea 5).
IMPORTANTE
Las funciones read() y readline() devuelven la cadena vaca cuando se alcanza
el final del fichero. Comprobando el valor que retornan podemos saber cuando hemos
recorrido todo el fichero.

Si se omite el parmetro de read() entonces se obtiene una nica cadena con todo el contenido
del fichero, tal como muestra el siguiente ejemplo:
>>> f = open("datos.txt", "r")
>>> datos = f.read()
>>> datos
En un lugar de la Mancha\nde cuyo nombre no quiero acordarme
>>>

En el ejemplo esa cadena se asocia a la variable datos que, como se puede ver al mostrar su
contenido, tiene un salto de lnea entre la palabra Mancha y la palabra de. Si se imprime esta
cadena con print el salto de linea se hace efectivo en la consola y podemos ver las dos lneas que
contiene el fichero.
>>> print "Contenido del fichero:\n", datos
Contenido del fichero:
En un lugar de la Mancha
de cuyo nombre no quiero acordarme
>>>

ATENCIN
La posibilidad de cargar todo un fichero en una sola operacin de lectura debe utilizarse
con precaucin ya que, si ste es de gran tamao, se podra sobrepasar la capacidad de
almacenamiento en memoria y el programa no funcionara.

2.6.2. Escritura en ficheros


Para escribir texto en un fichero necesitamos, en primer lugar, abrir el fichero en modo escritura.
En este caso, si el fichero no existe, se crea uno nuevo, y si ya existe entonces se sobrescribe (por
tanto, se pierde) su contenido. A continuacin podemos efectuar operaciones de escritura de cadenas
de caracteres con write(). Ntese que la operacin de escritura no aade separador de lneas, as
que si queremos escribir una lnea completa debemos incluir al final de la cadena el salto de lnea,
tal como se muestra en este ejemplo:
>>> f = open("texto.txt","w")
>>> f.write("Esta es la primera\n")
>>> f.write("Esta es la segunda\n")
>>> f.close()

Dado que los mecanismos de manejo de ficheros en Python estn orientados a ficheros de cadenas
de caracteres, si necesitamos almacenar valores de otro tipo debemos convertirlos previamente a
cadenas. Por ejemplo, el programa siguiente pide por teclado nmeros hasta que se escriba la
palabra fin, y almacena en un fichero los pares y en otro los impares:
2.6 Ficheros 81

1 def es_par(n):
2 return n % 2 == 0
3
4 def pide_numero():
5 print "Introduce un numero entero (fin para terminar):",
6 n = raw_input()
7 if n == "fin":
8 return None
9 else:
10 return int(n)
11
12 fpares = open("pares.txt", "w")
13 fimpares = open("impares.txt", "w")
14 n = pide_numero()
15 while (n != None):
16 num_a_cadena = " %d\n" % n
17 if es_par(n):
18 fpares.write(num_a_cadena)
19 else:
20 fimpares.write(num_a_cadena)
21 n = pide_numero()
22 fpares.close()
23 fimpares.close()

En la linea 10, dentro de la funcin pide_numero(), se realiza la conversin a entero de la


cadena tecleada por el usuario. Esta conversin es necesaria para luego poder comprobar si el nmero
es par o impar. Posteriormente, a la hora de escribir el nmero en el fichero correspondiente, tenemos
que convertirlo de nuevo en una cadena de caracteres y aadirle el salto de lnea. Esa conversin se
realiza en la lnea 16, asignando el resultado a la variable num_a_cadena.
Si ahora queremos hacer un programa que lea los dos ficheros creados por el programa anterior
y que calcule el valor medio de los nmeros pares y de los impares entonces podramos programar
lo siguiente:
1 def calcula_media(nombre):
2 suma = 0
3 contador = 0
4 fichero = open(nombre, "r")
5 num_str = fichero.readline()
6 while num_str != "":
7 suma = suma + int(num_str)
8 contador = contador + 1
9 num_str = fichero.readline()
10 fichero.close()
11 return float(suma)/contador
12
13 print "La media de los pares es", calcula_media("pares.txt")
14 print "La media de los impares es", calcula_media("impares.txt")

Observa que tenemos que hacer la conversin a nmero entero de cada uno de los nmeros en
formato cadena ledos del fichero, tal como se hace en la lnea 7. Este programa hace adems otra
conversin necesaria para obtener un resultado correcto, que es la de convertir la variable suma
a nmero real, de forma que la divisin de la lnea 11 devuelva un nmero real y no trunque el
resultado a un nmero entero.
2.6.3. Un ejemplo prctico: agenda de direcciones
En esta seccin vamos a presentar una pequea aplicacin en la que usaremos lo aprendido sobre
ficheros para almacenar una simple agenda de contactos.
1 def nueva_entrada():
2 """Incorpora una nueva entrada a la agenda con los datos que se
2.6 Ficheros 82

3 piden al usuario por teclado"""


4 print "Nombre:",
5 nombre = raw_input()
6 print "Apellidos:",
7 apellidos = raw_input()
8 print "Tel:",
9 telefono = raw_input()
10 print "Correo electronico:",
11 email = raw_input()
12 # abrimos el fichero para incorporar la nueva entrada
13 agenda = open("agenda.txt", "a")
14 escribir_entrada(agenda, nombre, apellidos, telefono, email)
15 agenda.close()
16
17 def borrar_entrada():
18 """Pide un nombre y apellidos y crea una nueva agenda a partir de la original
19 en la que se copian todos los contactos excepto ese"""
20 print "Introduce nombre y apellidos del contacto a eliminar"
21 print "Nombre:",
22 nombre_borrar = raw_input()
23 print "Apellidos:",
24 apellidos_borrar = raw_input()
25 # abrimos el fichero para leer las entradas y copiarlas
26 # a otro fichero, excepto la que queremos eliminar
27 agenda = open("agenda.txt", "r")
28 agenda_bis = open("agenda.copia.txt", "w")
29 nombre, apellidos, telefono, email = leer_entrada(agenda)
30 while nombre != "":
31 if nombre == nombre_borrar and apellidos == apellidos_borrar:
32 print "Borrando %s, %s" % (apellidos_borrar, nombre_borrar)
33 else:
34 escribir_entrada(agenda_bis, nombre, apellidos, telefono, email)
35 nombre, apellidos, telefono, email = leer_entrada(agenda)
36 agenda.close()
37 agenda_bis.close()
38 # la copia de la agenda sin la entrada pasa a ser la agenda original
39 copiar_agenda("agenda.copia.txt", "agenda.txt")
40
41 def buscar_entrada():
42 """Busca una entrada en la agenda cuyo nombre y apellidos coincidan con los que
43 se piden por teclado"""
44 print "Introduce nombre y apellidos del contacto a buscar"
45 print "Nombre:",
46 nombre_buscar = raw_input()
47 print "Apellidos:",
48 apellidos_buscar = raw_input()
49 agenda = open("agenda.txt", "r")
50 encontrado = False
51 fin_de_fichero = False
52 while not encontrado and not fin_de_fichero:
53 nombre, apellidos, telefono, email = leer_entrada(agenda)
54 encontrado = (nombre == nombre_buscar) and (apellidos == apellidos_buscar)
55 fin_de_fichero = (nombre == "")
56 if nombre == nombre_buscar:
57 imprimir_entrada(nombre, apellidos, telefono, email)
58 else:
59 print "Contacto no encontrado!!"
60 agenda.close()
61
62 def copiar_agenda(origen, destino):
63 """Copia el fichero cuyo nombre se pasa como primer argumento en otro
2.6 Ficheros 83

64 fichero cuyo nombre se pasa como segundo argumento"""


65 agenda = open(origen, "r")
66 agenda_copia = open(destino, "w")
67 todo = agenda.read()
68 agenda_copia.write(todo)
69 agenda.close()
70 agenda_copia.close()
71
72 def leer_entrada(agenda):
73 """Lee una entrada del fichero que se le pasa como argumento y devuelve
74 las cadenas sin el salto de linea del final"""
75 nombre = agenda.readline()
76 apellidos = agenda.readline()
77 telefono = agenda.readline()
78 email = agenda.readline()
79 return nombre.strip(), apellidos.strip(), telefono.strip(), email.strip()
80
81 def con_salto(cadena):
82 """Concatena un salto de linea a la cadena que se le pasa como argumento"""
83 return cadena + "\n"
84
85 def escribir_entrada(agenda, nombre, apellidos, telefono, email):
86 """Escribe una entrada en el fichero que se le pasa como primer argumento"""
87 agenda.write(con_salto(nombre))
88 agenda.write(con_salto(apellidos))
89 agenda.write(con_salto(telefono))
90 agenda.write(con_salto(email))
91
92 def imprimir_entrada(nombre, apellidos, telefono, email):
93 """Imprime una entrada en pantalla"""
94 print "\n\n"
95 print "DATOS DEL CONTACTO"
96 print "=================="
97 print "Nombre:", nombre
98 print "Apellidos:", apellidos
99 print "Telefono:", telefono
100 print "Correo electronico:", email
101 print "\n\n"
102
103 def menu():
104 salir = False
105 while not salir:
106 print "\n\n"
107 print "*******************"
108 print "PyAgenda 1.0"
109 print "*******************"
110 print "1) Nueva entrada"
111 print "2) Borrar entrada"
112 print "3) Buscar"
113 print " "
114 print "q) Salir de PyAgenda"
115 print "*******************"
116 opcion = raw_input()
117 if opcion == "1":
118 nueva_entrada()
119 elif opcion == "2":
120 borrar_entrada()
121 elif opcion == "3":
122 buscar_entrada()
123 elif opcion == "q":
124 salir = True
2.6 Ficheros 84

125 else:
126 print "Opcion desconocida!!\n\n"
127
128
129 print "PyAgenda 1.0"
130 menu()
131 print "Adios!"

La ejecucin del programa consiste en invocar a la funcin menu(), que muestra las opciones
disponibles y, dependiendo de lo que el usuario escoja, llama a la funcin apropiada para aadir,
borrar o buscar una entrada en la agenda, o bien abandonar el programa.
La funcin nueva_entrada() pide por teclado los datos del nuevo contacto a aadir y, a
continuacin, abre el fichero en modo aadir ("a") y escribe los campos haciendo uso de una
funcin auxiliar, escribir_entrada(), que incluye al final de cada cadena el salto de lnea
necesario para distinguir los campos cuando vayamos a leerlos.
La funcin borrar_entrada() pide al usuario el nombre y apellidos del contacto que desea
eliminar y luego crea una copia de la agenda en otro fichero con todos los contactos excepto el que
se desea borrar. Finalmente, el segundo fichero que ya no contiene el contacto eliminado, se copia
sobre el fichero de agenda original. Esta funcin lee una a una las entradas de la agenda mediante
la funcin leer_entrada(), que retorna los cuatro campos de un contacto sin el salto de lnea
al final. Esto facilita la comparacin con cadenas introducidas por teclado que no llevan al final el
delimitador y simplifica su uso para imprimir mensajes formateados en la consola. Cada una de las
entradas ledas se escribe en el fichero copia, excepto aquellas cuyo nombre y apellidos coincidan
con los indicados por el usuario para ser eliminados. La ltima instruccin de esta funcin es una
llamada a la funcin auxiliar copiar_agenda(), que abre el fichero cuyo nombre se indica como
primer parmetro, carga todo su contenido en una cadena y la vuelca en un segundo fichero, con el
nombre indicado por el segundo parmetro.
La operacin de bsqueda est implementada en la funcin buscar_entrada(), que pide el
nombre y apellidos del contacto a buscar y luego abre y recorre cada entrada de la agenda hasta
que, o bien se encuentra el contacto, o bien se alcanza el final del fichero. Al abandonar el bucle
de bsqueda, si el contacto se ha encontrado se imprimen sus datos por consola, y si no se ha
encontrado se muestra un mensaje de aviso.
2.6.4. Ejercicios propuestos
[Ejercicio 1] Haz una funcin que tome como parmetros un nombre de fichero y una palabra
e imprima las lneas de dicho fichero que contienen esa palabra. Nota: python dispone del
operador booleano in que no se haba explicado. Cuando se aplica entre dos cadenas, produce
como resultado True si la primera aparece dentro de la segunda. Por ejemplo "algo" in
"algoritmo" es True mientras que "algo" in "ordenador" es False.

[Ejercicio 2] Haz una funcin encripta_fichero() que cifre un fichero grabando el resultado
en otro fichero. Los parmetros de la funcin sern el nombre del fichero origen y del fichero
destino. El algoritmo de cifrado ser muy simple: cada carcter se sustituir por el siguiente
en la tabla de caracteres. Para ello necesitars hacer uso de las funciones ord(), que retornan
la posicin en la tabla de un carcter que se pasa como argumento, y chr(), que retorna el
carcter de que ocupa la posicin que se le pasa como argumento.

[Ejercicio 3] Haz una funcin desencripta_fichero() capaz de descifrar los ficheros encrip-
tados generados por la funcin del ejercicio anterior.

[Ejercicio 4] Ampliacin al programa agenda.py: corrige el programa para que cuando se intro-
duzca una entrada ya existente se reemplacen sus datos, en vez de aadir un nuevo contacto.
2.7 Tipos y estructuras de datos bsicas: listas y arrays 85

[Ejercicio 5] Ampliacin al programa agenda.py: Mejora la funcin de bsqueda de forma que,


cuando el usuario quiera buscar una entrada se le pida el texto a buscar y el programa muestre
todas las entradas de la agenda en las que algn campo coincida, aunque sea parcialmente,
con el texto introducido (el operador in de cadenas te ser de gran ayuda).

2.7. Tipos y estructuras de datos bsicas: listas y arrays


La mayor parte de los lenguajes de programacin aparte de trabajar con los tipos bsicos de datos
tales como los nmeros, los caracteres, etc., implementan otras estructuras que permiten trabajar
con cantidades de informacin ms amplias. En matemticas o en fsica, estamos acostumbrados a
tratar con vectores o matrices, que son una coleccin de valores agrupados bajo un solo nombre.
Por ejemplo, para representar las coordenadas de un punto en el espacio se suelen usar vectores.

v = (3, 4, 0)
o para representar los trminos de un sistema de ecuaciones podemos hacer uso de las matrices.

1 3 7
A= 2 1 0

1 3 2
El vector v o la matriz A representan a todo el conjunto de datos, pero tambin se puede
referenciar a cada uno de los datos particulares, en este caso, mediante ndices.

v2 = 4 , A1,3 = 7
Los lenguajes de programacin modernos implementan varios tipos de estructuras que agrupan
colecciones de datos bajo un solo nombre de variable. Las listas, los arrays, las cadenas de texto, los
diccionarios o los conjuntos son algunos de los tipos estructurados ms usuales.
Las listas de Python engloban conjuntos de datos que pueden ser de distintos tipos (y en este
sentido pueden ser usadas de forma similar al tipo de datos denominado estructura o registro en
otros lenguajes, y del que Python carece), mientras que los arrays agrupan datos que necesariamente
han de ser todos del mismo tipo, y a los que se da el nombre de componentes. Las cadenas, de las
que ya hemos visto numerosos ejemplos, por su uso habitual tienen un tratamiento especial en todos
los lenguajes. En cuanto a los tipos diccionario y conjunto no se vern en esta asignatura.
En Python, el tipo lista se denomina list y permite implementar directamente agrupaciones de
datos en los que cada dato ocupa una posicin dentro de la agrupacin. Su longitud es variable y de
hecho, se pueden aadir o quitar elementos en cualquier momento. Cada elemento de la lista puede
ser de cualquier tipo (incluso otras listas). El acceso a cada elemento particular se realiza a travs
de ndices (que comienzan en la posicin 0 y no en 1 como es tradicional en fsica o matemticas).
Las cadenas tienen su propio tipo asociado str y en Python se implementan como un tipo
especial de lista, por lo que comparten la mayor parte de sus caractersticas.
Los vectores y matrices se representan mediante el tipo ndarray, que viene implementado en
la librera numpy. Pueden ser unidimensionales (vectores) o multidimensionales (matrices) aunque
en este texto no iremos ms all de la dimensin 2. Su longitud, en cuanto al nmero de elementos,
o su forma (nmero de filas y/o columnas) es tambin variable. El acceso a los elementos se realiza
igualmente a travs de ndices.
Veamos con detenimiento estos tres tipos estructurados de datos.
2.7.1. El tipo list
El tipo list se introduce simplemente encerrando entre corchetes la lista de datos, separados
por comas. Por ejemplo
2.7 Tipos y estructuras de datos bsicas: listas y arrays 86

>>> lista = [velocidad, 17, 3.1416]

Esto crea un recipiente al cual se le pone el nombre lista, y en dicho recipiente se reserva
espacio para tres datos. En cada uno de los huecos reservados se pone cada uno de los datos, en
este caso la cadena velocidad y los nmeros 17 y 3.1416.
Tambin es posible representar el vector v anterior mediante una lista. En este caso todos los
elementos son del mismo tipo.
>>> v = [3, 4, 0]

Una vez creada qu podemos hacer con una lista? Algunas de las operaciones bsicas que
Python trae de fbrica son:

Contar cuntos elementos tiene la lista. Basta usar la funcin len


>>> len(lista)
3

Calcular la suma de todos los elementos, usando la funcin sum, si todos los elementos son
numricos (enteros o reales):
>>> sum(v)
7

Encontrar el mximo o el mnimo de los elementos (igualmente tiene sentido si todos son
numricos). Para ello usamos las funciones max y min:
>>> max(v)
4
>>> min(v)
0

Imprimir la lista completa, con print:


>>> print lista
[velocidad, 17, 3.1416]
>>> print v
[3, 4, 0]

Ordenar la lista, devolviendo como resultado una nueva lista, que podemos imprimir o alma-
cenar en otra variable (la lista original no se modifica, mantendr el orden que tena):
>>> print v
[3, 4, 0]
>>> print sorted(v)
[0, 3, 4]
>>> print v
[3, 4, 0]
>>> v_ordenada = sorted(v)
>>> print v_ordenada
[0, 3, 4]

Concatenar listas. Si usamos el operador + entre dos listas, lo que ocurre es que se crea una
nueva lista concatenando ambas. Esta nueva lista se puede imprimir o asignar a otra variable.
Las listas originales no son modificadas. Ejemplo:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 87

>>> print v
[3, 4, 0]
>>> print v+v
[3, 4, 0, 3, 4, 0]
>>> otra = v + [100]
>>> print otra
[3, 4, 0, 100]
>>> print v
[3, 4, 0]

Observa que en el ejemplo anterior, el valor [100] es otra lista, con un solo elemento, por lo
que el operador + concatenar ambas listas. Si hubiramos puesto en cambio v+100 estaramos
intentando sumar un tipo lista (la variable v) con un tipo entero (el dato 100). El operador
+ no funciona si sus dos operandos no son del mismo tipo, por lo que tendamos un error.

Asignar otro nombre a la lista, mediante el operador de asignacin =. Al hacer por ejemplo
q=v, tendremos dos nombres (q y v) para referirnos a la misma lista:
>>> print v
[3, 4, 0]
>>> q = v
>>> print q
[3, 4, 0]

Ms adelante en este tema veremos qu ocurre exactamente con el operador de asignacin y


qu consecuencias tiene al tratar con listas.

Hay ms operaciones predefinidas para listas, pero estas son suficientes. La cuestin es y si
queremos hacer algo con los datos de una lista que no puede hacerse con ninguna de las funciones
predefinidas? Por ejemplo, y si queremos cambiar cada elemento de la lista por su triple? o bien
y si queremos calcular la suma de los cuadrados de los elementos? etctera...
La respuesta es que en realidad podemos hacer cualquier cosa con los datos que hay en una lista
porque cada uno de esos datos sigue siendo accesible por separado, adems de poder accederse a la
lista como un conjunto a travs de su nombre. Veamos esto con detalle.
2.7.2. Acceso a los elementos individuales de la lista
Cada uno de los elementos de la lista p est accesible a travs de una variable llamada p[i],
donde i es el denominado ndice del elemento. Es como cuando en matemticas decimos que un
vector v tiene por componentes v1 , v2 , . . . , vi , . . . , vn , siendo n el nmero de componentes del vector.
En Python, al igual que en la mayora de los lenguajes de programacin (Java, C, etc.), y a
diferencia de lo habitual en matemticas, los ndices comienzan a numerarse desde cero, y por tanto
los n elementos de la lista p seran accesibles mediante los nombres p[0] (primer elemento), p[1]
(segundo elemento), etc... hasta p[n-1] (ltimo elemento).
Por ejemplo, considera la asignacin p=[100, 150, 30, 15], que crea una lista con cuatro
elementos. La variable p es un nombre para esa lista. Representaremos la situacin mediante la
siguiente figura:

p 100 150 30 15

Cada uno de los datos a los que apunta p puede ser accedido individualmente mediante la
sintaxis p[0], p[1], etc, como muestra la siguiente figura:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 88

p[0] p[1] p[2] p[3]

p 100 150 30 15

La expresin p[i] puede usarse como parte de cualquier expresin, y as por ejemplo p[0]+p[1]*2
producira el resultado 400, la expresin a=p[2] asignara el entero 30 a la variable a, etc.
El tipo de p[i] es el tipo del dato all contenido, de modo que por ejemplo type(p[0]) sera
int. Recuerda que en Python cada elemento de la lista podra ser de un tipo diferente, aunque en
esta asignatura no usaremos mucho esta caracterstica.
Observa que si tenemos dos nombres diferentes para una misma lista (por ejemplo, si hacemos
q=p, q se convierte en un nuevo nombre para la lista p), entonces podremos usar cualquiera de esos
nombres para acceder a los elementos que hay en ella. Es decir, tras la asignacin q=p, tendramos
la situacin de la figura:

p[0] p[1] p[2] p[3]


p
100 150 30 15
q
q[0] q[1] q[2] q[3]

Por lo que p[1] y q[1] ambos se refieren al mismo dato, el entero 150.
Las listas son objetos mutables
Esto es muy importante si usamos la expresin p[i] al lado izquierdo de una asignacin, puesto
que en este caso estaremos modificando el dato almacenado en esa posicin de la lista. Es decir, si
hacemos q[1]=3, estaremos cambiando lo que haba en q[1] (el 150) por un 3. La nueva situacin
sera:

p[0] p[1] p[2] p[3]


p
100 3 30 15
q
q[0] q[1] q[2] q[3]

Indirectamente hemos cambiado el valor de p! Si ahora usamos p[1] en cualquier expresin


(por ejemplo print p[1]) encontraremos que vale 3.
Si lo que queremos es crear una nueva lista q que inicialmente contenga los mismos valores que
p, pero que sea un objeto independiente, de modo que podamos modificar q sin afectar a p, una
posibilidad para lograrlo es la siguiente:
>>> p = [100, 150, 30, 15]
>>> q = list(p)
>>> print p
[100, 150, 30, 15]
>>> print q
[100, 150, 30, 15]

La funcin list() crea un nuevo objeto del tipo list, y carga en l los valores iniciales que
le pasemos como parmetro, que ha de ser de tipo secuencia. En este caso le estamos pasando una
lista p. A la nueva lista que resulta, que es una copia de la que haba en p, le damos el nombre
q. Al imprimir ambas vemos que tienen los mismos valores, sin embargo se trata de dos objetos
diferentes. La situacin sera la de la figura siguiente:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 89

p[0] p[1] p[2] p[3]

p 100 150 30 15

q 100 150 30 15
q[0] q[1] q[2] q[3]

Si ahora modificamos cualquier elemento de q, esto no afecta a los elementos de p, como podemos
ver:
>>> q[1] = 3
>>> print p
[100, 150, 30, 15]
>>> print q
[100, 3, 30, 15]

ya que p y q se refieren a diferentes listas.

p[0] p[1] p[2] p[3]

p 100 150 30 15

q 100 3 30 15
q[0] q[1] q[2] q[3]

Nota sobre comparacin de listas. Es posible comparar dos listas mediante el operador de
igualdad ==. Este comparador lo que har ser en primer lugar comparar la longitud de las listas,
y si resultan iguales comparar entonces uno a uno cada elemento. Si todos son iguales, el resultado
ser True. As, si hubiramos mirado si p==q antes de cambiar q[1], el resultado habra sido
True, mientras que si lo miramos de nuevo tras cambiarlo (siendo q una copia independiente de
q), el resultado sera False.
El comparador == por tanto nos dice si dos listas son iguales elemento a elemento, pero no nos
dice si son la misma. Puede ser que las dos listas sean iguales porque son en realidad la misma
(como ocurra con p y q tras hacer q=p), pero pueden ser iguales tambin si, an siendo diferentes
objetos, contienen la misma secuencia de datos.
Si queremos descubrir si las listas son en realidad la misma, podemos usar el comparador is,
en la expresin p is q. Este operador dar como resultado True slo si ambas variables apuntan
al mismo objeto. Si apuntan a objetos diferentes, el resultado ser False, aunque pueda darse el
caso de que ambos objetos sean iguales elemento a elemento.
Es decir:
>>> p = [100, 150, 30, 15]
>>> q = p
>>> r = list(p)
>>> p == q
True
>>> p == r
True
>>> p is q
True
>>> p is r
False

La situacin creada por el cdigo anterior se muestra en la siguiente figura:


2.7 Tipos y estructuras de datos bsicas: listas y arrays 90

p
100 150 30 15
q
r 100 150 30 15

Si en este momento hiciramos la asignacin p[1]=3, intenta adivinar qu resultado daran las
comparaciones p is q, p is r, p==q y p==r.
Aadir y quitar datos en una lista
Supongamos que a la lista p de los ejemplos anteriores le queremos aadir otro dato, por ejemplo
el nmero 12. La sintaxis para lograrlo es:
>>> p.append(12)

Esta sintaxis es diferente a lo que vimos hasta ahora. Ocurre que Python es un lenguaje orientado
a objetos y si bien no vamos a ahondar en esta caracterstica del lenguaje en esta asignatura, s
que nos encontraremos en algunos lugares (por ejemplo ahora), con la sintaxis relacionada con el
manejo de objetos.
En pocas palabras, un objeto es un tipo de dato que agrupa bajo una misma estructura datos
y funciones para trabajar sobre esos datos. A los datos se les denomina comunmente atributos, y
a las funciones mtodos. Los mtodos son las nicas funciones que tienen va libre para modificar,
si se requiere, los atributos. Aunque no lo habamos comentado hasta ahora, todos los datos en
Python son objetos (el tipo entero, el float, las cadenas, las listas, etc.) Para llamar a un mtodo
un objeto se usa la sintaxis que acabamos de ver en el ltimo ejemplo, es decir, primero el nombre
de la variable que apunta al objeto, despus un punto y despus el nombre del mtodo, seguido de
unos parntesis, dentro de los cuales van los parmetros si es que los necesita.
Como vemos la sintaxis es igual a la vista para llamar a una funcin, slo que delante del nombre
de la funcin, separada por un punto, va el nombre de una variable que seala al objeto.
En este caso, el objeto de tipo list tiene el mtodo append(12) como una forma de modificar
los contenidos de la lista, aadiendo un 12 al final de los que ya haba. El resultado ser que la lista
a la que p se refiere habr credido y tendr ahora 5 elementos en lugar de 4. Podemos imprimirla
y comprobar su nueva longitud:
>>> print p
[100,150,30,15,12]
>>> len(p)
5

La situacin, grficamente, es:


p
100 150 30 15 12
q
r 100 150 30 15

Observa que, ya que q se refera a la misma lista que p, cualquier cambio que hagamos en la lista
a travs de p se ver reflejado tambin cuando la manejemos a travs de q. En concreto len(q)
tambin ser 5. En cambio r se refera a una lista diferente (aunque inicialmente tena los mismos
datos). El aadido de un dato a travs de p no ha afectado a r, como se ve en la figura.
Otro mtodo til que un objeto tipo list tiene es extend(). A travs de este mtodo podemos
hacer crecer la lista aadindole varios elementos en lugar de uno solo (como haca append()).
Para ello, a extend() se le pasa como parmetro otra lista (o secuencia), conteniendo los elementos
que queremos aadir. Por ejemplo:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 91

>>> p.extend([1, 2, 3])


>>> len(p)
8
>>> print p
[100, 150, 30, 15, 12, 1, 2, 3]

Adems de poder pasarle una lista de valores directamente, como en el ejemplo anterior, podra-
mos haberlo hecho a travs de otra variable. Por ejemplo, si quisiramos aadir a p los elementos
que hay en la lista r, podramos poner p.extend(r). En este caso se crear una copia de la lista
r y esa se aadir a p.
Si se quieren aadir datos a una lista, pero no en el final sino en cualquier punto intermedio,
se puede conseguir haciendo uso del mtodo insert, que tiene como parmetros la posicin y el
elemento que queremos insertar en la lista. Existen otras posibilidades, como el uso de slices, pero
su explicacin queda fuera de las pretensiones de esta asignatura.
Para eliminar datos de una lista, tenemos dos posibilidades:

Si conocemos en qu posicin de la lista est el dato que queremos borrar, usamos el mtodo
pop(posicion) de la lista. Recuerda que las posiciones comienzan a numerarse desde 0 y
llegan hasta len(lista)-1. Si no se especifica la posicin (es decir, usamos simplemente
pop() sin parmetros), se eliminar el ltimo de la lista.
Adems de eliminar el dato, su valor es retornado, de modo que lo leemos a la vez que lo
eliminamos. Por ejemplo:
>>> p = [1, 3, 5, 7, 11, 13]
>>> n = p.pop()
>>> print n
13
>>> print p
[1, 3, 5, 7, 11]
>>> n = p.pop(0)
>>> print n
1
>>> print p
[3, 5, 7, 11]

Si conocemos el valor del dato, pero no en qu posicin est en la lista, podemos usar el
mtodo remove(dato). Si el dato se encuentra, es eliminado (si aparece varias veces, slo
se elimina la primera). No obstante el uso de este mtodo es un poco arriesgado, ya que si el
dato no estuviera en la lista, se generara una excepcin. Por ejemplo:
>>> p = [1, 3, 5, 7, 11, 13]
>>> p.remove(5)
>>> print p
[1, 3, 7, 11, 13]
>>> p.remove(2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

Para evitar el error, podramos comprobar si el dato efectivamente est, antes de intentar
eliminarlo. Para ello Python tiene el operador in que se usa en la expresin booleana:
dato in lista, y que devuelve True si el dato est en la lista y False si no. As que
si hacemos if 2 in p: antes de intentar p.remove(2), evitaramos que se generase la
excepcin.
2.7 Tipos y estructuras de datos bsicas: listas y arrays 92

2.7.3. Listas que contienen listas


Una lista es una serie de datos, y cada uno de estos datos puede ser de cualquiera de los tipos
que ya hemos visto. Por tanto, un dato contenido en una lista podra ser otra lista. Por ejemplo:
>>> p = [100, 200, 300, [1, 2, 3]]
>>> print p
[100, 200, 300, [1, 2, 3]]
>>> print p[0]
100
>>> print p[2]
300
>>> print p[3]
[1, 2, 3]

La estructura de datos que hemos creado en el cdigo anterior se puede representar grficamente
as:

1 2 3

p 100 200 300

Qu valor crees que obtendremos al hacer len(p)? Comprubalo en el intrprete.


Como vemos, el ltimo elemento de p no contiene un dato propiamente dicho, sino una refe-
rencia hacia otro dato que es la lista [1, 2, 3]. Esta lista de alguna forma es annima en el
sentido de que no tiene nombre (no hay una variable que se refiera a ella). Si quisiramos entonces
modificar el 1 que hay en ella y cambiarlo por un 5 cmo podramos lograrlo? Pinsalo un poco
antes de continuar leyendo.
Hemos dicho que no hay una variable que se refiera a la lista [1,2,3], pero esto no es del
todo cierto. En realidad p[3] es un nombre que se refiere a esa lista, como hemos visto al hacer
print p[3]. Y si p[3] es una lista, podremos aplicarle las mismas operaciones que a cualquier
otra lista. Por ejemplo, podemos hacer len(p[3]) (qu valor devolvera?). Y en particular, tam-
bin podemos poner unos corchetes tras su nombre y acceder as a cualquiera de sus elementos.
De modo que para cambiar el 1 por un 5 la sintaxis sera:
>>> p[3][0] = 5
>>> print p
[100, 200, 300, [5, 2, 3]]

Observa que en el ejemplo anterior, la lista [1, 2, 3] slo puede ser accedida a travs de
p[3], ya que no tenemos ninguna otra variable que se refiera a esa lista. Pero podramos tenerla.
Considera el siguiente cdigo:
>>> q = p[3]

Tras la asignacin anterior, q se convierte en otro nombre para la lista [1, 2, 3], como refleja
la siguiente figura:

q 5 2 3

p 100 200 300

A partir de esta figura, se comprende que si hacemos por ejemplo q[1]=27 estaremos modifi-
cando indirectamente el valor de p[3][1], lo cual se manifestar al imprimir p.
2.7 Tipos y estructuras de datos bsicas: listas y arrays 93

>>> q[1] = 27
>>> print q
[5, 27, 3]
>>> print p
[100, 200, 300, [5, 27, 3]]

A la misma situacin de la figura anterior habramos llegado tambin si hubieramos inicializado


p y q de este otro modo:
>>> q = [5, 2, 3]
>>> p = [100, 200, 300, q]
>>> print p
[100, 200, 300, [5, 2, 3]]

Fjate que al dar la lista de valores de p hemos usado q como uno de ellos. El efecto es que
dentro de p[3] se almacena una referencia a la misma lista a la que se refiere q. Es decir, la misma
situacin de la figura anterior. Las modificaciones que hagamos a travs de q tendrn efecto en p.
Si hubiramos querido tener en p[3] una referencia a una copia de q, en lugar de una referencia
a la misma lista que q) una forma de lograrlo habra sido:
>>> q = [5, 2, 3]
>>> p = [100, 200, 300]
>>> p.append(q)
>>> print p
[100, 200, 300, [5, 2, 3]]

Aunque el resultado parece el mismo, la situacin ahora sera la de la figura siguiente:

q 5 2 3 5 2 3

p 100 200 300

2.7.4. Bucles para recorrer listas


Como hemos dicho antes, Python trae algunas funciones tiles para realizar clculos elementales
sobre listas. Por ejemplo, la funcin sum(lista) nos devuelve la suma de todos los elementos de
una lista. Sin embargo, hay otras muchas operaciones que podramos necesitar, y que no vienen con
el lenguaje. Por ejemplo, y si quisiramos calcular la suma de los cuadrados? O crear una nueva
lista cuyos elementos sean las races cuadradas de los elementos de la lista dada? etctera...
Obviamente la solucin consiste en implementar nosotros mismos los clculos requeridos en un
bucle. En cada iteracin (repeticin) del bucle, obtendremos un elemento de la lista a procesar, con
el que realizaremos nuestros clculos.
Ya hemos visto que cada elemento de la lista es accesible a travs de un ndice, que va desde 0
hasta len(lista)-1, por lo que una estrategia directa es utilizar un bucle for sobre una variable
i que recorra el rango 0 a len(lista)-1, y dentro de l usar esa variable como ndice para acceder
a lista[i]. Precisamente este rango es el que obtenemos mediante range(len(lista)), por
lo que una implementacin directa de estas ideas sera la siguiente:
1 # Inicializamos la lista p con una serie de numeros
2 p = [4, 9, 27, 100, 110]
3
4 # Calculemos la suma de los cuadrados
5 suma_2 = 0 # de momento vale cero
6 for i in range(len(p)):
7 suma_2 = suma_2 + p[i]**2
8 print "Lista p =", p
2.7 Tipos y estructuras de datos bsicas: listas y arrays 94

9 print "La suma de los cuadrados vale", suma_2


10
11 # Creemos ahora una nueva lista que contenga las raices cuadradas de cada
12 # uno de los datos de la lista p
13 # Para calcular raices cuadradas necesitamos la funcion sqrt del modulo math
14 import math
15
16 # La nueva lista con los resultados, inicialmente vacia:
17 raices_cuadradas = []
18
19 # Rellenemos la lista anterior, mediante un bucle
20 for i in range(len(p)):
21 raices_cuadradas.append(math.sqrt(p[i]))
22 print "Raices cuadradas:", raices_cuadradas

El resultado de ejecutar el cdigo anterior sera:


Lista p = [4, 9, 27, 100, 110]
La suma de los cuadrados vale 22926
Raices cuadradas: [2.0, 3.0, 5.196152422706632, 10.0, 10.488088481701515]

Esta forma de acceder a cada elemento de una lista, a travs de su ndice, es la forma que
permiten casi todos los lenguajes de programacin (C, C++, java, etc.).
Python proporciona otra forma an ms breve para recorrer los elementos de una lista. Se trata
de usar la sintaxis siguiente:
1 for variable in lista:
2 sentencia1
3 sentencia2
4 etc...

Lo que ocurre es que la variable variable va pasando por todos los valores de la lista, por
orden. En la primera iteracin del bucle variable toma el valor de lista[0], en la siguiente
iteracin toma el valor de lista[1] y as sucesivamente hasta agotar todos los valores de la lista.
Observa que con esta sintaxis no se requieren ndices ni corchetes.
Usemos esta sintaxis para implementar de nuevo el clculo de la suma de los cuadrados y la lista
con las races cuadradas:
1 # Inicializamos la lista p con una serie de numeros
2 p = [4, 9, 27, 100, 110]
3
4 # Calculemos la suma de los cuadrados
5 suma_2 = 0 # de momento vale cero
6 for dato in p:
7 suma_2 = suma_2 + dato**2
8 print "Lista p =", p
9 print "La suma de los cuadrados vale", suma_2
10
11 # Creemos ahora una nueva lista que contenga las raices cuadradas de cada
12 # uno de los datos de la lista p
13 # Para calcular raices cuadradas necesitamos la funcion sqrt del modulo math
14 import math
15
16 # La nueva lista con los resultados, inicialmente vacia:
17 raices_cuadradas = []
18
19 # Rellenemos la lista anterior, mediante un bucle
20 for dato in p:
21 raices_cuadradas.append(math.sqrt(dato))
22 print "Raices cuadradas:", raices_cuadradas
2.7 Tipos y estructuras de datos bsicas: listas y arrays 95

Como ves, esta sintaxis es ms clara, pero ten en cuenta que es una caracterstica que en otros
lenguajes puede no estar presente (el ejemplo ms notable es el C).
Para saber ms
En realidad, la sintaxis for variable in lista no es una sintaxis alternativa para
el for, sino la nica que Python tiene. Lo que ocurre es que la funcin range() que
usbamos hasta ahora, crea una lista que contiene una serie de nmeros en secuencia,
sobre la cual despus el bucle for itera.
Puedes comprobar esto con el intrprete:
>>> numeros = range(10)
>>> type(numeros)
<type list>
>>> print numeros
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for i in numeros:
... print i,
...
0 1 2 3 4 5 6 7 8 9
>>>

2.7.5. Listas y funciones


Una funcin puede recibir como parmetro una lista, y tambin devolver una lista como resul-
tado. As, por ejemplo, podemos convertir en una funcin uno de los ejemplos antes vistos, el que
calcula la suma de los cuadrados de los elementos de una lista.
1 def suma_de_los_cuadrados(lista):
2 """Dada una lista como parametro, que contiene una serie de
3 numeros, la funcion retorna la suma de los cuadrados"""
4 suma_2 = 0 # De momento la suma es cero
5 for dato in lista:
6 suma_2 = suma_2 + dato**2
7 # Al salir del bucle tenemos el resultado, que retornamos
8 return suma_2
9
10 # Para probar el ejemplo anterior, creare una lista
11 p = [1, 2, 3, 4]
12 resultado = suma_de_los_cuadrados(p)
13 print "La lista es:", p
14 print "La suma de los cuadrados es", resultado

Al ejecutar el programa anterior, el resultado ser 30. Si necesitramos una funcin que en lugar
de la suma de los cuadrados hiciera la suma de los cubos, bastara cambiar el **2 de la lnea 6
por un **3. Esto nos lleva a plantearnos la siguiente generalizacin: Escribe una funcin llamada
P n
suma_de_las_potencias que, dada una lista {xi } calcule xi , siendo n otro valor que se le
pasa como parmetro. Se deja este problema como ejercicio para el lector.
Como hemos dicho antes, una funcin tambin puede retornar una lista como resultado. Gracias
a esto tambin podemos convertir en funcin el otro ejemplo antes visto, que a partir de una lista
dada crea otra lista que contiene las races cuadradas de cada elemento de la lista original. La
solucin sera la siguiente:
1 import math # Para poder usar la funcion sqrt
2
3 def raices_cuadradas(lista):
4 """Dada una lista como parametro, que contiene una serie de
5 numeros, la funcion retorna otra lista que contiene las
2.7 Tipos y estructuras de datos bsicas: listas y arrays 96

6 raices cuadradas de esos numeros"""


7 lista_resultado = [] # De momento esta vacia
8 for dato in lista:
9 lista_resultado.append(math.sqrt(dato))
10 # Al salir del bucle tenemos la lista_resultado rellena
11 return lista_resultado
12
13
14 # Para probar el ejemplo anterior, creare una lista
15 p = [4, 25, 16, 9]
16 resultado = raices_cuadradas(p)
17 print "La lista es:", p
18 print "Las raices cuadradas son:", resultado

Retornar una lista como resultado puede usarse para crear funciones que retornen varios resul-
tados, como un mecanismo alternativo al que se mostr en la seccin ??. Por ejemplo, una funcin
que dado un par de enteros retorna el cociente y el resto de su divisin. Podemos retornar una
lista cuyo primer elemento sea el cociente, y el segundo sea el resto, como se muestra en el listado
siguiente
1 def cociente_y_resto(a, b):
2 """Dados dos enteros, a y b, la funcion retorna una lista
3 cuyo primer elemento es el cociente entero a/b y cuyo segundo
4 elemento es el resto de dicha division"""
5 cociente=a/b
6 resto=a %b
7 return [cociente, resto]
8
9 # Probemos la funcion con un par de numeros que nos de el usuario
10 numero1=int(raw_input("Dame un entero: "))
11 numero2=int(raw_input("Dame otro: "))
12 resultado=cociente_y_resto(numero1, numero2)
13 print "El cociente es", resultado[0], "y el resto", resultado[1]

Un par de observaciones sobre el programa anterior. En primer lugar, la funcin es tan simple
que su cdigo podra haberse acortado hasta dejarla en una sola lnea, simplemente si no hacemos
uso de las variables intermedias cociente y resto, sino que ponemos directamente las expresiones
a/b y a %b en los valores a retornar. As (he omitido aqu la documentacin de la funcin, que sera
la misma que en el listado anterior):
1 def cociente_y_resto(a, b):
2 return [a/b, a %b]

En segundo lugar, cuando llamamos a la funcin y recogemos el valor retornado, lo hacemos sobre
una variable llamada resultado, y despus necesitamos acceder a resultado[0] para obtener
el cociente y a resultado[1] para obtener el resto. Esto es poco legible y puede mejorarse gracias
a una caracterstica del lenguaje Python, que nos permite asignar las listas del mismo modo que se
mostr en la para las tuplas. Si al lado izquierdo de una asignacin, en lugar de una variable hay una
lista de variables, y al lado derecho de la asignacin hay una lista de valores o expresiones, entonces
primero se evalan las expresiones del lado de la derecha, y despus cada una de las variables de la
izquierda recibir cada uno de los resultados. Esto es:
>>> [x, y, z] = [8, 3*5, 10/2]
>>> x
8
>>> y
15
>>> z
5
>>> [a, b, z] = [z, y, x]
2.7 Tipos y estructuras de datos bsicas: listas y arrays 97

Puedes adivinar qu valor tomarn las variables a, b y z tras esta ltima asignacin?
Para que este tipo de asignacin funcione, la lista de la izquierda ha de tener la misma longitud
que la lista de la derecha, y la lista de la izquierda ha de estar compuesta exclusivamente por nombres
de variables. La lista de la derecha podra ser cualquier cosa. Incluso el resultado de llamar a una
funcin! Esto nos permitira hacer, por ejemplo:
1 [cociente, resto] = cociente_y_resto(10, 3)
2 print "Cociente=", cociente, "Resto=", resto

Es decir, hemos usado [cociente, resto] en vez de resultado, por lo que despus tenemos
nombres para el cociente y para el resto en lugar de tener que acceder a ellos con la sintaxis menos
legible resultado[0], resultado[1].
En todo caso, el mtodo estndar para que una funcin retorne varios resultados es el mostrado
en la seccin ??. El que se pueda hacer de forma similar con listas es una mera curiosidad.
La funcin puede cambiar elementos en la lista que recibe como parmetro
Una consecuencia directa de que las listas son objetos mutables, y del funcionamiento del paso
de parmetros y la asignacin en Python, es que, a diferencia de lo visto hasta ahora, una funcin
puede recibir un parmetro de tipo lista y devolver la misma modificada.
Ya hemos visto en el tema de funciones que el paso de parmetros no es ms que una asignacin,
en la que se asigna a los parmetros formales (los declarados en la implementacin de la funcin)
los valores que tienen los parmetros reales (los que se ponen en la llamada a la funcin).
Teniendo esta idea clara, veamos qu pasa cuando una funcin intenta modificar el valor del
parmetro que ha recibido. Considera el siguiente ejemplo:
1 def intenta_modificar(x):
2 print " x vale", x
3 x = [0, 0, 0]
4 # Hemos cambiado el valor de x?
5 print " Ahora x vale", x
6
7 # Vamos a crear una variable a con una lista
8 a = [1, 2, 3]
9 print "a vale", a
10
11 # Llamamos a la funcion intenta_modificar, pasandole a
12 intenta_modificar(a)
13
14 # Habra cambiado el valor de a?
15 print "Ahora a vale", a

Qu crees que saldr por pantalla al ejecutar este programa? Pinsalo un instante antes de leer
la respuesta.
a vale [1, 2, 3]
x vale [1, 2, 3]
Ahora x vale [0, 0, 0]
Ahora a vale [1, 2, 3]

Como puedes ver, la funcin ha cambiado el valor de x, pero eso no ha afectado al valor de a.
Si no comprendes por qu, los siguientes esquemas pueden ayudarte a clarificar la situacin.

Instruccin Explicacin Diagrama


a = [1, 2, 3] Crea una nueva lista que contiene
los datos 1, 2 y 3, y hace que la va- a 1 2 3
riable a apunte (se refiera) a dicha
lista.
2.7 Tipos y estructuras de datos bsicas: listas y arrays 98

print a Se imprime el valor de a y obvia-


mente sale [1, 2, 3]
intenta_modificar(a) Durante la llamada a la funcin, se x
realiza la asignacin al parmetro a 1 2 3
formal, es decir x=a, lo cual crea un
nuevo nombre para la misma lista
print x Se imprime el valor de x que obvia-
mente es el mismo que el de a.
x = [0, 0, 0] Se crea una nueva lista que contiene 0 0 0
tres ceros, y se modifica x para que x
ahora apunte a esta nueva lista. Eso a 1 2 3
no afecta a a que sigue apuntando a
la antigua.
print x Se imprime el valor de x y ahora sa-
len tres ceros
(return implcito) La funcin retorna, esto hace que x
0 0 0
deje de existir. Ya que niguna otra x
variable apunta a la lista [0,0,0],
a 1 2 3
esta lista tambin ser destruida por
Python en algn momento, de forma
automtica.
print a Se imprime el valor de a y como se
ve del ltimo diagrama, sigue apun- a 1 2 3
tando a la lista original, por lo que
de nuevo sale [1, 2, 3]

Cabe destacar que todo lo explicado en este ejemplo en el que a y x son variables de tipo list,
es igualmente cierto y aplicable a cualquier otro tipo de datos en Python. En particular, esto mismo
sucede si a y x son de tipo entero. En general, sea cual sea el tipo del parmetro de una funcin,
una asignacin que se haga a ese parmetro causa que se modifique slo esa variable (haciendola
apuntar a otro lugar) y sin afectar a la variable que era el parmetro real.
Sin embargo. . . qu pasa si dentro de la funcin hacemos x[0]=0, por ejemplo? Es decir, qu
imprimira el cdigo siguiente?
1 def intenta_modificar2(x):
2 print " x vale", x
3 x[0] = 0
4 # Hemos cambiado el valor de x?
5 print " Ahora x vale", x
6
7 # Vamos a crear una variable a con una lista
8 a = [1, 2, 3]
9 print "a vale", a
10
11 # Llamamos a la funcion intenta_modificar, pasandole a
12 intenta_modificar2(a)
13
14 # Habra cambiado el valor de a?
15 print "Ahora a vale", a
2.7 Tipos y estructuras de datos bsicas: listas y arrays 99

Si te fijas, este ejemplo es idntico al anterior, salvo por la lnea 3, que antes haca x=[0,0,0] y
ahora hace x[0]=0 (bueno, y tambin que hemos renombrado la funcin a intenta_modificar2,
pero esto es irrelevante).
Si esperabas que al ejecutar este cdigo la variable a no se viera afectada, es que no lo has
pensado bien. Mira el resultado:
a vale [1, 2, 3]
x vale [1, 2, 3]
Ahora x vale [0, 2, 3]
Ahora a vale [0, 2, 3]

Al cambiar el primer elemento de x y poner all un cero, hemos afectado indirectamente a la


variable a del programa principal, que ahora tambin tiene un cero en su primer elemento! En
realidad, si has comprendido el caso del ejemplo anterior, este tiene tambin perfecto sentido. La
siguiente tabla lo explica paso a paso:

Instruccin Explicacin Diagrama


a = [1, 2, 3] Crea una nueva lista que contiene
los datos 1, 2 y 3, y hace que la va- a 1 2 3
riable a apunte (se refiera) a dicha
lista.
print a Se imprime el valor de a y obvia-
mente sale [1, 2, 3]
intenta_modificar2(a) Durante la llamada a la funcin, se x
realiza la asignacin al parmetro a 1 2 3
formal, es decir x=a, lo cual crea un
nuevo nombre para la misma lista
print x Se imprime el valor de x que obvia-
mente es el mismo que el de a.
x[0] = 0 Se modifica el primer elemento de x
la lista apuntada por x. Ya que es a 0 2 3
la misma lista a la que apuntaba a,
estamos modificando a!
print x Se imprime el valor de x y ahora sale
[0,2,3]
(return implcito) La funcin retorna, esto hace que
x deje de existir. La lista a la que a 0 2 3
apuntaba x no se destruye, porque
todava tenemos a a apuntando a
ella.
print a Se imprime el valor de a y evidente-
mente sale [0, 2, 3] a 0 2 3

Por tanto cuando se pasa una lista a una funcin, esta funcin puede modificar los elementos
almacenados en esa lista, si la funcin usa los corchetes para acceder a un elemento de la lista y le
asigna otro valor.
Esto es posible slo con listas (en general, con cualquier objeto en Python que sea mutable). Si
2.7 Tipos y estructuras de datos bsicas: listas y arrays 100

x fuese un entero, no hay forma de hacer x[0]=0 (si lo intentas dar un error, porque el operador
[] slo tiene sentido sobre listas). Y si lo que hacemos es x=0 ya hemos visto que eso simplemente
cambia la x para que apunte a un cero, sin modificar el valor al que apuntaba a.
De modo que es posible escribir funciones que modifiquen una lista in situ, es decir, sin crear
una lista nueva a partir de ella. As, podramos hacer una funcin raices_cuadradas_lista que
en lugar de crear una nueva lista con los valores de las raices cuadradas y retornar esa nueva lista,
lo que haga sea ir modificando la lista original sustituyendo cada elemento por su raz cuadrada.
Sera como sigue:
1 import math # Para poder usar la funcion sqrt
2
3 def raices_cuadradas_in_situ(lista):
4 """Dada una lista como parametro, que contiene una serie de
5 numeros, la funcion MODIFICA esa lista cambiando cada elemento
6 por su raiz cuadrada"""
7 for i in range(len(lista)):
8 lista[i] = math.sqrt(lista[i])
9 # No es necesario retornar ningun valor, ya estan todos en la lista
10
11 # Para probar el ejemplo anterior, creare una lista
12 p = [4, 25, 16, 9]
13 print "Antes de llamar, la lista es:", p
14 resultado = raices_cuadradas_in_situ(p)
15 print "Despues de llamar, la lista es:", p
16 print "El valor retornado por la funcion es", resultado

Observa que la funcin no contiene sentencia return (aunque de todas formas har un return
implcito cuando salga del bucle, ya que no hay ms instrucciones para ejecutar en la funcin). La
forma de llamar a esta funcin por tanto es distinta a la del ejemplo con raices_cuadradas,
donde hacamos resultado=raices_cuadradas(p). En aquel ejemplo la lista con las races
cuadradas era diferente de la lista p, y la variable resultado serva para apuntar a la nueva lista.
En cambio ahora la lista con las races es la propia p (sus valores originales se pierden), y la funcin
no retorna nada, por lo que asignar a resultado como hace el programa anterior no tiene sentido.
Bastaba llamar a la funcin sin asignar su resultado a ninguna variable. No obstante, si lo asignamos
como se ve en el ejemplo anterior, encontraremos que la variable resultado toma el valor especial
None, que es el valor que Python usa para representar nada. La funcin no ha retornado nada.
Al ejecutar ese cdigo veremos en pantalla:
Antes de llamar, la lista es: [4, 25, 16, 9]
Despues de llamar, la lista es: [2.0, 5.0, 4.0, 3.0]
El valor retornado por la funcion es None

Para terminar, indicar que es posible escribir programas que nunca hagan uso de esta carac-
terstica. Es decir, cualquier problema computacional se puede resolver haciendo uso de funciones
que nunca modifiquen los valores de los parmetros que reciben, sino que en vez de ello creen otros
datos nuevos y los retornen.
2.7.6. Listas y cadenas
La cadena es un tipo especial de lista
Una cadena de caracteres es un tipo especial de lista, en la que cada elemento es un carcter, esto
es, una letra, un dgito, un signo de puntuacin o un carcter de control. Por tanto, podemos usar
los mecanismos que conocemos de las listas para iterar sobre sus elementos, calcular su longitud,
concatenarlas, etc.
Por ejemplo, el siguiente cdigo cuenta cuntas letras vocales hay en la frase escrita por el
usuario:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 101

1 # Pedir al usuario un texto


2 texto = raw_input("Escribe una frase: ")
3
4 vocales = 0 # Contador de vocales halladas
5 # Recorrer letra a letra el texto
6 for letra in texto:
7 # Comprobar si es una vocal
8 # Es sencillo gracias al operador "in" ya visto para listas
9 # que tambien es aplicable a cadenas
10 if letra in "aeiouAEIOU":
11 vocales = vocales + 1
12
13 print "Tu frase tiene", len(texto), "letras"
14 print "de las cuales", vocales, "son vocales."

Sin embargo hay una diferencia fundamental entre las cadenas y las listas. Las cadenas son
inmutables, lo que significa que no podemos alterar ninguno de sus caracteres. Si bien podemos
consultar el valor de texto[i] para ver qu letra es, no podemos en cambio asignar nada a la
variable texto[i]. Si lo intentamos, obtendremos un error en tiempo de ejecucin.
Imagina que queremos programar una funcin que recibe como parmetro una cadena y queremos
que se ocupe de cambiar todas las vocales que aparezcan en dicha cadena por el signo _. Es decir, si
la cadena que recibe contiene el mensaje "Hola Mundo", el resultado debera ser "H_l_ m_nd_".
Si intentamos una versin de la funcin que modifique la cadena in situ, fracasar:
1 def cambiar_vocales(texto):
2 """Esta funcion recibe una cadena de texto como parametro
3 e intenta cambiar todas las vocales que contiene por el
4 signo _. Sin embargo, ya que las cadenas son inmutables,
5 producira un error."""
6 # Recorremos todos los indices para acceder a cada letra
7 for i in range(len(texto)):
8 # Miramos si es una vocal
9 if texto[i] in "aeiouAEIOU":
10 # Si lo es, la cambiamos. Esto es lo que dara error
11 texto[i] = "_"
12
13 # Para probar la funcion anterior creo un mensaje
14 mensaje = "Mensaje de prueba"
15
16 # Intento "borrar" sus vocales
17 cambiar_vocales(mensaje)
18
19 # Imprimo el resultado (en realidad esto nunca llegara a ejecutarse
20 # porque el programa "rompe" antes con un error)
21 print mensaje

Al ejecutar el programa anterior obtendremos un error:


Traceback (most recent call last):
File "funcion-sustituir-vocales-mal.py", line 17, in <module>
cambiar_vocales(mensaje)
File "funcion-sustituir-vocales-mal.py", line 11, in cambiar_vocales
texto[i] = "_"
TypeError: str object does not support item assignment

La solucin consiste en hacer una funcin que, en lugar de modificar la cadena, crea una cadena
nueva que va construyendo letra a letra, copiando cada letra de la cadena original, salvo si es una
vocal en cuyo caso inserta el carcter "_". Pero aparentemente esto tampoco puede hacerse, ya
que al ser las cadenas datos inmutables, carecen tambin del mtodo .append() para poder ir
aadiendo caracteres. Entonces?
2.7 Tipos y estructuras de datos bsicas: listas y arrays 102

La respuesta es que, aunque efectivamente no puedo aadir caracteres a una cadena dada, s
puedo crear una nueva cadena como la suma de dos (concatenacin), y asignar el resultado de esta
concatenacin a la misma variable. Por ejemplo:
>>> texto="Prueba"
>>> texto
Prueba
>>> texto = texto + "s"
>>> texto
Pruebas

Puede parecer que hemos aadido una letra "s" a la cadena. En realidad lo que ha ocurrido es
que hemos creado una cadena nueva, que contiene "Pruebas", pero sin afectar a la cadena original
que sigue conteniendo "Prueba". Despus hacemos que la variable texto se refiera a esta nueva
cadena. La cadena original ya no tiene variable que se refiera a ella y Python la destruir.
Usando este enfoque, la funcin que cambia vocales por subrayados quedara as:
1 def cambiar_vocales(texto):
2 """Esta funcion recibe una cadena de texto como parametro
3 y retorna otra cadena que es una copia de la recibida, salvo
4 por que todas las vocales han sido sustituidas por el
5 signo _"""
6 resultado = "" # De momento no tenemos letras en el resultado
7 # Recorremos todos los indices para acceder a cada letra
8 for letra in texto:
9 # Miramos si es una vocal
10 if letra in "aeiouAEIOU":
11 # Si lo es, concatenamos "_" al resultado
12 resultado = resultado + "_"
13 else:
14 # Si no, concatenamos la letra en cuestion
15 resultado = resultado + letra
16 # Una vez salimos del bucle, tenemos la cadena formada
17 # No olvidarse de retornarla!
18 return resultado
19
20 # Para probar la funcion anterior creo un mensaje
21 mensaje = "Mensaje de prueba"
22
23 # Borramos sus vocales, pero debo recoger el resultado en otra variable
24 cambiado = cambiar_vocales(mensaje)
25
26 # Imprimir cadena original y cambiada:
27 print mensaje
28 print cambiado

Para saber ms
El mtodo usado en la funcin anterior para ir haciendo crecer una cadena, se considera
mala prctica entre los programadores expertos de Python. La razn es que ese cdigo
es muy ineficiente, ya que cada vez que hacemos texto=texto+algo, se est creando
una nueva cadena en memoria, copiando a ella todos los caracteres concatenados de
texto y algo, reasignando la variable texto para que apunte a esa nueva cadena, y
destruyendo la cadena anterior (si no hay ya variables que apunten a ella). Si este tipo
de crecimiento de cadenas se usa dentro de un bucle que se repite muchas veces, para
crear cadenas muy largas, el programa puede empezar a ir ms lento de lo deseable.
En nuestro caso, con cadenas tan cortas, preocuparse por la eficiencia no es necesario. No
obstante, si quisieras hacerlo bien, lee el recuadro Para saber ms de la pgina 106,
2.7 Tipos y estructuras de datos bsicas: listas y arrays 103

que muestra como usar la operacin join() (que se describe ms adelante) para crear
cadenas que se componen de ir agregando muchas otras cadenas, y de forma eficiente.

Convertir una cadena en una lista


A menudo se tiene una cadena de texto que contiene una serie de palabras, separadas mediante
algn smbolo separador especial. Por ejemplo, al exportar una hoja de clculo Excel en el formato
denominado csv (comma separated values) lo que hace Excel es escribir un fichero en el que cada
lnea representa una fila de la tabla, y los contenidos de cada celda se escriben todos en la misma
lnea, usando el punto y coma (;) como separador de columnas.
Por ejemplo, considera una tabla Excel que contenga la siguiente informacin, sobre los apellidos
ms frecuentes:

Apellido Frecuencia Por 1000


GARCIA 1.483.939 31,6
GONZALEZ 935.135 19,9
RODRIGUEZ 932.924 19,8
FERNANDEZ 928.618 19,7
LOPEZ 879.145 18,7

Si exportamos esta hoja al formato csv, el fichero resultante se podra abrir en el bloc de notas
(contiene solo texto) y veramos lo siguiente:
Apellido;Frecuencia;Por 1000
GARCIA;1.483.939;31,6
GONZALEZ;935.135;19,9
RODRIGUEZ;932.924;19,8
FERNANDEZ;928.618;19,7
LOPEZ;879.145;18,7

Si leyramos ese fichero desde un programa en Python, la funcin readline nos dara una
lnea completa, y sera interesante poder romper esa lnea en tres trozos y as poder recuperar el
apellido, la frecuencia y el tanto por 1000 almacenado en cada lnea.
Pues bien, las cadenas de texto tienen entre sus mtodos uno llamado split() que sirve
justamente para este propsito. Este mtodo espera un parmetro que es el carcter (o en realidad
la sub-cadena) que se usar como separador. En nuestro ejemplo se tratara del punto y coma. El
resultado del mtodo es una lista, en la cual cada elemento es una cadena que ha resultado de
romper la cadena original. En nuestro ejemplo, la lista tendra tres elementos correspondientes a
los tres trozos. Por ejemplo:
>>> linea = "GARCIA;1.483.939;31,6"
>>> trozos=linea.split(";")
>>> len(trozos)
3
>>> trozos[0]
GARCIA
>>> trozos[1]
1.483.939
>>> trozos[2]
31,6
2.7 Tipos y estructuras de datos bsicas: listas y arrays 104

Convirtiendo datos desde Excel


Lo que leemos del archivo csv son cadenas de texto. Al partirlo en trozos con split()
cada trozo sigue siendo una cadena de texto. Si queremos manejar un trozo como si fuera
un valor numrico (para sumarlos, compararlos o lo que sea), sera necesario convertirlo
al tipo apropiado (int o float).
Sin embargo hay un problema adicional y es que Excel ha metido como parte del nmero
otros smbolos que confundirn a Python. Por ejemplo, en los enteros de ms de 3 cifras
mete un punto como separador de miles, que Python podra tomar como el separador
de decimales. Y en los reales que tienen parte fraccin usa la coma como separador, en
lugar del punto
Si queremos tratar esas cadenas como nmeros, antes habra que convertirlas a una forma
apropiada, antes de pasarlas a int() o float(). Esto implica procesar la cadena,
eliminando cada . innecesario, y cambiando la , separadora de decimales por el
punto. Aunque el procesamiento de cadenas se sale de los objetivos de la asignatura, por
su utilidad en este caso particular, daremos cmo se hara, a modo de receta.
La siguiente funcin recibir una cadena de caracteres como las que Excel genera para
representar un nmero, y devuelve un dato Python de tipo int o float con el valor
representado en dicha cadena. Puedes copiar esta funcin tal cual aparece aqu y usarla
en tus programas si la necesitas.
1 def interpreta_cadena_excel(dato):
2 """Recibe un dato que es una cadena de texto formateada en el estilo
3 en que excel formatea los numeros, es decir, usando coma para separar
4 los decimales, y usando punto como separador de millares, millones, etc
5 La funcion retorna un dato tipo int o float que contiene el valor
6 representado por la cadena que ha recibido"""
7
8 # Lo primero quitarle al dato todos los puntos (.) que tenga
9 # El metodo replace() cambia un texto por otro dentro de la cadena
10 # En esta ocasion lo usamos para cambiar el punto por una cadena vacia
11 # con lo que lo borramos.
12 dato = dato.replace(".", "")
13
14 # Seguidamente cambiar las comas que contenga por puntos
15 dato = dato.replace(",", ".")
16
17 # Ya esta listo para ser procesado por python. El resultado
18 # sera un float si contiene el caracter punto "." o un entero
19 # si no lo contiene
20 if "." in dato:
21 resultado = float(dato)
22 else:
23 resultado = int(dato)
24 return resultado

Otra forma de convertir una cadena en una lista es usar la funcin list() pasndole una
cadena. El resultado ser una lista en la que cada elemento es una letra de la cadena original. Esto
tiene en general poca utilidad, y no lo usaremos en esta asignatura.
Convertir una lista en una cadena
Podemos convertir una lista que contenga valores de cualquier tipo en una cadena, que sera la
misma que veramos en pantalla al hacer un print de la lista. Para ello basta pasar dicha lista a
la funcin str(). Pero esto en general no es muy til:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 105

>>> lista = [1, 2.3, 5]


>>> lista
[1, 2.2999999999999998, 5]
>>> cadena = str(lista)
>>> cadena
[1, 2.2999999999999998, 5]

Otro caso mucho ms til es aquel en el que tenemos una lista cuyos elementos son cadenas, y
queremos concatenar todos juntos estos elementos, posiblemente insertando entre ellos algn tipo
de separador.
Por ejemplo, tenemos la lista semana que contiene como elementos ["lunes", "martes",
"miercoles", "jueves", "viernes", "sabado", "domingo"] y queremos construir una
cadena que contenga el texto "lunes, martes, miercoles, jueves, viernes, sabado,
domingo".Como ves, se trata de concatenar las palabras que haba en la lista, poniendo una coma
y un espacio (", ") entre ellas.
Con lo que sabemos hasta ahora, esto podra hacerse de diferentes formas. La ms directa (y la
peor), podra ser simplemente sumar (concatenar) los 7 elementos de la lista a mano.
1 cadena = semana[0] + ", " + semana[1] + ", " + semana[2] + ", " +
2 semana[3] + ", " + semana[4] + ", " + semana[5] + ", " +
3 semana[6]

Ni que decir tiene que el cdigo anterior es una barbaridad. Adems de lo torpe que resulta
tener que repetir tantas veces la misma expresin, ni siquiera es una solucin genrica. Habra que
cambiarlo si la lista que quiero concatenar tiene ms o menos elementos. Para esto estn los bucles!
En una solucin con bucles, comenzaramos con una cadena vaca (que contenga "") e iramos
sumndole a dicha cadena cada elemento de semana, ms la cadena ", ", hasta llegar al ltimo.
1 cadena="" # Inicialmente vaca
2 for texto in semana:
3 cadena = cadena + texto + ", "

Sin embargo el cdigo anterior no hace exactamente lo que queramos, ya que aparecera una
coma tambin despus del ltimo da de la semana, y en ese caso no la queremos. El ultimo caso
es excepcional y para manejar ese caso tenemos que afear un poco la solucin anterior. Tenemos
dos formas, la primera sera comprobar dentro del bucle si estamos en el ltimo elemento, y si no
estamos, aadir la coma separadora. Sera as:
1 cadena="" # Inicialmente vaca
2 ultimo_indice = len(semana) - 1
3 for i in range(len(semana)):
4 cadena = cadena + semana[i] # Aadir el dato
5 if i != ultimo_indice: # y si no es el ultimo
6 cadena = cadena + ", " # aadir tambin la coma

La segunda forma es hacer que el bucle se recorra para todos los elementos salvo el ltimo, y
tratar este despus, fuera del bucle. Sera as:
1 cadena="" # Inicialmente vaca
2 ultimo_indice = len(semana) - 1
3 for i in range(ultimo_indice):
4 cadena = cadena + semana[i] + ", " # Aadir dato con su coma
5 # Ahora aadir el ultimo elemento
6 cadena = cadena + semana[ultimo_indice] # sin coma detras

Cualquiera de estas soluciones es buena. Ambas funcionan para listas de cualquer longitud, salvo
para listas vacas, en las que la segunda solucin fallara. Si quisiramos hacerlo totalmente genrico
habra que comprobar en el segundo caso si la lista tiene longitud cero, en cuyo caso no habra que
hacer nada ms sobre cadena.
2.7 Tipos y estructuras de datos bsicas: listas y arrays 106

Este es el problema que intentamos resolver, y aunque ya hemos dado con una solucin para l,
resulta conveniente saber que Python ya vena con una solucin pre-programada para este problema.
Se trata de un mtodo llamado .join() que tienen las cadenas.
La sintaxis de este mtodo es un poco extraa y de alguna forma parece estar al revs de
lo que uno esperara. El mtodo se invoca sobre una cadena que contenga el separador a insertar
(en nuestro caso, la cadena ", "), y se le pasa como parmetro la lista que contiene los datos a
concatenar. El resultado de la llamada es la cadena concatenada como queramos. Para el ejemplo
anterior la llamada sera por tanto:
1 cadena = ", ".join(semana)

En casos excepcionales podemos querer concatenar todos los elementos de la lista sin ningn
tipo de separador intermedio. Por ejemplo, en el caso en que cada elemento de la lista sea un solo
carcter y queramos juntarlos todos para formar una palabra o cadena. Esto tambin puede hacerlo
join(), basta usar una cadena vaca ("") en la llamada. Por ejemplo:
>>> letras = ["H", "o", "l", "a"]
>>> palabra = "".join(letras)
>>> palabra
Hola

Para saber ms: Uso para crear cadenas letra a letra


En el ejemplo que se puede ver en la pgina 102 vimos una funcin que sustitua las
vocales de una cadena dada por otro carcter. Dentro de la funcin la cadena resultado
se iba creando letra a letra, por el mtodo de ir concatenando cada letra a lo que
haba previamente. Se coment all que el mtodo era ineficiente porque para cada
concatenacin se creaba una cadena nueva.
El mtodo eficiente de lograr el mismo resultado consiste en crear una lista con las
letras de la nueva cadena. Para ir aadiendo cada nueva letra a la lista se usa el mtodo
.append() de la lista, en lugar de concatenar como en las cadenas. Esto modifica
siempre la misma lista, hacindola crecer, en lugar de crear listas nuevas para cada letra
que se aade, y por tanto es ms eficiente. Como paso final, una vez tenemos la lista
con todas las letras que la componen, se crea una cadena juntando todas ellas, con el
mtodo visto en el ltimo ejemplo de uso de join().
El cdigo que implementa esta idea sera:
1 # coding=latin1
2 def cambiar_vocales(texto):
3 """Esta funcion recibe una cadena de texto como parametro
4 y retorna otra cadena que es una copia de la recibida, salvo
5 por que todas las vocales han sido sustituidas por el
6 signo _"""
7 # El resultado sera una lista, en lugar de una cadena
8 resultado = [ ] # De momento no tenemos letras en el resultado
9 # Recorremos todas las letras de la cadena original
10 for letra in texto:
11 # Miramos si es una vocal
12 if letra in "aeiouAEIOU":
13 # Si lo es, metemos "_" en el resultado
14 resultado.append("_")
15 else:
16 # Si no, metemos la letra en cuestion
17 resultado.append(letra)
18 # Una vez salimos del bucle, tenemos una lista con todas
2.7 Tipos y estructuras de datos bsicas: listas y arrays 107

19 # las letras del resultado. Lo convertimos en una cadena


20 # concatenando todas esas letras sin separador, y retornamos
21 # el resultado
22 return "".join(resultado)
23
24 # Para probar la funcion anterior creo un mensaje
25 mensaje = "Mensaje de prueba"
26
27 # Borramos sus vocales, pero debo recoger el resultado en otra variable
28 cambiado = cambiar_vocales(mensaje)
29
30 # Imprimir cadena original y cambiada:
31 print mensaje
32 print cambiado

2.7.7. Un caso frecuente en ingeniera: listas de listas rectangulares, matrices


Muchas magnitudes usadas en ingeniera se representan como matrices porque se corresponden
con una estructura bidimensional sobre una rejilla con un cierto nmero de filas y columnas. Por
ejemplo, medidas tomadas sobre un terreno, tensiones e intensidades en un circuito elctrico, es-
fuerzos en la barras de una estructura, colores de pixels de una imagen, etc. Python dispone de un
tipo especfico de dato para realizar clculos con matrices, con la mayor parte de las operaciones
habituales (producto, inversa, determinante), implementadas. El mdulo en donde estas caracters-
ticas estn implementadas se estudiar ms adelante. Sin embargo es posible realizar clculos con
matrices representando estas como listas de listas. El inconveniente estriba en que no existe una
funcin predefinida en Python que permita crear esta estructura de datos, por as decirlo, darle un
nmero de filas y columnas. Sin embargo es muy fcil con lo que hemos visto hasta ahora, de hecho
se puede hacer de dos formas, usando append y el operador de repeticin * o bien slo este ltimo.
La primera idea consiste en ir aadiendo "filas" a una lista inicialmente vaca. Ntese que de
esta forma cada elemento de la lista inicialmente vaca es a su vez una lista, de modo que para
indexar cada uno de los escalares son necesarios dos ndices, el primero indicara la fila y el segundo
el elemento concreto dentro de esa fila, es decir, la columna. A modo de ejemplo se crear una lista
de listas para albergar una matriz de tres filas y dos columnas.
>>> a=[]
>>> for i in range(3):
... a.append([None]*2)
...

En el caso anterior no se han inicializado los elementos individuales de la matriz con ningn
valor, se ha utilizado None. Segn el caso podra ser interesante inicializarlos todos a 1 o a 0. Por
ejemplo:
>>> a=[]
>>> for i in range(3):
... a.append([0]*2)
...

En cualquier caso, es posible asignar los valores individuales utilizando los ndices correspondie-
nes a la fila y columna de cada elemento:
>>> a[0][0]=3.1
>>> a[0][1]=-1.0
>>> a[1][0]=0.0
>>> a[1][1]=-0.1
>>> a[2][0]=7.0
2.7 Tipos y estructuras de datos bsicas: listas y arrays 108

>>> a[2][1]=5.3

As, la lista de listas quedara finalmente:


>>> a
[[3.1, -1.0], [0.0, -0.1], [7.0, 5.3]]

Si se utiliza un objeto de este tipo con uno o ms ndices fuera del rango definido para filas o
columnas, se produce un error:
>>> a[1][3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range

La segunda de las formas de crear una lista de listas para almacenar una matriz es similar a
la anterior, pero la lista inicial se crea del tamao de las filas (con tantos elementos como filas
tenga la matriz) y despus se asigna a cada uno de esos elementos una lista con tantos elementos
como columnas tenga la matriz. Para ello se usa el operador de repeticin *. La clave de que as se
consiga asignar espacio para los distintos elementos est en que (como se dijo en su momento) los
operadores sobre listas producen nuevos objetos, no referencias a objetos existentes. Al igual que en
el caso anterior, se puede inicializar cada uno de los elementos de la matriz en este punto. En este
caso se ha inicializado a 1.0, aprovechando para recordar la importancia del tipo de datos empleado
a la hora de realizar operaciones aritmticas y que Python es un lenguaje de tipado dinmico.
>>> a=[None]*3
>>> for i in range(3):
... a[i]=[1.0]*2
...

El resto de operaciones seran idnticas al caso anterior.


Es evidente que la salida por pantalla de las matrices as representadas no tiene el aspecto que
se espera, una organizacin bidimensional de los nmeros que contiene. Podemos aproximarnos de
forma sucesiva a este aspecto recordando distintos temas que se han visto en el tema de listas. En
primer lugar vamos a iterar con un slo bucle directamente sobre la lista, es decir, cada elemento
que vamos a obtener es a su vez una lista:
>>> for fila in a:
... print fila
...
[3.1, -1.0]
[0.0, -0.1]
[7.0, 5.3]

Las instrucciones anteriores hacen que, la primera vez, el objeto fila sea la primera fila de la
matriz, una lista, que al ser mostrada aparece entre corchetes con los elementos separados por
comas. La segunda vez la siguiente y as sucesivamente. Ahora bien, se puede hacer esto mismo con
cada elemento de cada fila, usando un bucle for anidado ms:
>>> for fila in a:
... for elemento in fila:
... print elemento,
... print
...
3.1 -1.0
0.0 -0.1
7.0 5.3
2.7 Tipos y estructuras de datos bsicas: listas y arrays 109

En el cdigo de ejemplo anterior, el primer bucle asigna al objeto fila cada una de las filas
de a, el segundo asigna a elemento cada uno de las componentes de la fila actual. Un par de
comentarios sobre como se usa print. El primero de ellos est dentro del bucle ms interno y por
lo tanto muestra cada uno de los elementos individuales de la matriz. Como queremos que salgan
en la misma lnea, lleva una coma al final. El segundo print es para mostrar en distintas lneas de
la pantalla cada una de las filas, est dentro del primer for pero fuera del segundo.
Alternativamente, se pueden usar secuencias de ndices dentro del rango vlido para filas y
columnas para acceder a los elementos de la matriz. En este caso el cdigo que la mostrara por la
pantalla sera:
>>> for i in range(3):
... for j in range(2):
... print a[i][j],
... print
...

Como se explic anteriormente, range(3) produce la lista [0,1,2] y range(2) produce la


lista [0,1], por este motivo, con los dos bucles anidados anteriores, se generan todas las posibles
parejas de ndices vlidos (en realidad el producto cartesiano de estos) para a.
El acceso a los elementos usando ndices tambin permite cambiar el valor de los elementos de
la matriz, cosa que no se podra hacer iterando sobre filas y elementos de filas. Por ejemplo, el
siguiente fragmento de cdigo asigna cero a los elementos de la matriz anterior:
>>> for i in range(3):
... for j in range(2):
... a[i][j]=0
...

De los ejemplos anteriores podra deducirse que es necesario usar de forma explcita el nmero
de filas o columnas para poder recorrer una lista que represente una matriz. Como se puede deducir
fcilmente, estos valores se pueden obtener de forma casi trivial usando la funcin len. De esta
forma, por ejemplo, se pueden reescribir algunos de los fragmentos de cdigo anteriores como sigue:
>>> for i in len(a):
... for j in len(a[i]):
... print a[i][j],
... print
...

La longitud de la lista "mas externa", len(a), es el nmero de filas. La longitud de cada fila
len(a[i]) es el nmero de columnas. En el caso concreto que nos ocupa, matrices rectangulares,
se podra haber usado len(a[0]) ya que todas las filas tienen la misma longitud. La alternativa
usada sirve para todos los casos, incluso aquellos en los que cada fila tenga un tamao distinto
y nos permite abstraernos de las dimensiones de la matriz que estemos manejando. Esto es ms
recomendable que usar de forma explcita el nmero de filas y columnas.
Como es evidente, las matrices representadas como listas se manejan con funciones de la misma
forma que cualquier otra lista. As por ejemplo podramos convertir en funcin el cdigo usado para
crear una matriz.
1 def zeros(filas,columnas):
2 """Devuelve una matriz de ceros de alto filas y ancho columnas"""
3 #Lista vacia
4 a = []
5 #Tantas veces como filas
6 for i in range(filas):
7 #anadir una fila con tantas columnas como ancho
8 a.append([0]*columnas)
2.7 Tipos y estructuras de datos bsicas: listas y arrays 110

9 #retornar la matriz
10 return a

Esto nos permite reutilizar cdigo en nuestros programas, como se indic cuando se trat el
tema de funciones. Por ejemplo, usando la funcin anterior se puede escribir otra para pedir una
matriz de reales por el teclado. Primero se crea la matriz, despus se recorre y en cada iteracin se
pide el elemento indexado por i y j.
1 def pide_matriz_float(filas,columnas):
2 """Pide una matriz de reales por el teclado"""
3 #se crea la matriz
4 a=zeros(filas,columnas)
5 #se recorre, en cada iteracion se pide uno de los elementos
6 for i in range(filas):
7 for j in range(columnas):
8 #se muestran los indices de los elementos que se piden
9 print "[ %d][ %d]" %(i,j)
10 a[i][j]=float(raw_input())
11 return a

Y podramos hacer lo mismo con el fragmento de cdigo que muestra una matriz por la pantalla.
1 def muestraMatriz(a):
2 """Muestra una matriz, representada la lista de listas a, por la
3 pantalla, una fila por linea de la pantalla"""
4 #se recorre la lista de listas usando indices y dos for anidados
5 for i in range(len(a)):
6 for j in range(len(a[i])):
7 #la coma hace que los elementos de una fila vayan seguidos
8 print a[i][j],
9 #siguiente linea
10 print

Al final de esta seccin se incluyen una serie de ejercicios resueltos en donde se ha intentado
cubrir un abanico lo ms amplio posible casos de uso de matrices representadas como listas de listas.
Siempre se han usado funciones, dado que es una prctica aconsejable proceder de esta forma.
2.7.8. Arrays
Numpy es un paquete de Python que reune tipos de datos y funciones para el clculo cien-
tfico. Proporciona, entre otras cosas, el tipo ndarray, til para la representacin de vectores y
matrices multidimensionales, as como importantes funciones de lgebra lineal, tales como diversas
operaciones con matrices, el clculo de la inversa o la resolucin de un sistema de ecuaciones.
Un array es una secuencia ordenada9 , de elementos del mismo tipo, agrupados en distintas
dimensiones. Si es nica la dimensin, hablamos de vectores. Si son varias, de matrices. El nmero
de dimensiones de una matriz (o nmero de ejes) no se limita a dos. Esta circunstancia permite
disponer de un tipo de dato adecuado para representar, por ejemplo, las propiedades de un objeto
tridimensional.
Los atributos ms tiles de un ndarray son:
ndim, devuelve el nmero de dimensiones de un array.
shape, devuelve el tamao del array en cada una de sus dimensiones
size, devuelve el nmero de elementos totales del array, es decir, el producto de su extensin
en cada una de sus dimensiones.
Para poder utilizar numpy en un programa o en modo interactivo, es necesario cargar el mdulo,
lo cual se hace con import como ya sabemos:
import numpy

9
En el sentido de que posee un orden interno, es decir, que cada elemento puede ser accedido mediante uno o ms
subndices. Son estos los que estn ordenados, no los valores que ocupan las posiciones especificadas por ellos.
2.7 Tipos y estructuras de datos bsicas: listas y arrays 111

En este curso, para crear un array se utilizar uno de estos mtodos:


1. Conversin desde otras estructuras de datos de Python (usualmente listas).
2. Creacin intrnseca de arrays con llamadas a funciones que devuelven arrays.
3. Lectura de arrays desde ficheros.
Conversin desde otras estructuras de datos
La funcin array(secuencia, dtype=tipo) permite convertir una secuencia en un array
de elementos del tipo especficado. Si este ltimo no se detalla la funcin usa el tipo ms genrico
encontrado en la secuencia.
Veamos unos ejemplos de conversin de listas numricas en arrays. Despus de crear cada array
podemos escribir su nombre y a continuacin pulsar return para ver su contenido o bien hacer uso
de la funcin print.
>>> a=numpy.array([7,23,4,.5])
>>> a
array([ 7. , 23. , 4. , 0.5])
>>> b=numpy.array([[7,2,3.5],[3.1,2.2,0]])
>>> b
array([[ 7. , 2. , 3.5],
[ 3.1, 2.2, 0. ]])
>>> c=numpy.array([[0,1.7,1.1],[1.3,1.5,2]], dtype=int)
>>> c
array([[ 0, 1, 1],
[ 1, 1, 2]])
>>> d=numpy.array((b,c))
>>> d
array([[[ 7. , 2. , 3.5],
[ 3.1, 2.2, 0. ]],

[[ 0. , 1. , 1. ],
[ 1. , 1. , 2. ]]])

En la sucesin de ejemplos anteriores, a es un array de una dimensin, b y c son arrays de dos


dimensiones y d es un array de tres dimensiones. Como podemos observar la matriz c se ha creado
especificando el tipo int por lo que los datos reales se han convertido a enteros truncando su valor.
Cuando no se especifica el tipo y aparecen en los datos elementos de tipo entero y real, se toma por
defecto el tipo real como bsico, ya que es el ms genrico.
A continuacin se muestra el valor de los atributos ndim, shape y size de las matrices y
vectores definidos. En este caso hemos usado las funciones del mdulo numpy con los mismos
nombres que nos devuelven el valor de los atributos correspondientes.
>>> numpy.ndim(a)
1
>>> numpy.ndim(b)
2
>>> numpy.shape(a)
(4,)
>>> numpy.shape(b)
(2, 3)
>>> numpy.size(a)
4
>>> numpy.size(b)
6
>>> numpy.size(c)
6
>>> numpy.shape(c)
(2, 3)
>>> numpy.shape(d)
2.7 Tipos y estructuras de datos bsicas: listas y arrays 112

(2, 2, 3)
>>> numpy.size(d)
12
>>> numpy.ndim(c)
2
>>> numpy.ndim(d)
3

Para saber ms
Una curiosidad: Vemos que el shape o forma del vector unidimensional a es (4,). En
Python dicha funcin retorna una tupla. El problema es que la tupla (4) se confunde con
la expresin numrica que representa al 4. Para que no haya confusin Python representa
una tupla con un nico valor as: (valor,). La coma indica que detrs debera haber
ms elementos (aunque se omitan) y que por tanto no es una expresin numrica simple.
Alguno puede pensar que an as, un vector puede ser considerado como una ma-
triz de una sla fila y tantas columnas como la dimensin del vector. Para que
Python piense lo mismo, el vector unidimensional debera haberse definido as:
a=numpy.array([[1,2,3,4]]). En este caso el nmero de corchetes igual a dos
indica que es una matriz, y ahora s, la funcin shape() devuelve el valor (1,4). Todo
lo cual, efectivamente, tiene su lgica.

Creacin intrnseca de arrays


La creacin intrnseca de arrays consiste en crearlos utilizando alguna de las funciones que
devuelven arrays. He aqu las ms tpicas.

arange(), tiene la misma funcionalidad que el range() que ya conocemos, pero en lu-
gar de devoler una lista (tipo list) devuelve un vector (tipo ndarray). Posee los mismos
parmetros que la funcin range. No lo usaremos en esta asignatura.
>>> numpy.arange(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> numpy.arange(0,1,0.1)
array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

zeros(), devuelve un ndarray con el atributo shape que se le pase como parmetro,
inicializando a cero cada elemento. El atributo shape se indica entre parntesis (adems de
los parntesis que ya tenamos por ser un parmetro, es decir, doble parntesis).
>>> a=numpy.zeros((2,3))
>>> a
array([[ 0., 0., 0.],
[ 0., 0., 0.]])

En el ejemplo anterior se ha creado un ndarray de tamao 2 3

ones(), devuelve un ndarray con el atributo shape que se le pase como parmetros (que
ha de ir entre parntesis, como en zeros()), inicializando a uno cada elemento.
>>> a=numpy.ones((2,3))
>>> a
array([[ 1., 1., 1.],
[ 1., 1., 1.]])
2.7 Tipos y estructuras de datos bsicas: listas y arrays 113

Indexado
Es posible acceder a cada valor almacenado en un ndarray, utilizando tantos ndices como
corresponda a su atributo ndim, es decir, uno para los de una dimensin, dos para los de dos, etc.
El rango de valores para esos ndices viene determinado por los valores correspondientes del atributo
shape, desde cero hasta ese valor menos uno. Por ejemplo, a es un array de una sola dimension
(ndim=1), por lo tanto slo es necesario un ndice para acceder a sus elementos. Por otra parte, el
valor de shape es (4,), por lo tanto los ndices vlidos para a son {0,1,2,3}.
>>> a[0]
7.0
>>> a[1]
23.0
>>> a[2]
4.0
>>> a[3]
0.5

Anlogamente, b es un array bidimensional (ndim vale 2), de modo que son necesarios dos ndices
para acceder individualmente a cada elemento. El atributo shape vale (2, 3), de modo que los
valores vlidos para el primer ndice son {0,1} y para el segundo {0,1,2}. Convencionalmente se suele
decir que el primero determina la fila y el segundo la columna. Existen dos notaciones distintas para
especificar parejas, ternas, etc. de ndices. La primera es idntica a la de listas que contienen listas:
>>> b[0][0]
7.0
>>> b[0][1]
2.0
>>> b[1][2]
0.0

Lo anterior se interpreta de la siguiente forma: por ejemplo, b[1] es la fila que est en la posicin
1 por lo tanto b[1][2] es (dentro de esa fila) el elemento en la posicin 2. Es decir, el elemento
b[1][2] del array. Sin entrar en demasiados detalles que exceden el alcance de este curso, el
acceso a los elementos de un array de este modo se considera ineficiente. La segunda de las formas
de especificar los ndices de los elementos de un array de dos o ms dimensiones es separar los
ndices por comas y encerrarlos todos entre una sola pareja de corchetes. A continuacin se accede
a los mismos elementos que antes utilizando esta sintaxis.
>>> b[0,0]
7.0
>>> b[0,1]
2.0
>>> b[1,2]
0.0

Para saber ms
Es posible especificar rangos de ndices separando el inicio y el fin del rango mediante
:, al igual que sucede con otras secuencias en Python. Recurdese que la secuencia de
ndices obtenida contiene el inicio del rango pero no el ltimo, termina con el penltimo.
De esta forma 3:7 representa 3,4,5,6. Por ejemplo, para un ndarray de una dimensin:
>>> a=numpy.array([ 1, 5, 2, 7, 4, 8, 9, 10, 3, 2, 5, 4])
>>> a[3:7]
array([7, 4, 8, 9])
2.7 Tipos y estructuras de datos bsicas: listas y arrays 114

En el caso de los ndarray de ms de una dimensin, los rangos pueden especificarse


en una o ms de sus dimensiones. Es necesario utilizar la segunda de las notaciones
mencionadas, en la que los ndices se separan por comas y slo se usa una pareja de
corchetes. Si no se especifican el inicio y el fin pero s los : entonces el rango abarca
todos los ndices vlidos de esa dimensin. Por ejemplo si se tiene el siguiente ndarray:
>>> b=numpy.array(([4,5,2,1,6,4],[3,3,6,7,8,1],[7,7,8,9,1,2],[1,2,2,3,1,1]))
>>> b
array([[4, 5, 2, 1, 6, 4],
[3, 3, 6, 7, 8, 1],
[7, 7, 8, 9, 1, 2],
[1, 2, 2, 3, 1, 1]])

La segunda columna sera (ntese el cambio de notacin mencionado):


>>> b[:,2]
array([2, 6, 8, 2])

La submatriz obtenida a partir de los elementos comprendidos ente la fila 1 y la tres y


las columnas 2 y 5 seran:
>>> b[1:3,2:5]
array([[6, 7, 8],
[8, 9, 1]])

Cambios en la forma de un ndarray


Es posible cambiar la forma de un ndarray, es decir, distribuir de forma distinta los elementos
que lo componen, resultando en un ndarray con el mismo nmero total de elementos pero un
nmero distinto de filas, columnas, etc. Entre las funciones disponibles en numpy estn las siguientes:

transpose, transpone una matriz.


>>> b=numpy.array([[5,2,4],[5,1,2],[1,1,5],[6,8,2]])
>>> b
array([[5, 2, 4],
[5, 1, 2],
[1, 1, 5],
[6, 8, 2]])
>>> c=numpy.transpose(b)
>>> c
array([[5, 5, 1, 6],
[2, 1, 1, 8],
[4, 2, 5, 2]])

ravel, convierte un ndarray en otro de una sola dimensin.


>>> d=numpy.ravel(c)
>>> d
array([5, 5, 1, 6, 2, 1, 1, 8, 4, 2, 5, 2])

Para saber ms
Otra operacin de cambio de forma de un ndarray que puede ser til es la siguiente:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 115

reshape, cambia el atributo shape de un ndarray al valor especificado. Si uno


de los valores del atributo es -1, se calcula a partir de los dems para que se cumpla
que size no cambie.
>>> a=numpy.array([[5,2,4,5],[1,2,1,1],[5,6,8,2]])
>>> a
array([[5, 2, 4, 5],
[1, 2, 1, 1],
[5, 6, 8, 2]])
>>> b=numpy.reshape(a,(2,6))
>>> b
array([[5, 2, 4, 5, 1, 2],
[1, 1, 5, 6, 8, 2]])
>>> b=numpy.reshape(a,(-1,3))
>>> b
array([[5, 2, 4],
[5, 1, 2],
[1, 1, 5],
[6, 8, 2]])

2.7.9. Operaciones bsicas con arrays


Las operaciones aritmticas sobre ndarray se efectan elemento a elemento, esto es de especial
importancia en el caso del producto: a*b no representa el producto de matrices al uso sino que
denota una operacin en la que el elemento a[i,j] se multiplica por el b[i,j], para los valores
de i y j vlidos segn el atributo shape de ambos ndarray. Cuando las operaciones se realizan
entre dos o ms ndarray, sus atributos shape deben de ser idnticos, de lo contrario se produce un
error. Cuando las operaciones se realizan con un escalar, la operacin se realiza entre cada elemento
del ndarray y ese escalar.
>>> a=numpy.array(([7,3,1],[5,6.5,1]))
>>> a
array([[ 7. , 3. , 1. ],
[ 5. , 6.5, 1. ]])
>>> b=numpy.array(([3.1,0,-2],[1.3,3,0]))
>>> a+b
array([[ 10.1, 3. , -1. ],
[ 6.3, 9.5, 1. ]])
>>> a*b
array([[ 21.7, 0. , -2. ],
[ 6.5, 19.5, 0. ]])
>>> a<b
array([[False, False, False],
[False, False, False]], dtype=bool)
>>> a+1
array([[ 8. , 4. , 2. ],
[ 6. , 7.5, 2. ]])
>>> a**2
array([[ 49. , 9. , 1. ],
[ 25. , 42.25, 1. ]])
>>> a==1
array([[False, False, True],
[False, False, True]], dtype=bool)

El producto matricial se representa mediante la funcin dot. Como es de esperar, el nmero de


columnas de la primera matriz ha de ser igual al nmero de filas de la segunda matriz. A modo de
ejemplo se muestra el producto de a por la transpuesta de b.
2.7 Tipos y estructuras de datos bsicas: listas y arrays 116

>>> numpy.dot(a,numpy.transpose(b))
array([[ 19.7, 18.1],
[ 13.5, 26. ]])

Las funciones universales, sin, cos, exp, etc., tambin se aplican elemento a elemento.
>>> c=numpy.array(([3.1415926535897931,3.1415926535897931/2],
[3.1415926535897931/3,3.1415926535897931/4]))
>>> c
array([[ 3.14159265, 1.57079633],
[ 1.04719755, 0.78539816]])
>>> numpy.cos(c)
array([[ -1.00000000e+00, 6.12323400e-17],
[ 5.00000000e-01, 7.07106781e-01]])

Las operaciones unarias (se aplican a ndarray pero devuelven un slo valor) por defecto se
aplican elemento a elemento como si los valores del ndarray se almacenasen en una lista, sin
importar el valor del atributo shape.
>>> numpy.min(a)
1.0
>>> numpy.max(a)
7.0
>>> numpy.sum(a)
23.5

Para saber ms
Si se desea operar sobre una dimensin o eje en concreto (filas o columnas, por ejemplo)
y producir un valor distinto para cada uno de los valores de ndice posibles para ese eje,
se especifica mediante el parametro axis. Por ejemplo, la suma de las filas por un lado
y de las columnas por otro de un ndarray de dos dimensiones sera:
>>> numpy.sum(a,axis=1)
array([ 11. , 12.5])
>>> numpy.sum(a,axis=0)
array([ 12. , 9.5, 2. ])

Las funciones max y min tambin se pueden usar de la misma forma:


>>> numpy.min(a,axis=0)
array([ 5., 3., 1.])
>>> numpy.min(a,axis=1)
array([ 1., 1.])
>>> a
array([[ 7. , 3. , 1. ],
[ 5. , 6.5, 1. ]])

La inversa y el determinante de una matriz (que cumpla, obviamente, los requisitos para que se
puedan calcular esos valores) se representan mediante las funciones linalg.inv y linalg.det,
respectivamente.
>>> coef
array([[ 7. , 3. ],
[ 5. , 6.5]])
>>> numpy.linalg.det(coef)
30.500000000000004
>>> numpy.linalg.inv(coef)
2.7 Tipos y estructuras de datos bsicas: listas y arrays 117

array([[ 0.21311475, -0.09836066],


[-0.16393443, 0.2295082 ]])

La funcin solve calcula la solucin de un sistema lineal de ecuaciones definido mediante su


matriz de coeficientes y los trminos independientes correspondientes. Por ejemplo, el sistema de
ecuaciones:

7x + 3y = 1
5x + 6.5y = 2

se resuelve as:
>>> y=numpy.array([1,2])
>>> numpy.linalg.solve(coef,y)
array([ 0.01639344, 0.29508197])

2.7.10. Copia de arrays


La asignacin se comporta con los ndarray de la misma forma que con cualquier otro objeto en
Python, en esencia se trata de dar un nombre alternativo a un objeto existente. Por ese motivo,
cualquier accin que se realice sobre un objeto obtiene el mismo resultado independientemente del
nombre que se utilice. En el siguiente ejemplo al cambiar el elemento 0,0 del ndarray y cambia
tambin el elemento 0,0 de x, porque es el mismo objeto de tipo ndarray.
>>> x=numpy.array(([4,3],[1,6]))
>>> x
array([[4, 3],
[1, 6]])
>>> y=x
>>> y[0,0]=1
>>> x
array([[1, 3],
[1, 6]])

Si por el motivo que sea se necesita copiar un objeto de tipo ndarray en otro, se utiliza la
funcin copy. En el siguiente ejemplo se ha asignado a y una copia de x, de modo que al cambiar
el elemento y[0,0], no cambiar el correspondiente elemento de x.
>>> x=numpy.array(([4,3],[1,6]))
>>> x
array([[4, 3],
[1, 6]])
>>> y=x.copy()
>>> y[0,0]=1
>>> x
array([[4, 3],
[1, 6]])
>>> y
array([[1, 3],
[1, 6]])

2.7.11. Recorrido de arrays


El tipo ndarray est concebido para ser muy eficiente cuando las operaciones sobre ste se
realizan sin utilizar bucles. Sin embargo en algunas ocasiones puede ser necesario utilizar bucles
para aplicar ciertas operaciones a todos o parte de los elementos de un ndarray. Adems, en
2.7 Tipos y estructuras de datos bsicas: listas y arrays 118

muchos lenguajes de programacin, el tipo equivalente al ndarray no est diseado para trabajar
de la misma forma, ms bien al contrario. Por este motivo se van a dar aqu unas indicaciones sobre
el uso de objetos de tipo ndarray mediante bucles.
Por defecto, la iteracin sobre un array se realiza sobre el primero de los ndices, el nico ndice
de un array de una dimensin, convencionalmente las filas en un array bidimensional.
En el siguiente ejemplo, como z es un array de una dimensin, la iteracin se produce sobre los
elementos del array, que estn indexados por el primer y nico ndice del mismo.
>>> z=numpy.array([3,6,4,6,8,5,6,7,8,9])
>>> for elemento in z:
... print elemento,
...
3 6 4 6 8 5 6 7 8 9

Sin embargo, si se itera sobre un array bidimensional, se itera sobre las filas, que estn indexadas
por el primer ndice
>>> a
array([[ 7. , 3. , 1. ],
[ 5. , 6.5, 1. ]])
>>> for fila in a:
... print fila
...
[ 7. 3. 1.]
[ 5. 6.5 1. ]

Evidentemente, en el caso anterior, cada fila a su vez puede ser recorrida como en el primero de
los ejemplos, en ese caso se utilizaran dos bucles anidados, el ms externo recorrera las filas y el
ms interno las columnas dentro da cada fila para acceder al valor de cada elemento.
>>> for fila in a:
... for elemento in fila:
... print elemento,
...
7.0 3.0 1.0 5.0 6.5 1.0

En algunos lenguajes de programacin no existe una construccin equivalente a las anteriores,


de modo que en esos casos se usan de forma explcita los valores de los ndices en todas las dimen-
siones posibles para (en esos lenguajes de programacin) acceder a los elementos individuales de las
estructuras de datos anlogas a ndarray. Es decir, se usan ndices para acceder a los elementos
del ndarray. Python tambin admite esta forma de trabajo; a continuacin se detalla esta tcnica
que habitualmente se llama recorrido.
En primer lugar es necesario generar una secuencia que contenga todos los valores vlidos para
los ndices que se utilicen en cada dimensin del ndarray. Una forma prctica es utilizar range
pasando como parmetro el elemento correspondiente del atributo shape que contenga el nmero
de elementos en la dimensin en cuestin. El primer elemento de shape es el nmero de elementos
en la primera dimensin, el segundo el nmero de elementos en la segunda dimensin, etc. En
el caso particular de los ndarray unidimensionales, size devuelve el nmero de elementos que,
evidentemente, coincide con el nmero de elementos que hay en la nica dimensin del ndarray.
En los ejemplos que van a continuacin, los ndarray utilizados son los definidos en los ejemplos
precedentes.
En el siguiente ejemplo se obtiene el nmero de elementos de z usando shape. Aunque este
atributo tenga un slo elemento, es necesario escribir una pareja de corchetes indicando el ndice
correspondiente. El nmero de elementos, que es 10, se asigna a nelementos. Despus se utiliza
este objeto como parametro en range, de modo que se generar la secuencia 0,1,2,...,9. En el
2.7 Tipos y estructuras de datos bsicas: listas y arrays 119

bucle for se utiliza esta secuencia para que i tome sucesivamente esos valores en orden creciente.
En cada iteracin del bucle for, se muestra el contenido del elemento de z indexado por i.
>>> nelementos=numpy.shape(z)[0]
>>> for i in range(nelementos):
... print z[i],
...
3 6 4 6 8 5 6 7 8 9

En el caso de los ndarray bidimensionales, shape contiene dos valores: el primero es el nmero
de filas y el segundo el nmero de columnas. Cada uno de estos valores se asigna a un objeto
adecuado (filas y columnas en el ejemplo). Al igual que en el ejemplo anterior, esos dos objetos
se utilizan en sendas llamadas a range para generar las secuencias que contienen los valores de
ndices vlidos para cada dimensin. Estas secuencias se utilizan en dos bucles for anidados, de
modo que, dentro del bucle ms interno, i y j adoptan todos los valores del producto cartesiano
de las dos secuencias. En otras palabras, todas las posibles parejas de ndices vlidos para el
objeto ndarray en cuestin. Como se deduce de la salida por pantalla del fragmento de cdigo que
se muestra, en este caso la matriz se recorre por filas, es decir, en primer lugar se accede a los
elementos de la primera fila, desde el primero al ltimo, en ese orden. Despus los de la segunda en
ese mismo orden. Si hubiese ms filas se continuara de la misma forma.
>>> filas=numpy.shape(a)[0]
>>> columnas=numpy.shape(a)[1]
>>> for i in range(filas):
... for j in range(columnas):
... print a[i][j],
...
7.0 3.0 1.0 5.0 6.5 1.0

Es posible alterar este esquema de recorrido y realizarlo por columnas, sin ms que intercam-
biar los bucles de posicin dentro del cdigo. En el siguiente ejemplo se puede observar como se
ha accedido a los elementos de la matriz mostrando en primer lugar los elementos de la primera
columna, despus los de la segunda.
>>> for j in range(columnas):
... for i in range(filas):
... print a[i][j],
...
7.0 5.0 3.0 6.5 1.0 1.0

Es posible invertir el orden del recorrido dentro de una o ms dimensiones de un ndarray, es


decir, hacer que la secuencia sea por ejemplo 9,8,...,1,0 en lugar de 0,1,...,8,9, para lo que
se puede usar range con un incremento negativo, o la funcin reversed que da la vuelta al resul-
tado habitual de range. En el siguiente ejemplo se muestra como recorrer el vector unidimensional
z desde el ltimo elemento al primero.
>>> for i in reversed(range(nelementos)):
... print z[i],
...
9 8 7 6 5 8 6 4 6 3

Alternativamente se podra haber utilizado como ndice de z una expresin que tomase los valores
9,8,...,1,0, construida a partir de i (que ira normalmente de 0 a 9, en orden creciente). En
este caso, la expresin sera nelementos-1-i.
>>> for i in range(nelementos):
... print z[nelementos-1-i],
...
9 8 7 6 5 8 6 4 6 3
2.7 Tipos y estructuras de datos bsicas: listas y arrays 120

De la misma forma es posible invertir el orden del recorrido de las filas o columnas de un
ndarray bidimensional.
2.7.12. Ejercicios resueltos.
[Ejercicio 1] Escribir una funcin que reciba como parmetros una lista y un valor escalar. La
funcin devuelve el nmero de veces que se repite el valor escalar dentro de la lista.
1 #En esta solucion se itera sobre la lista
2 #de valores directamente
3 #elemento toma el valor de cada uno de los
4 #elementos de la lista.
5 def veces1(lista,valor):
6 """Devuelve el numero de veces que se repite
7 valor dentro de lista"""
8 #se inicializa el contador
9 veces=0
10 for elemento in lista:
11 #si el elemento actual es el valor que se contabiliza
12 if elemento==valor:
13 #se incrementa el contador
14 veces=veces+1
15 #se retorna el valor al acabar el bucle
16 return veces
17
18 #En esta solucion se itera sobre la lista
19 #de los indices validos para el parametro
20 #lista para acceder al valor de cada elemento de
21 #la lista se usan los [] y el valor del
22 #indice.
23 def veces2(lista,valor):
24 """Devuelve el numero de veces que se repite
25 valor dentro de lista"""
26 veces=0
27 for i in range(len(lista)):
28 if lista[i]==valor:
29 veces=veces+1
30 return veces

[Ejercicio 2] Escribir una funcin que reciba como parmetros una lista y un valor escalar.
La funcin devuelve el ndice que ocupa la primera ocurrencia del valor escalar dentro de la lista o
None si no se encuentra.
1 #En este caso es mas conveniente usar una lista
2 #de indices validos porque se necesita saber en
3 #donde esta el valor buscado.
4 def donde_esta(lista,valor):
5 """Devuelve el indice de lista en donde esta la primera ocurrencia de
6 valor, si es que esta, None en caso contrario"""
7 #ya que python dispone del operador in, nos permite devolver
8 #None directamente si valor no esta en lista, sin tener que
9 #recorrerla de forma explicita
10 #si el valor esta en la lista
11 if valor in lista:
12 #recorremos la lista
13 for i in range(len(lista)):
14 #si se encuentra el valor
15 if lista[i]==valor:
16 #se retorna su indice
17 return i
18 #en caso contrario se retorna None
19 else:
20 return None
2.7 Tipos y estructuras de datos bsicas: listas y arrays 121

[Ejercicio 3] Escribir una funcin que reciba como parmetros dos listas, representando dos
vectores numricos. La funcin devuelve el producto escalar de ambos vectores.
1 #En este caso no se puede iterar sobre las
2 #listas (con lo que se ha visto en teor a)
3 #porque es necesario recorrer en
4 #paralelo las dos, que codifican dos vectores.
5 def producto_escalar(v1,v2):
6 """Devuelve el producto escalar de v1 y v2"""
7 #como se va a hacer un sumatorio se inicializa resultado a 0
8 resultado=0
9 #se supone que v1 y v2 tienen la misma longitud
10 for i in range(len(v1)):
11 #se acumula en resultado el producto de las componentes
12 #que ocupan la misma posicion
13 resultado=resultado+v1[i]*v2[i]
14 return resultado

[Ejercicio 4] Escribir una funcin que reciba como parmetros dos listas, representando dos
vectores numricos. La funcin devuelve la suma vectorial de ambos vectores.
1 #En este caso no se puede iterar sobre las
2 #listas (con lo que se ha visto en teor a)
3 #porque es necesario recorrer en
4 #paralelo las dos, que codifican dos vectores.
5 #Se da tamano a resultado repitiendo 0
6 #tantas veces como elementos hay en v1.
7 def suma_vectorial1(v1,v2):
8 """Devuelve la suma vectorial de v1 y v2"""
9 #dar tamano al raesultado
10 resultado=[0]*len(v1)
11 #da igual usar len de v1, v2 o resultado
12 for i in range(len(resultado)):
13 #la componente i esima del resultado es la suma de las
14 #componentes que ocupan el mismo lugar
15 resultado[i]=v1[i]+v2[i]
16 return resultado
17
18 #En este caso no se puede iterar sobre las
19 #listas (con lo que se ha visto en teor a)
20 #porque es necesario recorrer en
21 #paralelo las dos, que codifican dos vectores.
22 #En esta version no se da tamano al resultado
23 #se utiliza append para ir anadiendo elementos
24 #segun se van calculando
25 def suma_vectorial2(v1,v2):
26 #no se da tamano porque se usa append en el for
27 resultado=[]
28 for i in range(len(v1)):
29 #anadir la componente i-esima al resultado
30 resultado.append(v1[i]+v2[i])
31 return resultado

[Ejercicio 5] Escribir una funcin que reciba como parmetros una lista de nmeros y un
nmero. La funcin devolver el producto del nmero y del vector que est representado como lista
de nmeros.
1 #similar a los anteriores, con una lista
2 #y un escalar como parametros.
3 def producto_por_escalar(v,a):
4 """Devuelve el producto del vector v por el escalar a"""
5 resultado=[0]*len(v)
6 #en cada iteracion se almacena en la componente i esima del resultado
2.7 Tipos y estructuras de datos bsicas: listas y arrays 122

7 #el producto de la componente i esima por el escalar


8 for i in range(len(resultado)):
9 resultado[i]=v[i]*a
10 return resultado

[Ejercicio 6] Escribir una funcin que reciba como parmetro una lista representando un vector
numrico y que devuelva su mdulo.
1 def modulo(a):
2 """Devuelve el modulo del vector a, representado como lista"""
3 #la variable que se utiliza para hacer el sumatorio se inicializa
4 #a cero
5 suma_cuadrados=0
6 for i in range(len(a)):
7 #se acumula el cuadrado de la componente actual
8 suma_cuadrados=suma_cuadrados+a[i]**2
9 #se puede discrepar de poner esto aqui
10 import math
11 #se devuelve la raiz cuadrada de la suma de los cuadrados
12 return math.sqrt(suma_cuadrados)

[Ejercicio 7] Escribir una funcin que reciba una lista y que devuelva otra lista con copias
nicas de los elementos de la lista original, es decir, eliminando las repeticiones.
1 def copiasUnicas(a):
2 """Devuelve un vector con copias unicas de los elementos de a,
3 es ddecir, elimina las repeticiones"""
4 #vector de booleanos para marcar los repetidos, inicialmente False
5 esta_repetido=[False]*len(a)
6 #comparar cada elemento con todos los que siguen
7 for i in range(len(a)-1):
8 for j in range(i+1,len(a)):
9 #si coincide el valor
10 if a[i]==a[j]:
11 #esta repetido
12 esta_repetido[j]=True
13 #inicializacion del resultado
14 b=[]
15 #recorrer otra vez a
16 for i in range(len(a)):
17 #si el elemento no esta repetido
18 if not esta_repetido[i]:
19 #anadir al resultado
20 b.append(a[i])
21 #devolver
22 return b

[Ejercicio 8] Escribir funciones para calcular la media, varianza y moda de un vector de datos
numricos. Comprobar el resultado usando unos valores de prueba adecuados.
1 def indice_maximo(lista):
2 """Devuelve el indice en donde esta el maximo de una lista de
3 numeros"""
4 #se inicializa el indice a cero, el primero
5 i_max=0
6 #se recorren los restantes
7 for i in range(1,len(lista)):
8 #si el i esimo es mayor, se actualiza
9 if lista[i]>lista[i_max]:
10 i_max=i
11 #se retorna al posicion en donde esta el maximo
12 return i_max
13
2.7 Tipos y estructuras de datos bsicas: listas y arrays 123

14 def media(lista):
15 """Calcula la media de una lista de numeros, como real."""
16 #suma dividido entre el numero de elementos. Se convierte a float
17 #la suma para obtener decimales.
18 return float(sum(lista))/len(lista)
19
20 def varianza1(x):
21 """Calcula la varianza de una lista de numeros, como real. Se usa
22 la expresion Var(x)=E(x**2)-(E(x))**2."""
23 #media de la lista
24 m=media(x)
25 #inicializacion de la lista de x**2
26 #alternativamente se podria ir anadiendo con append
27 #dentro del bucle
28 x_2=[0]*len(x)
29 #para cada elemento de la lista
30 #se calcula el elemento i esimo de la lista de x**2
31 for i in range(0,len(x)):
32 x_2[i]=x[i]**2
33 #se devuelve el valor de la varianza
34 return media(x_2)-media(x)**2
35
36 def varianza2(x):
37 """Calcula la varianza de una lista de numeros, como real. Se usa
38 la expresion Var(x)=E((x-E(x))**2). Por lo tanto primero se calcula
39 E(x), despues (x-E(x))**2 y despues la media de esta."""
40 #media de los valores de la lista
41 m=media(x)
42 #inicializacion de la lista con (x-media(x))**2
43 x_e_x_2=[0]*len(x)
44 #se calcula el elemento i esimo de la lista con (x-media(x))**2
45 for i in range(0,len(x)):
46 x_e_x_2[i]=(x[i]-m)**2
47 #se retorna la varianza
48 return media(x_e_x_2)
49
50
51 #La implementacion de la funcion moda no es especialmente ortodoxa,
52 #he primado que sea pedagogica, y tampoco es eficiente.
53 #El ultimo elemento, si es distinto no se cuenta, lo cual da igual:
54 #Si la lista es de longitud uno, ese elemento es la moda.
55 #Si la longitud es mayor que uno, o todos son distintos y entonces
56 #cualquiera es la moda o este no se repite y entonces no es la moda
57 #o se ha repetido antes y ya se ha contado. Se puede mejorar
58 #facilmente anadiendo un vector de booleanos marcando los visitados.
59 def moda(lista_numeros):
60 """Devuelve la moda de una lista_numeros, es decir, el numero
61 que mas se repite.
62 NOTA: no valido para muestras de valores continuos."""
63 #caso especial, un solo elemento
64 if len(lista_numeros)==1:
65 return lista_numeros[0]
66 #inicializacion lista de contadores
67 lista_contadores=[0]*len(lista_numeros)
68 #para cada elemento excepto el ultimo
69 for i in range(0,len(lista_numeros)-1):
70 lista_contadores[i]=1
71 #para todos los siguientes
72 for j in range(i+1,len(lista_numeros)):
73 #si son iguales se incrementa el contador asociado a i
74 if lista_numeros[i]==lista_numeros[j]:
2.7 Tipos y estructuras de datos bsicas: listas y arrays 124

75 lista_contadores[i]=lista_contadores[i]+1
76 #alternativamente se puede usar sorted y devolver el
77 #primer valor de la lista ordenada
78 return lista_numeros[indice_maximo(lista_contadores)]
79
80 print moda([2,3,4,3,2,1,2,1,2,3,4,5])
81 print varianza1([2,3,4,3,2,1,2,1,2,3,4,5])
82 print varianza2([2,3,4,3,2,1,2,1,2,3,4,5])

[Ejercicio 9] Escribir una funcin que devuelva True si el nmero que se pasa como parmetro
es capica, False es caso contrario. Usando esa funcin escribir un programa que muestre los n
primeros nmeros capica. El nmero de capicas se pide por el teclado.
1 def es_capicua(n):
2 """devuelve true si es capicua, false en caso contrario"""
3 #si el numero convertido en cadena es igual que el numero
4 #con las cifras en orden inverso, usando str
5 return str(n)==str(n)[::-1]
6
7 #cuantos capicua se van a mostrar
8 cuantos=int(raw_input(cuantos?))
9 #contador capicuas
10 conta=0
11 #cada uno de los numeros que se prueban
12 num=0
13 #mientras no encuentre el numero de capicuas pedido
14 while conta < cuantos:
15 #si es capicua
16 if es_capicua(num):
17 #se muestra
18 print num
19 #se cuenta
20 conta+=1
21 #siguiente numero
22 num+=1

[Ejercicio 10] Escribir una funcin que devuelva True si el nmero que se pasa como par-
metro es automrfico, False en caso contrario. Un nmero es automrfico si aparece al final de su
cuadrado. Por ejemplo, 25 al cuadrado es 625, luego 25 es automrfico. Usando esa funcin escribir
un programa que muestre los n primeros nmeros capica. El nmero de automrficos se pide por
el teclado.
1 #Usa cadenas y slicing.
2 def es_automorfico(n):
3 """devuelve True si es automorfico, False en caso contrario"""
4 #numero al cuadrado convertido a cadena
5 cuadrado_str=str(n**2)
6 #longitud del numero original
7 lon_n=len(str(n))
8 #longitud del cuadrado
9 lon_cuadrado=len(cuadrado_str)
10 #parte final del cuadrado de la longitud del numero original
11 p_final_cuadrado=cuadrado_str[lon_cuadrado-lon_n:lon_cuadrado]
12 #si coincide con el numero original es automorfico
13 return p_final_cuadrado==str(n)
14
15 #cuantos automorficos se van a mostrar
16 cuantos=int(raw_input(cuantos?))
17 #contador automorficos
18 conta=0
19 #cada uno de los numeros que se prueban
20 num=0
2.7 Tipos y estructuras de datos bsicas: listas y arrays 125

21 #mientras no encuentre el numero de automorficos pedido


22 while conta < cuantos:
23 #si es automorfico
24 if es_automorfico(num):
25 #se muestra
26 print num
27 #se cuenta
28 conta+=1
29 #siguiente numero
30 num+=1

[Ejercicio 11] Escribir una funcin que reciba tres parmetros. Los dos primeros representan el
nmero de filas y columnas de una matriz. El tercero el valor inicial de los elementos de la matriz.
La funcin devuelve una lista de listas que representa esa matriz, cada elemento de la matriz igual
al tercer parmetro de la funcin.
1 def inicializaMatriz(fil,col,val):
2 """Inicializa una matriz al numero de filas y columnas indicado,
3 cada elemento de la matriz a val"""
4 #numero de filas
5 a = [None]*fil
6 #cada filal longitud igual a columnas, cada elemento igual a val
7 for i in range(fil):
8 a[i]=[val]*col
9 return a

[Ejercicio 12] Escribir una funcin que reciba una matriz de nmeros como parmetro, repre-
sentada como una lista de listas. La funcin devolver la suma de todos los valores de la matriz.
1 #version clasica recorriendo la matriz elemento a elemento
2 def suma_elementos_matriz(a):
3 """Calcula la suma de todos los elementos de una matriz"""
4 #variable para hacer el sumatorio
5 suma=0
6 #para el numero de filas de a
7 for i in range(len(a)):
8 #para el numero de columnas de a
9 #si a es rectangular, da igual usar len(a[i]) o len(a[0])
10 for j in range(len(a[i])):
11 suma=suma+a[i][j]
12 return suma
13
14 #version usando sum para calcular una lista con la suma de las filas
15 #despues se usa sum para sumar esa lista.
16 def suma_elementos_matriz_sum(a):
17 """Calcula la suma de todos los elementos de una matriz"""
18 #lista de suma de cada fila
19 suma_f=[]
20 #para cada fila
21 for i in range(len(a)):
22 #anadir su suma a la lista
23 suma_f.append(sum(a[i]))
24 #retornar la suma de la lista de sumas por filas
25 return sum(suma_f)

[Ejercicio 13] Escribir una funcin que reciba dos matrices y devuelva la suma matricial de
ambas.
1 def suma_matricial(a,b):
2 """Devuelve la suma de las matrices a y b"""
3 #se crea la matriz de alguna de las formas vistas
4 #el tamano del resultado es igual que el de los parametros de entrada
5 c=crea_matriz(len(a),len(a[0]))
2.7 Tipos y estructuras de datos bsicas: listas y arrays 126

6 #cada elemento i,j del resultado es la suma de los elementos i,j


7 #de a y b
8 for i in range(len(a)):
9 for j in range(len(a[0])):
10 c[i][j]=a[i][j]+b[i][j]
11 return c

[Ejercicio 14] Escribir una funcin que reciba una matriz y devuelva una lista con la suma de
cada fila por separado.
1 def suma_filas_matriz(a):
2 """Devuelve la suma de los elementos de cada fila de a por separado"""
3 #alternativamente se podria crear vacia y anadir con append, cuidado
4 #con la variable usada entonces, reinicializar a cero cada vez
5 suma_filas=[0]*len(a)
6 #para cada fila
7 for i in range(len(a)):
8 #sumar cada elemento
9 for j in range(len(a[0])):
10 suma_filas[i]=suma_filas[i]+a[i][j]
11 return suma_filas
12
13 #version usando la funcion sum por filas
14 def suma_filas_matrizSum(a):
15 """Devuelve la suma de los elementos de cada fila de a por separado"""
16 #en realidad en este caso no hace falta inicializar a cero
17 suma_filas=[0]*len(a)
18 #para cada fila
19 for i in range(len(a)):
20 #se suman los elementos de la fila con sum
21 suma_filas[i]=sum(a[i])
22 return suma_filas

[Ejercicio 15] Escribir una funcin que reciba una matriz y devuelva una lista con la suma de
cada columna por separado.
1 #lo mismo por columnas. No se puede hacer usando sum, a no ser
2 #que se trasponga antes.
3 def suma_columnas_matriz(a):
4 """Devuelve una lista con la suma de cada columna de a por separado"""
5 suma_columnas=[0]*len(a[0])
6 #basicamente, para cada columna
7 for j in range(len(a[0])):
8 #recorrerla y sumar sus elementos
9 for i in range(len(a)):
10 suma_columnas[j]=suma_columnas[j]+a[i][j]
11 return suma_columnas

[Ejercicio 16] Escribir una funcin que reciba una matriz y que devuelva el mayor de sus
elementos.
1 #max devuelve el valor de una lista pero no el de una lista de listas
2 #por eso tiene sentido implementar esta funcion
3 #version clasica recorriendo la matriz.
4 def max_matriz(a):
5 """Devuelve el mayor elemento de una matriz representada como lista
6 de listas"""
7 #tambien se podria haber inicializado al maximo de la primera fila y
8 #comenzar i en 1
9 maximo=a[0][0]
10 #se recorre la matriz
11 for i in range(len(a)):
12 for j in range(len(a[i])):
2.7 Tipos y estructuras de datos bsicas: listas y arrays 127

13 #si se encuentra uno mayor que el maximo actual, es el


14 #nuevo maximo
15 if a[i][j]>maximo:
16 maximo=a[i][j]
17 return maximo
18
19 #max devuelve el valor de una lista pero no el de una lista de listas
20 #por eso tiene sentido implementar esta funcion
21 #version calculando el maximo de los maximos por filas.
22 def max_matriz_max(a):
23 """Devuelve el mayor elemento de una matriz representada como lista
24 de listas"""
25 #Inicializo maximo al maximo de la primera fila
26 maximo=max(a[0])
27 #se recorren las filas posteriores a la 0
28 for i in range(1,len(a)):
29 #maximo de la fila actual
30 max_fila=max(a[i])
31 #si es mayor que el maximo actual, es el nuevo maximo
32 if max_fila>maximo:
33 maximo=max_fila
34 return maximo

[Ejercicio 17] Escribir una funcin que reciba una matriz y que devuelva su traspuesta.
1 #evidentemente si no es rectangular no tiene sentido.
2 def traspuesta(a):
3 """Devuelve la traspuesta de a"""
4 #el resultado tiene de numero de filas las columnas de a y de numero
5 #de columnas las filas de a
6 b=zeros(len(a[0]),len(a))
7 #para cada elemento de a
8 for i in range(len(a)):
9 for j in range(len(a[i])):
10 #se asigna al elemento j,i de b el i,j de a
11 b[j][i]=a[i][j]
12 return b

[Ejercicio 18] Escribir una funcin que reciba dos matrices y devuelva su producto matricial.
1 def producto_matricial(a,b):
2 """Devuelve el producto matricial de a y b"""
3 #en este caso, como se va a sumar repetidas veces sobre cada c[i][j]
4 #es obligatorio inicializar c toda a ceros
5 #el tamano del resultado es filas de a y columnas de b
6 c=zeros(len(a),len(b[0]))
7 #para cada elemento del resultado
8 for i in range(len(a)):
9 for j in range(len(b[0])):
10 #acumular en c[i][j] el producto de a[i][k] y b[k][j]
11 for k in range(len(a[0])):
12 c[i][j]=c[i][j]+a[i][k]*b[k][j]
13 return c

[Ejercicio 19] Usando Numpy y las operaciones vectorizadas sobre arrays, escribir una funcin
que calcule la varianza de una lista de nmeros sin usar bucles. Usar la formula E((x E(x))2 )
1 def varianza3(x):
2 """Devuelve la varianza de una lista de numeros"""
3 #se construye un array con los valores de la lista
4 x_array=numpy.array(x,dtype=float)
5 n=x_array.shape[0]
6 #la media es la suma dividido entre el numero de elementos
7 m=sum(x_array)/n
128

8 #las operaciones con escalares se hacen sobre cada elemento del array
9 #por lo tanto de esta forma se calcula el cuadrado de la diferencia
10 #de cada elemento a la media
11 x_e_x_2=(x_array-m)**2
12 #la varianza es la media del array anterior
13 return sum(x_e_x_2)/n

[Ejercicio 20] Usando Numpy y las operaciones vectorizadas sobre arrays, escribir una funcin
que calcule la media de los elementos pares de una matriz sin usar bucles.
1 #En alguna parte del programa escribir
2 import numpy
3
4 def mediaPares(a):
5 """Devuelve la media de los numeros pares de una lista de listas"""
6 #se copnvierte en un array de numpy
7 an=numpy.array(a,dtype=int)
8 #an %2==0 es 1 en donde an[i][j] es par, 0 en el resto
9 #sum de un array de dos dimensiones es un array de una dimension
10 #con la suma por filas. La suma de este es la suma total.
11 #an*(an %2==0) es 0 en donde an[i][j] es impar, el valor original en
12 #donde es par. La suma de esta matriz es la suma de los pares.
13 #La suma de an %2==0 es el numero de pares. El cociente de las dos
14 #sumas es la media de los pares. Se convierte una a float para obtener
15 #decimales
16 return float(sum(sum(an*(an %2==0))))/sum(sum(an %2==0))

2.7.13. Ejercicios Propuestos


[Ejercicio 1] Escribir una funcin que reciba como parmetros una lista y un valor escalar. La
funcin devuelve el ndice que ocupa la ltima repeticin del valor escalar dentro de la lista o None
si no se encuentra.
[Ejercicio 2] Escribir una funcin que reciba como parmetros una lista y un valor escalar. La
funcin devuelve una lista con los ndices de cada repeticin del valor escalar dentro de la lista o
None si no se encuentra.
[Ejercicio 3] Repetir el ejercicio que expurga las repeticiones de los elementos de una lista,
usando el mtodo append y el operador in.
[Ejercicio 4] Escribir una funcin que reciba un parmetro, representando el tamao de una
matriz cuadrada. La funcin devuelve una lista de listas que contiene la matriz identidad.
[Ejercicio 5] Escribir una funcin que reciba un parmetro, representando una matriz cuadrada.
La funcin devuelve True si la matriz es diagonal, False en caso contrario.
[Ejercicio 6] Escribir una funcin que reciba un parmetro, representando una matriz cuadrada.
La funcin devuelve True si la matriz es simtrica, False en caso contrario.
[Ejercicio 7] Usando append, Escribir una funcin que reciba una matriz y devuelva una lista
con la suma de cada columna por separado.
[Ejercicio 8] Escribir una funcin que reciba una lista de listas de nmeros representando una
matriz y que devuelva una lista con el mximo de cada fila por separado
[Ejercicio 9] Escribir una funcin que reciba una lista de listas de nmeros representando una
matriz y que devuelva una lista con el mximo de cada columna por separado
[Ejercicio 10] Repetir el anterior usando la traspuesta del parmetro y la funcin que calcula
el mximo de cada fila por separado.
Parte III
Introduccin a las bases de
datos

129
CAPTULO 3

Introduccin a las Bases de Datos

3.1. Conceptos de bases de datos


3.1.1. Definicin de Bases de Datos (BD) y de Sistema de Gestin de Bases de Datos
(SGBD).
Una base de datos se puede definir como un conjunto de informacin interrelacionada, que se
almacena de forma estructurada para ser utilizada posteriormente. Actualmente, cuando hablamos
de base de datos nos referimos a aquellas que se almacenan de forma digital, y cuya informacin
se procesa mediante programas especficos. Una base de datos contiene informacin asociada a un
determinado sistema u organizacin, ya sea de una empresa de transportes, una compaa area,
una farmacia, la secretara de la Universidad o de nuestra pequea biblioteca.
Originalmente esta informacin se almacenaba en diferentes ficheros (fichero de productos, de
empleados, de pedidos, etc.) que eran accedidos por diversos programas (gestin de pedidos, nomi-
nas, contabilidad, etc.).
Esta organizacin de ficheros y programas independientes para manejarlos, pronto empez a
presentar diversos problemas: se deban organizar muy bien los ficheros y coordinar muy bien los
programas para compartir los mismos formatos, para que no se almacenara informacin redundante,
para permitir accesos concurrentes, para establecer permisos a los distintos usuarios, etc.
Un sistema de gestin de base de datos (SGBD) es un programa que nos permiten
manipular la informacin que conforma una base de datos y que aporta soluciones a los problemas
ya mencionados.
Por tanto no es lo mismo una base de datos (BD) que un gestor de bases de datos (SGBD),
aunque en muchas ocasiones nos referimos a ambos con el mismo trmino: Base de Datos. Es decir,
la BD del vdeo club es la informacin asociada al mismo (pelculas, juegos, clientes, alquileres, etc.)
mientras que el SGBD es el programa que utilizamos para mantener dicha informacin (Postgres,
Oracle, SQL Server, MySQl, Access u otros).
3.1.2. Funcionalidad de un SGBD
Hemos comentado que un gestor de base de datos (SGBD) es un programa, aunque real-
mente de trata de un conjunto de programas interrelacionados que nos permiten gestionar diversas
bases de datos.
Realmente se puede considerar como un Sistema Operativo de propsito especfico, ya que sus
funcionalidades son similares.
Cuando hablamos de un SGBD hablamos de un sistema que nos ofrece las siguientes funciona-
lidades.

Gestin de almacenamiento: Es una de las ms importantes funcionalidades de un SGBD,

130
3.1 Conceptos de bases de datos 131

ya que su principal objetivo es el almacenamiento de informacin as como la recuperacin


de la misma de forma eficiente. Los SGBD cuentan con estructuras y mecanismos para poder
realizar la manipulacin de datos (insercin, modificacin y borrado) y su localizacin de
manera muy optimizada. Adems de lo que es la organizacin de la informacin en disco los
SGBD tambin disponen de mecanismos para gestionar la informacin que se mantiene en
memoria principal.
Gestin de usuarios: Ya que una BD puede ser accedida por mltiples usuarios se hace
necesario llevar una gestin de los mismos, pudiendo asignar diferentes privilegios a cada uno.
Gestin de integridad: Otro aspecto fundamental es mantener una consistencia e integridad
entre los datos almacenados. Los SGBD habilitan procedimientos para imponer restricciones
a la informacin de la BD.
Gestin de concurrencia: Como consecuencia del acceso simultneo a la informacin de
una BD por distintos usuario o programas, los SGBD implementan sistemas de control de la
concurrencia de manera que, en la medida de lo posible, cada usuario tenga la sensacin de
que es el nico que est accediendo a la BD en un momento dado.
Gestin de transacciones: Existen muchas operaciones que si se ejecutan a medias pueden
provocar inconsistencia entre los datos. Uno de los ejemplos ms ilustrativos es la transferencia
de x euros de una cuenta A a otra cuenta B, este tipo de operaciones se componen de varias
sub-operaciones: comprobar que A tiene saldo, descontar a A x euros y sumar a B x euros.
Este tipo de operaciones se denomina transacciones. El SGBD debe garantizar que: o se
realizan todas las sub-operaciones o no se realiza ninguna. Un sistema as, se denomina sistema
transaccional.
Gestin de recuperaciones: Los ordenadores, de vez en cuando, caen o se cuelgan (por
muy diversos motivos), y an as los SGBD deben garantizar la consistencia de los datos. Para
ello disponen de mecanismos de recuperacin, de tal forma que ante una cada el sistema se
recupere en la versin consistente ms reciente posible. Estos mecanismos estn ntimamente
ligados a la Gestin de transacciones.

Todas estas funcionalidades se basan en distintos gestores o mdulos que no son independientes
sino que trabajan de forma muy interrelacionada.
Por encima de todos estos gestores, que en la mayora de los casos resultan transparentes para
los usuario del SGBD, disponemos de un intrprete que nos permitir comunicarnos con el propio
SGBD utilizando un determinado lenguaje. El lenguaje ms comn es el SQL. Mediante rdenes
SQL podremos crear nuestra BD, insertar, modificar, borrar y consultar datos, definir usuarios,
privilegios, restricciones sobre los datos, y muchas cosas ms. La mayora de los SGBD tambin
disponen de diferentes lenguajes de programacin con los que podremos trabajar con nuestros datos.
En muchos casos no se hace necesario un lenguaje para manejar nuestro SGBD, ya que dispo-
nemos de interfaces grficas que nos facilitan las operaciones y resultan de gran utilidad cuando
el usuario es inexperto. Como es lgico estas interfaces grficas tambin presentan importantes
deficiencias, no se puede tener todo.
Aunque a da de hoy hay muchos tipos de SGBD funcionando (algunos de ellos realmente
antiguos), los ms estandarizados son los SGBD Relacionales (SGBDR). A lo largo de este captulo,
cuando mencionemos un SGBD nos referiremos siempre a los Relacionales, ya que queda fuera de
este contexto estudiar otros tipos de gestores.
3.1.3. Aplicaciones sobre Bases de Datos.
Cuando queremos trabajar con una base de datos lo normal es desarrollar una aplicacin que se
comunica con el SGBD. Las dos arquitecturas ms utilizadas son:
3.2 Modelos de Datos 132

Aplicaciones de Escritorio: se trata de programas implementados en un determinado lenguaje


de programacin (C++, Java, python, etc.) que hace de host o anfitrin y que se comunica,
utilizando alguna librera de programacin, con el SGBD. Este tipo de arquitectura se deno-
mina de dos niveles. Con el lenguaje anfitrin (en l se aloja el cdigo para comunicarse con el
SGBD) desarrollamos el interface (normalmente grfico) que utiliza el usuario para manipular
la informacin de la base de datos.
Aplicaciones Web: aqu hablamos de arquitectura de tres niveles: navegador web, servidor web
y servidor de bases de datos (SGBD). En este caso es el servidor web el que mediante algn
lenguaje de programacin (es muy frecuente el uso de PHP) se comunica con el SGBD para
atender las peticiones que hace el usuario a travs de su navegador. Las siglas LAMP se
asocian a este tipo de arquitectura y se corresponden con: Linux, con sistema operativo en
el que se instala el servidor web Apache, que se comunica con el servidor de bases de datos
MySql utilizando el lenguaje PHP. Es frecuente que el MySql y el Apache corran sobre el
mismo Linux.

3.2. Modelos de Datos


Ya que el objetivo de una base de datos es reflejar la informacin de un determinado sistema,
se hace necesario compartir o establecer unas herramientas comunes que nos permitan trabajar con
datos.
Se define un Modelo de Datos como una coleccin de herramientas que nos permiten describir
los datos con los que vamos a trabajar. Con un modelo de datos podremos representar (en algunos
casos de forma grfica):
los propios datos
las relaciones entre ellos
la semntica de los datos
las restricciones de los datos
Dependiendo del nivel de abstraccin con el que trabajemos dispondremos de distintos Modelos
de Datos. Nosotros vamos a distinguir tres niveles
1. Nivel lgico basado en Objetos: a este nivel vamos a trabajar con objetos. Intentaremos
identificar los objetos de nuestro sistema (productos, clientes, asignaturas, pedidos, vuelos,
etc.); ver qu caractersticas los definen y cmo se relacionan unos objetos con otros. A este
nivel se trabaja con el modelo de datos denominado Entidad-Relacin (E-R), en el que grfica-
mente representaremos la informacin de nuestro sistema. Con este modelo de datos daremos
el primer paso para disear nuestra futura base de datos.
2. Nivel lgico basado en Registros: En este nivel, con menor grado de abstraccin que el
E-R, vamos a trabajar con registros o filas compuestas por campos en las que almacenaremos
nuestros datos. Ahora un producto lo veremos como una tupla o fila formada por los campos
cod_producto, nombre, precio, existencias. El modelo ms importante con el que se trabaja a
este nivel es el Modelo Relacional. Bsicamente se trata de agrupar estos registros en tablas,
pero ya lo veremos posteriormente con mayor detalle.
3. Nivel Fsico: a este nivel lo que nos importa es poder detallar la forma en la que se almacenan
los datos. Trabajamos con un nivel de detalle mayor, ahora nos preocuparemos de definir si el
precio se almacena como un entero o un decimal o si el cod_producto se debe guardar como
una cadena de tres letras seguidas de dos dgitos.
3.3 Modelo Relacional 133

3.3. Modelo Relacional


3.3.1. Conceptos Bsicos
Podemos considerar el Modelo Relacional como el ms comn en la implementacin de bases de
datos. Tal y como mencionamos anteriormente los SGBD ms habituales son los SGBD Relacionales,
es decir, los basados en este modelo. El elemento fundamental de este modelo es la relacin que no es
otra cosa que una tabla. El origen de este modelo proviene de las matemticas, ms concretamente
de la teora de conjuntos y relaciones, de ah su nombre. De forma sencilla podemos ver una tabla
como una serie de columnas fijas y un nmero de filas variable. Veamos un ejemplo:

P RODU CT OS
cod_producto nombre precio existencias
MA172 Manzana 2.35 50
PE111 Peras 3.14 72
KW001 Kiwis 4.56 61
PL011 Pltanos 1.69 54

Una relacin (tabla) est formada por un nmero fijo de atributos (columnas o campos) y uno
variable de tuplas( filas o registros). Disear una BD consiste bsicamente en disear un conjunto de
tablas para almacenar nuestros datos; y disear una tabla consiste a su vez en definir las columnas
que la forman. A cada columna le daremos un nombre, le asociaremos un tipo de datos (entero,
cadena, decimal, fecha, etc.) y las restricciones que se consideren necesarias.
Vamos a plantearnos que queremos llevar un control de los pedidos de nuestra empresa Fruticaos
S.A. y por tanto decidimos crear algunas tablas ms:

CLIEN T ES P EDIDOS

id_cliente Nombre DNI id_pedido id_cliente fecha


1 Luis 02345678F 101 1 2011-07-12
2 Pepa 52555698 D 102 1 2011-08-21
3 Paco 103 2 2011-08-25
4 Luis 535678X 110 3 2011-09-12
3.3 Modelo Relacional 134

DET ALLES_P EDIDO


id_pedido cod_producto cantidad
101 MA172 10
101 PE111 12
103 KW001 7
103 MA172 13
102 PE111 2
Aprovechando nuestro ejemplo vamos a seguir explicando aspectos bsicos del Modelo Rela-
cional. Una idea que subyace es que la informacin solo debe guardarse una vez, debemos evitar
almacenar informacin de forma redundante. Podramos haber planteado guardar en la tabla de
P EDIDOS la informacin del cliente que realiza cada pedido, pero en el momento que un cliente
realizara ms de un pedido repetiramos sus datos en distintas filas. Hasta aqu el problema podra
ser nicamente el desperdicio de espacio, cosa que al precio del byte no parece muy importante.
Pero si esa informacin del cliente empieza a sufrir modificaciones la cosa empezara a complicarse,
ya que nos obligar a mantener todas las filas asociadas a los pedidos de dicho cliente con la misma
informacin, es decir, que la informacin sea consistente.
Con el sencillo mecanismo de repetir ciertas columnas en diferentes tablas podemos solucionar
muchos de nuestros problemas. En nuestro ejemplo vemos que en la tabla P EDIDOS se repite
la misma columna id_cliente que en la tabla CLIEN T ES. Por lo que ya no se hace necesario
repetir toda la informacin del cliente en la tabla P EDIDOS, sino sencillamente almacenamos su
identificador, que nos permitir identificar al cliente de dicho pedido. Aqu surgen tres conceptos
fundamentales de este modelo:

Clave primaria (primary key, PK): En una tabla se denomina clave primaria a la columna
(o columnas) que nos permiten identificar de forma nica a una fila. Es decir que dado un valor
de la clave primaria solo podemos encontrar como mucho una fila. Por tanto los valores de la
clave primaria no se pueden repetir dentro de la tabla. Debido a esa capacidad de identificar
a una sola fila, en muchas tablas la columna que forma la clave primaria se le suele llamar
identificador (id_cliente, id_pedido), aunque tambin es frecuente utilizar el trmino cdigo
(cod_producto). Es importante ver que id_cliente funciona como clave primaria en la tabla
de CLIEN T ES y que no lo hace en la tabla de P EDIDOS, donde podra tomar valores
repetidos (tantos como pedidos realice un mismo cliente).
Nota: en las tablas se han representado mediante negrita las columnas que forman la clave
primaria.

Clave ajena (foreign key, FK): En una tabla se denomina clave ajena a aquella que hace
referencia a una clave primaria de otra tabla. Este es el mtodo que tenemos para no tener que
repetir la misma informacin en diferentes tablas. Los valores de una FK se pueden repetir
dentro de la tabla, pero deben existir previamente en la tabla a la que hacen referencia.
En nuestro caso la columna id_cliente de la tabla de P EDIDOS es FK de la tabla de
CLIEN T ES y de esta forma no tenemos que guardar toda la informacin del cliente que
hizo el pedido, sino nicamente su identificador. Como ya acabamos de comentar. Adems
no podremos almacenar un pedido con un valor de id_cliente que no exista en la tabla de
clientes.
Nota: en las tablas se han representado mediante cursiva las columnas que son clave ajena.

Clave candidata (UNIQUE): Evidentemente la columna DNI de la tabla de CLIEN T ES


tiene casi las mismas caractersticas que id_cliente, ya que tampoco debera repetirse (en
este caso tendramos dos clientes con el mismo DNI o el mismo cliente guardado dos veces)
y tambin permitira identificar de forma nica a una fila. Cuando esto ocurre se dice que
3.3 Modelo Relacional 135

son una clave candidata, por lo que toda clave primaria es a su vez una clave candidata. Por
tanto en una tabla podremos tener varias claves candidatas pero solo una de ellas ser la clave
primaria, normalmente la que nos resulte ms cmoda. A las claves candidatas que no son
elegidas como claves primarias se las denomina tambin valores nicos (UNIQUE) y presentan
una sutil diferencia con las PK: pueden dejarse sin valor (con valor null) como en el DNI de
Paco.

Ya que hemos mencionado el valor null vamos a comentar algo sobre l. En principio el valor
nulo es un valor vlido para cualquier columna a no ser que especficamente lo prohibamos. Los
valores nulos son un mal necesario que generan gran nmero de problemas. Para empezar en la
mayora de los casos no sabemos qu significan. En nuestro caso Paco tiene un null en el campo
DNI, pero realmente no sabemos si es debido a que Paco no tiene DNI (por ser un nio o un
extranjero sin papeles) o que se trata de una persona mayor que cuando le dimos de alta no llevaba
el DNI, ni se acordaba de l. La propia representacin de valor nulo tambin nos puede generar
problemas. Una alternativa es utilizar la palabra null para representarlo, otra es dejarlo en blanco,
pero en este caso, si nos referimos a una cadena de texto, la representacin del valor nulo coincidir
con una cadena de blancos o tabuladores, incluso con la cadena vaca. Si hablamos de nmeros no es
lo mismo un cero que un nulo aunque en este caso su representacin no lleva a engaos. Los SGBD
nos facilitan mecanismos para poder almacenar y operar con valores nulos.
3.3.2. Diseo de tablas
Como hemos visto, si repetimos ciertas columnas en distintas tablas podemos evitar repetir
innecesariamente informacin. La cuestin est en cmo realizar esto de forma que podamos guardar
y recuperar correctamente nuestros datos. Para entender cmo se deben relacionar unas tablas con
otras a travs de PKs y FKs vamos a definir tres tipos de asociaciones entre registros de distintas
tablas:

1. Tipo de Asociacin 1:1 (Uno a Uno): Un registro de una tabla A se relaciona a lo sumo
con otro de la otra tabla B, y viceversa. Imaginemos que tenemos una tabla con informacin
de los ciudadanos (id_ciudadano, nombre, direccin) y otra tabla con informacin sobre
sus defunciones (id_defuncin, id_ciudadano, fecha_defuncion, lugar_defuncion). Eviden-
temente uno slo se muere una vez y una defuncin solo se corresponde con un ciudadano.
Alguien podra plantear fusionar las dos tablas en solo una, con las columnas (id_ciudadano,
nombre, direccin, fecha_defuncion, lugar_defuncion), pero esto conllevara mantener valores
nulos para fecha_defuncion y lugar_defuncion para todos los ciudadanos vivos, cosa que si se
puede evitar, es mejor evitarla.

2. Tipo de Asociacin 1:n (Uno a muchos): una fila de una tabla A se puede asociar con n
filas de la tabla B, pero una de la B solo se puede asociar como mucho con una de la tabla A.
Este es el caso de los pedidos y los clientes: un cliente puede realizar muchos pedidos, pero un
pedido slo est asociado a un cliente. Est claro que para poder representar esta restriccin
debemos colocar la FK id_cliente en la tabla P EDIDOS, ya que si lo hiciramos al revs
y pusiramos la FK id_pedido en la tabla CLIEN T ES entonces estaramos diciendo es un
cliente solo puede realizar un pedido, y un pedido puede estar asociado a varios clientes. A la
hora de disear las tablas el propio sentido comn nos dir cmo colocar la FKs.

3. Tipo de Asociacin n:m (muchos a muchos): una fila de una tabla A se puede asociar
con n de la tabla B, y viceversa. Este es el caso de los pedidos y los productos: un producto
puede aparecer en muchos pedidos, y un pedido puede contener muchos productos. Este caso
no se soluciona poniendo la FK cod_producto en la tabla de P EDIDO, ni la FK id_pedido
en la tabla de P RODU CT OS. Para ello debemos crear una tabla intermedia, en nuestro caso
3.4 Modelo Entidad-Relacin 136

id_pedido

fecha
nombre precio
Cantidad
cod_producto
(0,n) (0,m)
PRODUCTOS Detalles PEDIDOS

(0,n)
existencias N:M

(1,1)
id_cliente
CLIENTES encarga 1:N

nombre DNI

Figura 3.1: Diagrama Entidad-Relacin del sistema de Pedidos.

DET ALLES_P EDIDO, en la que podremos asociar productos con pedidos y pedidos con
sus productos. Ntese que en esta tabla intermedia la PK est formada por las dos FKs, es
decir que en un pedido no puede aparece el mismo producto ms de una vez, si as fuese podra
aparece con diferentes cantidades y generar una inconsistencia. Es decir si nos encontrramos
con las filas (101, MA172, 10) y (101, MA172, 11), no sabramos si nos piden 10, 11 22
kilos de manzanas. Al definir as la PK, evitamos que se repitan en la tabla el par de valores
(cod_producto, id_pedido), y solucionamos el problema.

3.4. Modelo Entidad-Relacin


3.4.1. Introduccin
Como ya se coment el Modelo E-R es un modelo de datos orientado a objetos. En este modelo
los objetos se denominan Entidades, de ah su nombre. El objetivo es identificar los objetos de
nuestro sistema y ver cmo se relacionan. No se pretende aqu explicar en profundidad este modelo,
pero si es importante resaltar que el diseo de bases de datos se hace utilizando este modelo. Los
usuarios de BD con poca formacin disean tablas directamente en el modelo relacional, tal y como
se explic en el apartado anterior, pero los profesionales no lo hacen as. Se usa este modelo en
alguna de sus distintas versiones. El modelo original fue desarrollado por Chen y nos permite crear
diagramas que representan la informacin de nuestro sistema. El aspecto ms interesante de este
modelo es que nos permite trabajar a un nivel de abstraccin alto a la hora de dibujar nuestro
diagrama E-R; y una vez realizado el diagrama en este modelo, existe un mtodo prcticamente
automtico, que nos traduce nuestros diagrama E-R en un conjunto de tablas del Modelo Relacional
que es directamente implementable en un SGBD Relacional.
De hecho existen herramientas que dado un diagrama E-R nos generan el cdigo SQL que crea
nuestra base de datos.
3.4.2. Ejemplo
Volvamos a nuestra base de datos de Pedidos. En este sistema identificamos tres entidades:
Productos, Pedidos y Clientes. Veamos el diagrama de la figura 3.1:
3.5 Uso bsico del lenguaje SQL 137

Cada entidad es definida por una serie de atributos, por ejemplo un producto cuenta con un
identificador, un nombre, un precio y unas existencias. Las entidades se representan mediante un
rectngulo y sus atributos mediante elipses. Las relaciones entre entidades se representan mediante
un rombo y si existe algn atributo que cualifique la relacin usamos una elipse, como es el caso
de la cantidad. Las relaciones se etiquetan con el tipo de cardinalidad en nuestro caso la relacin
entre pedidos y clientes es de 1:N y la de pedidos y productos de N:M, de manera similar a lo que
se explic en el Diseo de tablas.
Lo que es realmente importante es que a partir de este diagrama se podra generar, de forma
automtica, el cdigo SQL bsico para crear la base de datos de pedidos.

3.5. Uso bsico del lenguaje SQL


Ya hemos hecho referencia al SQL como un lenguaje estndar para trabajar con bases de datos.
A menudo se diferencia entre lenguajes de definicin de datos (LDD o DDL en ingls) y lenguajes de
manipulacin de datos (LMD o DML en ingls). Los LDD son aquellos que incluyen todas aquellas
rdenes que nos permiten crear, modificar y borrar objetos en nuestros SGBD, ya sean base de
datos, tablas, tipos de datos, ndices, usuarios, etc. Con el LDD definiremos la estructura en la
que guardaremos nuestros datos. Los LMD incluyen aquellas rdenes que nos permiten insertar,
modificar, borrar y consultar informacin en nuestra BD. El SQL (Structured Query Language) es
un lenguaje comercial que soporta ambos tipos de rdenes. Es un lenguaje muy antiguo que ha ido
soportando el paso del tiempo y se ha ido adaptando en lo posible a algunas novedades de los SGBD,
pero sigue siendo el ms utilizado actualmente e integrado en los todos los SGBD comerciales ms
populares. Existe un estndar SQL que se va revisando cada cierto tiempo, la ultima versin es
del 2008, pero cada SGBD dispone de su propia implementacin del mismo, con alguna diferencias
entre unos y otros.
3.5.1. rdenes de definicin de datos (LDD)
Antes de empezar a trabajar con nuestra base de datos tenemos que disearla y crearla. Se trata
de construir la estructura que albergar nuestros datos. Esta estructura debera ser fija, pero en la
realidad siempre est sujeta a cambios o nuevas versiones. Las dos rdenes bsicas para nosotros
sern las de:

create database mibd: con la que le diremos al SGBD que cree una base de datos; y

create table mitabla ( ...): con la le diremos al SGBD que cree una tabla.

Ya hemos comentado que es posible ejecutar estas rdenes mediante una interface grfica y sin
necesitad de conocer la sintaxis del SQL para hacerlo.
Retomando nuestro ejemplo el cdigo SQL que creara nuestra BD con sus tablas sera:

/* ------------------------------------------------*/
/* Cdigo SQL para la creacion de la Base de Datos */
/* ------------------------------------------------*/

/* Creacion de la base de datos*/


CREATE DATABASE pedidos;

/* Creacin de tablas */
CREATE TABLE clientes (
id_cliente integer not null primary key ,
nombre char(15),
DNI varchar(10)
3.5 Uso bsico del lenguaje SQL 138

);

CREATE TABLE productos (


cod_producto char(5) not null primary key ,
nombre varchar(15),
precio decimal (5,2) ,
existencias integer
);

CREATE TABLE pedidos (


id_pedido integer not null primary key,
fecha date,
id_cliente integer not null references clientes
);

CREATE TABLE detalles_pedido (


id_pedido integer not null references pedidos,
cod_producto char(5) not null references productos,
cantidad integer,
PRIMARY KEY ( id_pedido,cod_producto )
);

Como se puede ver la creacin de una tabla se concreta en ir definiendo cada columna con su
tipo de dato y sus restricciones. El texto que queda entre los /* y */ son comentarios.
3.5.2. rdenes de manipulacin de datos (LMD)
Para ejecutar ests rdenes es necesario obviamente tener ya creadas las tablas. Las rdenes
bsicas son:

insert: con esta orden insertaremos filas en una tabla. Ejemplo

insert into productos values (MA172, Manzana,2.35, 50)

update: con esta orden modificaremos filas en una tabla. Ejemplo

update productos
set precio = precio * 1.05
where cod_producto = MA172;

De esta forma incrementamos en precio de las manzanas en un 5 por ciento

delete: con esta orden borraremos filas de una tabla. Ejemplo

delete from productos


where precio > 50;

As borramos los productos cuyo precio supere los 50 euros.

select: con esta orden buscamos informacin en una tabla. Ejemplo


3.6 SGBD en entornos profesionales de la ingeniera 139

select cod_producto, nombre


from productos
where existencias = 0;

As obtendremos los productos sin existencias.

Las rdenes ms complejas son las bsquedas (los selects) por lo que vamos a profundizar un poco
ms en ellas. El select que hemos visto utiliza una sola tabla, pero lo normal es que necesitemos
consultar varias tablas para obtener la informacin que buscamos. Para esto es necesario reunir
(hacer joins) la informacin distribuida por diferentes tablas. Esto se especifica en la clusula from
del select. Cuando deseemos reunir la informacin de dos tablas es necesario decir al intrprete a
travs de que columna mezclaremos la informacin de ambas tablas, es decir, qu columna debe
poseer el mismo valor en ambas tablas. La sintaxis es:

select columna, columna , ...


from tabla1 join tabla2 on tabla1.campo_comun = tabla2.campo_comun
where condicion de fila;

Como ejemplo vamos a obtener los pedidos con su fecha hechos por los clientes cuyo nombre sea
Luis

select id_pedido, fecha


from pedidos join clientes on pedidos.id_cliente = clientes.id_cliente
where nombre ilike Luis;

En algunos casos es necesario calcular ciertos valores a partir de un conjunto de filas, para ello
necesitas poder agrupar filas y luego aplicar alguna funcin a todas ellas. Como ejemplo vamos
a obtener el coste total de los pedidos hecho entre septiembre y octubre de 2011. Necesitaremos
consultar tres tablas y por tanto haremos el join de las mismas y posteriormente agrupar por cada
pedido, es decir formar un grupo con todas las filas asociadas a un mismo pedido.

select id_pedido,
sum (cantidad * precio)
from pedidos join detalles_pedidos on pedidos.id_pedido= detalles_pedido.id_pedido
join productos on detalles_pedidos.id_producto = prodcutos.id_prodcuto
where fecha between 2011-09-01 and 2011-10-31
group by pedidos.id_pedido;

3.6. SGBD en entornos profesionales de la ingeniera


3.6.1. Introduccin
Cualquier entorno profesional suele tener asociado un sistema de informacin. Hace aos la
relacin de la ingeniera con la informtica se vea ms centrada en la capacidad de clculo de los
ordenadores mientras que los bancos eran los que desarrollaban sistemas cuya caracterstica era
trabajar con grandes volmenes de informacin.
Algunos sistemas de ingeniera, como los sistemas de CAD, han manejado importantes vol-
menes de informacin, pero no gestionados por SGBD de propsito general. Actualmente muchas
ingenieras utilizan un SGBD para el propio funcionamiento de la empresa, esto ha supuesto que
los SGBD sean conocidos y se empiecen a utilizar en los propios procesos de ingeniera y estn
reemplazando a las habituales Hojas de Clculo.
3.6 SGBD en entornos profesionales de la ingeniera 140

El uso de Hojas de Clculo se ha estandarizado ya que no necesitan de unos conocimientos


previos tan especializados como las BD. An as son muchos los profesionales que cuando descubren
las ventajas de una BD, abandonan las Hojas de Clculo. Est claro que cada herramienta tiene su
utilidad y es para lo que es.
Hoy en da los SIG (Sistemas de Informacin Geogrficos) han revolucionado el mundo de las
bases de datos. Algunos SGBD ya incorporan funcionalidades para manejar este tipo de informacin
espacial como por ejemplo Postgis.
3.6.2. Bases de Datos espaciales y geogrficas
El soporte de los datos espaciales en las BD es importante para el almacenamiento y la realizacin
de consultas eficientes de los datos basados en las posiciones espaciales. Dos tipos de datos espaciales
son especialmente importantes:

1. Los datos de diseo asistido por computador (CAD), que incluyen informacin espacial
sobre el modo en que los objetos (edificios, coches, aviones, etc.) estn construidos. Los sistemas
CAD tradicionalmente almacenaban los datos en la memoria durante su edicin u otro tipo
de procesamiento y los volvan a escribir en ficheros al final de la sesin de edicin. Pero un
diseo de gran tamao, como el de un avin, poda resultar imposible guardarlo en memoria.
Los objetos almacenados en las BD CAD suelen ser objetos geomtricos de los que adems se
puede almacenar informacin no espacial por ejemplo el material del que estn construidos,
color u otras caractersticas.

2. Los datos geogrficos (mapas de carreteras, tierra, mapas topogrficos, mapas catastrales,
imgenes de satlite, etc.).
Los sistemas de informacin geogrfica son bases de datos adaptadas tanto para el alma-
cenamiento de los datos geogrficos como para el procesamiento de los mismos. Los datos
geogrficos, como los mapas o imgenes de satlite son de naturaleza espacial, pero se dife-
rencian de los datos de diseo en ciertos aspectos. Los mapas pueden proporcionar no slo
informacin sobre la ubicacin (fronteras, ros, carreteras, ...) sino tambin informacin mucho
ms detallada asociada con la ubicacin (como la elevacin del terreno, el tipo de suelo, el uso
de la tierra, etc.).
Se diferencias dos tipos de datos geogrficos:

Tipo array consisten en mapas de pxeles (picture element) en 2 o ms dimensiones. Un


ejemplo son las imgenes de satlite, con las que podemos obtener arrays bidimensionales
(la cobertura nubosa en la que cada pxel almacena la visibilidad de las nubes en una
regin concreta) o tridimensionales (la temperatura a distintas altitudes, la temperatura
superficial en diferentes momentos, etc.).
Tipo vectorial estn formados a partir de objetos geomtricos bsicos como puntos, seg-
mentos rectilneos, polilneas de 2 dimensiones, cilindros, esferas u otros.

Los datos cartogrficos suelen representarse en formato vectorial. La representacin vectorial


es ms precisa que la de arrays en algunas aplicaciones.
Aplicaciones de los datos geogrficos:

Mapas en lnea : existen de muchos tipos aunque los ms populares son los mapas de carre-
teras. Muchos son interactivos y permiten el clculo de rutas. Disponen de informacin
como el trazado de carreteras, lmites de velocidad, condiciones de las vas, servicios, etc.
Sistemas de navegacin : proporcionan mapas de carreteras, de rutas de montaa, o cartas
de navegacin nutica. Se basa en el uso de GPS (Global Position System) La unidad
141

GPS halla la ubicacin en trminos de: latitud, Longitud y elevacin. El sistema de


navegacin puede consultar la BD geogrfica para hallar el lugar en que se encuentra y
la ruta a seguir.
Sistemas de informacin de redes de distribucin : en ellos se almacena informacin
sobre servicios de telefona, electricidad, suministro de agua, etc. No solo el trazado sino
la descripcin de los elementos que constituyen dichas redes.

3.6.3. Tipos de consultas espaciales


Para ver unos ejemplos de consultas espaciales vamos a utilizar Postgis. Postgis es una extensin
del SGBD Postgres para poder trabajar con informacin georeferenciada.

Consultas de proximidad: Obtener la referencia, las coordenadas y la distancias al punto (x, y)


de los n objetos ms cercanos a dicho punto:

select referencia,
x(the_geom),
y(the_geom),
ST_Distance(the_geom, GeomFromText(POINT(x y), -1))
from objetos
order by distancia desc limit n;

Consultas de solapamiento: Obtener la referencia y las coordenadas de aquellos objetos que


se encuentran dentro del rectngulo de esquinas (0, 0) y (150, 200):

select referencia,
x(the_geom),
y(the_geom)
from objetos
where the_geom && BOX3D(0 0, 150 250)::box3d;
Parte IV
Componentes hardware y
software de un sistema
informtico

142
CAPTULO 4

Componentes hardware y software de un sistema informtico

4.1. Estructura y funcionamiento de un computador


4.1.1. Concepto de computador
Para muchos el computador es simplemente una caja llena de componentes electrnicos que se
conecta a un teclado, un ratn y un monitor, que permite conectarse a Internet y ejecutar programas
de diversa ndole:
Procesadores de texto
Juegos
Correo electrnico
Navegadores WEB, etc.
Nosotros iremos ms all y trataremos de comprender cmo funciona internamente el compu-
tador, es decir el hardware, que es el conjunto de componentes que integran la parte material del
computador, y cmo ese hardware puede ejecutar al software (brevemente: los programas y sus
datos).
Ya hemos visto en la introduccin del curso que un computador es una mquina capaz de
ejecutar programas, pero de tal modo que los programas no forman parte de la arquitectura de la
mquina, sino que estn almacenados en ella y pueden ser cambiados por otros, lo que convierte al
computador en una mquina de popsito general, que puede desempear diferentes cometidos segn
el programa que se le suministre.

Figura 4.1: Vision simplista del computador

4.1.2. Arquitectura von Neumann


En el ao 1945 el matemtico John von Neumann propuso una arquitectura que permita cons-
truir el computador, la cual bsicamente ha perdurado hasta nuestros das.
Ya en el tema 1 se mostr una figura que esquematiza los componentes de esta arquitectura y
su interrelacin. Se muestra de nuevo en la figura 4.2 la misma imagen para mayor comodidad del
lector.

143
4.1 Estructura y funcionamiento de un computador 144

Reloj

Entrada/Salida

CPU Memoria

Bus de direcciones

Bus de datos

Bus de control

Figura 4.2: Arquitectura Von Neumann

En el tema 1 ya se han descrito los principales componentes de esta arquitectura pero cmo
funciona? Es decir, de qu manera se logra que la funcin desempeada por esta arquitectura no
est prefijada en su propia construccin, sino que pueda venir dictada desde fuera a travs de un
programa? Y cmo se almacena este programa? en qu lenguaje est? cmo puede la arquitectura
ejecutarlo?
En el tema 1 vimos cmo los datos de diferentes tipos (enteros, reales, booleanos, texto. . . ) se
pueden codificar mediante secuencias de bits. El componente llamado Memoria en la arquitectura
Von Neumann no es ms que un almacn de bits, por tanto parece idneo para guardar datos.
El aspecto clave de esta arquitectura es que los programas tambin pueden almacenarse como
secuencias de bits (enseguida veremos cmo), y por tanto almacenarse en la misma memoria que
los datos.
La idea es la siguiente:
La CPU tiene prefijado por hardware (esto es, por la forma en que est construda) un cierto
nmero de operaciones que sabe hacer sin que se le diga cmo. El nmero de operaciones
diferentes suele ser bastante reducido. Se denominan instrucciones mquina.
Los algoritmos se expresan mediante secuencias de instrucciones que se denominan programas.
Para que una CPU pueda ejecutarlo, el algoritmo debe estar compuesto slo por aquellas
instrucciones que la CPU sabe hacer, es decir, por las instrucciones mquina.
Cada una de las instrucciones que forman parte de un programa se representa usando una
secuencia de bits (unos y ceros), denominado cdigo mquina, y se almacena en la memoria
del computador. Observese que, ya que el juego de instrucciones mquina de la CPU es finito,
es posible asignar un cdigo diferente a cada posible instruccin.
Los datos de los programas tambin se representan con secuencias de bits y se almacenan en
la misma memoria.
Por ejemplo, la figura 4.3 muestra a su izquierda parte de un programa (se muestran solo tres
instrucciones) y a la derecha el cdigo binario correspondiente a esas instrucciones. Lo que la CPU
4.1 Estructura y funcionamiento de un computador 145

Programa Cdigo mquina


XOR R5, R5, R5 0110010110110100
COMP R1, R5 0110100110100000
BRC MENOR1 1111000000000001
mximo = 3 0000000000000011

Figura 4.3: Ensamblador y cdigo mquina

realmente comprende es lo que aparece a la derecha. Lo de la izquierda no son ms que unos


nombres que los diseadores de la CPU han decidido ponerle a cada instruccin, para que sea ms
sencillo recordar lo que hace cada una. Por ejemplo, la instruccin XOR R5,R5,R5 indica a la CPU
que debe realizar la operacin lgica xor con el dato que tiene en el registro R5. No necesitas
comprender qu significa esto exactamente, pero es importante que entiendas que la CPU s sabe
realizar esa operacin pues tiene en su interior un hardware capaz de ello. Cuando la CPU recibe el
cdigo mquina 0110010110110100 que correspondera a esa instruccin, sabe bien lo que debe
hacer, y lo hace.
La figura muestra tambin en el lado izquierdo una variable, llamada maximo que contiene el
dato 3. A la derecha vemos que el valor 3 se codifica en binario. El nombre de la variable no existe
cuando pasamos al dominio del cdigo mquina. El nombre no es ms que una forma conveniente
para nosotros de referirnos a la posicin de la memoria en la que est el dato.
Si quisieras escribir programas directamente en el lenguaje comprendido por la CPU, deberas
escribir las ristras de unos y ceros que aparecen a la derecha. Naturalmente nadie hace eso, ya que
es imposible recordar lo que significa cada una. Como sucedneo de esto, se escribe el programa
usando el lenguaje que aparece a la izquierda (denominado lenguaje ensamblador). Este lenguaje,
una vez te habitas a l, no es tan difcil de recordar, ya que los nombres de las instrucciones (XOR,
COMP, BRC) son una abreviatura (mnemnico) de lo que hacen (COMP compara, BRC realiza una
bifurcacin, o en ingls branch). Cada uno de estos mnemnicos se traduce directamente a un
cdigo binario. La herramienta que hace esa conversin se denomina ensamblador.
Aunque usar el ensamblador es un avance sobre el tener que escribir los programas en binario,
sigue siendo una tarea muy compleja y tediosa. Principalmente porque las instrucciones de las que
dispones en el lenguaje ensamblador son slo aquellas de las que disponga el hardware de la CPU
y ya hemos dicho que son muy pocas y muy simples. Por ejemplo, tienes instrucciones para sumar
dos nmeros, pero algunas CPUs no tienen instrucciones para multiplicar. Si necesitaras multiplicar
dos nmeros deberas hacerlo mediante un bucle que realizara muchas sumas (multiplicar 4 por 5
equivale a sumar 4 veces el 5 consigo mismo). Si tuvieras que escribir en ensamblador, para una
CPU que no sabe multiplicar, un programa que calcule una expresin como (a + b) (c + d) donde
a, b, c y d son nombres de variables, el programa tendra docenas de lneas, ya que cada instruccin
slo puede sumar dos nmeros, y esos nmeros han de estar previamente en registros del procesador
(el concepto de registro se ver ms adelante), por lo que tendras que poner las instrucciones que
traen los datos desde las variables (memoria) a los registros, las que suman dos registros, las que
almacenan el resultado intermedio, y finalmente el algoritmo para multiplicar uno de los resultados
intermedios por el otro (mediante sumas sucesivas).
Muy poca gente programa hoy da en ensamblador. Se usan los lenguajes de alto nivel (como C,
o python) y las herramientas que los convierten a cdigo mquina (compiladores e intrpretes).
No obstante, si quieres comprender lo que realmente est haciendo una CPU cuando ejecuta un
programa, es necesario que comprendas el concepto de instruccin ensamblador y su cdigo mquina
asociado.
Adems de la CPU que es quien ejecuta las instrucciones, y la memoria que es quien las almacena
4.1 Estructura y funcionamiento de un computador 146

CPU Sistema de E/S


Imgenes a
visualizar
Interfaz de vdeo

Figura 4.4: La CPU enva un dato a la interfaz de vdeo para que se muestre en pantalla

junto con los datos, los restantes componentes de la arquitectura Von Neumann son:

El sistema de entrada y salida (E/S). Conecta el computador con su entorno, tpicamente con
el usuario o con otros dispositivos informticos (impresoras, red, discos duros, etc.)
El sistema de E/S est formado por las interfaces de los perifricos. Cada una de las interfaces
permite conectar un perifrico al computador. Por ejemplo, la interfaz de vdeo es lo que
comunmente se llama tarjeta de vdeo o tarjeta grfica y permite conectar un monitor al
computador, a travs del cual el usuario recibe imgenes (ver figura 4.4).

La CPU, la memoria y el sistema de E/S estn conectados a travs de conjuntos de conductores


elctricos denominados buses. A travs de estos se transmiten bsicamente los bits que se leen
o escriben.

4.1.3. Ejecucin de programas


Antes de detallar el bucle de ejecucin que la CPU est llevando a cabo continuamente, es
necesario explicar algunos conceptos:

La memoria almacena muchas palabras (una palabra en este contexto es un grupo de bits,
de un tamao prefijado, tpicamente 8 bits). Cada palabra est almacenada en una direccin
(posicin) que la distingue de las dems. Puedes imaginar la memoria como un armario con
una infinidad de cajones numerados. El nmero de cada cajn es su direccin, y el contenido
de cada cajn es el dato, denominado palabra.
Para acceder a una instruccin o a un dato almacenados en memoria, es preciso conocer la
direccin (posicin) en que est almacenado. Cuando la CPU quiere leer de la memoria, debe
suministrar la direccin de la cual quiere leer. Si quiere escribir, debe suministrar el dato que
quiere escribir y la direccin donde quiere hacerlo.
Esta memoria almacena el programa que se quiere ejecutar como una secuencia de palabras
(cada una es una instruccin) almacenado en direcciones consecutivas. Los datos manejados
por el programa (sus variables) estarn tambin en otras direcciones de esta memoria.

Aunque instrucciones y datos estn en memoria, para que la CPU pueda ejecutar las instruc-
ciones y operar con los datos, debe antes obtener una copia de los mismos, y almacenarlos en
otras memorias internas a la CPU denominadas registros. Cada registro es una unidad de
almacenamiento en la que cabe solo una palabra.
El nmero de registros de que dispone una CPU es limitado y est prefijado por el hardware.
Los datos almacenados en los registros estn disponibles inmediatamente para la CPU (acceso
ultrarrpido), a diferencia de los que estn en memoria que deben traerse antes a la CPU a
travs del bus, lo que requiere un largo tiempo (largo desde el punto de vista de la CPU, capaz
de ejecutar millones de instrucciones por segundo).
Tpicamente, todas las CPUs disponen al menos de los siguientes registros:
4.1 Estructura y funcionamiento de un computador 147

Memoria del computador


Direcciones
CPU de memoria Palabras de memoria
 0110010110110100
 0110100110100000

 1111000000000001
Contador de
programa(PC)
 0000000000000011

Figura 4.5: Funcin del contador de programa dentro de la CPU

CPU Memoria del computador


Lectura de
Cdigo mquina
instruccin
0110010110110100
0110010110110100
Registro de 0110010110110100 0110100110100000
instruccin (IR)
1111000000000001
0000000000000011

Figura 4.6: Funcin del registro de instruccin dentro de la CPU

Registros de propsito general. Sirven para contener datos o tambin direcciones


para referirse a la memoria. Estos son los datos con los que podrn operar las instrucciones
mquina (por ejemplo para sumarlos, restarlos, realizar con ellos operaciones lgicas, etc.)
La funcin que desempean depende del algoritmo que se est ejecutando, no tienen una
funcin predeterminada, de ah su nombre.
Contador de programa (o Program Counter, PC). Contiene un nmero que es la
direccin de la memoria donde debe ir a buscar la prxima instruccin a ejecutar.
Registro de Instruccin (IR). Contiene un cdigo binario que es el de la instruccin
que toca ejecutar en ese momento. Este cdigo ha venido desde la memoria, desde la
posicin indicada por PC.

Una vez aclarado el concepto de registro y el papel de la memoria, podemos pasar a detallar los
pasos que sigue la CPU para ejecutar los programas:

1. La CPU solicita a la memoria el cdigo que hay en la posicin sealada por PC (figura 4.5).

2. La memoria necesita un tiempo para acceder al dato solicitado y responder con l. Entretanto
la CPU aprovecha para incrementar PC, preparndolo as para la siguiente instruccin.

3. El cdigo respondido por la memoria es almacenado en el registro IR (figura 4.6).

4. El contenido de IR es decodificado (se determina qu operacin es la que hay que hacer).


Por ejemplo, si el cdigo fuese 0110010110110100, la instruccin representada sera XOR
R5, R5, R5, lo que le indica a la CPU que debe llevar a cabo una operacin XOR con ciertos
operandos (en este caso con el registro de propsito general llamado R5)

5. Para llevar a cabo la instruccin, la CPU utiliza su hardware interno. Los resultados de
la operacin son almacenados en sus registros de propsito general. Algunas instrucciones
pueden solicitar otros datos a la memoria, que seran copiados a registros internos antes de
poder operar con ellos. Otras instrucciones solicitan que el contenido de un registro interno
sea copiado sobre cierta direccin de memoria, indicada por otro registro, etc.
4.2 Dispositivos perifricos 148

Figura 4.7: Conector PS2 y Figura 4.8: Funcionamiento


USB de una tecla

6. Finalizada la ejecucin de la instruccin, se vuelve al paso 1.

La CPU est atrapada permanentemente en el bucle anterior que repite incesantemente1 .

4.2. Dispositivos perifricos


Comunican al computador con su entorno. Bsicamente, podemos dividirlos en:

1. Perifricos de interfaz humana de entrada: teclado, ratn.

2. Perifricos de interfaz humana de salida: monitor, impresora.

3. Perifricos de almacenamiento: discos duros, memorias USB, discos pticos (CD/DVD/Blu-


Ray).

Cada perifrico incorpora un mecanismo de conexin al computador que debe conocerse: USB,
Bluetooth, SATA, PS2, Ethernet, etc. Por ejemplo, un ratn PS2 no puede conectarse al computador
empleando la interfaz SATA.
Presentaremos de forma simplificada el principio de funcionamiento y las caractersticas ms
importantes de los perifricos de E/S y de los de almacenamiento.
4.2.1. Perifricos de interfaz humana de entrada
Envan informacin al computador. Los ms usuales son el ratn y el teclado. El ratn y el
teclado suelen utilizar conectores PS2, USB (en la figura 4.7 se muestran ambas conexiones, co-
rrespondindose la imagen superior con una conexin PS2 y la inferior con una conexin USB), o
incluso conexiones inalmbricas Bluetooth.
El ratn enva al computador desplazamientos a lo largo de dos ejes perpendiculares. Estos mo-
vimientos se procesan dentro del computador y aparecen tpicamente reflejados como movimientos
de un puntero en pantalla (la tpica flecha).
Los ratones antiguos utilizaban una bola de goma para detectar los movimientos. Los modernos
emplean una pequea cmara. Algunos ratones incorporan botones especiales y ruedas de scroll
(verfigura 4.9).
Los teclados disponen de pequeos pulsadores que modifican circuitos elctricos (fig. 4.8). Al-
gunos teclados disponen de teclas especiales que sirven de atajos a ciertas funciones muy usadas.
1
El lector inteligente habr advertido que esta secuencia de pasos obliga a que la CPU ejecute siempre las instruc-
ciones en el orden en que estn en memoria, en forma de bloque secuencial. Parece por tanto hacer imposible la
existencia de control de flujo (condicionales, bucles). La historia completa es que ciertas instrucciones pueden tener
como resultado que el valor de PC se modifique, y as la siguiente instruccin a ejecutar no sera la que tocara
despus de la actual, permitiendo de esta forma realizar saltos hacia adelante o hacia atrs en el cdigo. El que el salto
se produzca o no puede hacerse depender de una condicin, lo que permite crear estructuras de control alternativas
4.2 Dispositivos perifricos 149

Figura 4.9: Funcionamiento del ratn

Figura 4.10: Conectores VGA y DVI Figura 4.11: La pantalla est compuesta de pixeles

4.2.2. Perifricos de interfaz humana de salida


Muestran informacin proveniente del computador. Los ms usuales son el monitor y la impre-
sora.
Monitores
Los monitores actuales suelen utilizar conectores VGA y DVI (en la figura 4.10 se muestran
estos conectores, correspondindose la imagen de la izquierda con el VGA y la de la derecha con
el DVI). El conector VGA es ms antiguo. Los monitores modernos emplean el conector DVI, pues
sobre l se transmiten las imgenes de manera digital, por lo que stas son menos sensibles a las
interferencias y por tanto se degradan menos.
La imagen que muestra el monitor se crea fijando el color de los millones de pxeles (puntos)
que constituyen la pantalla (fig. 4.11). La resolucin de la pantalla (ej: 1024x768) indica los pxeles
en horizontal y vertical.
El principio de funcionamiento de un monitor plano es el siguiente:

En la parte trasera de un monitor TFT hay una fuente de luz blanca. Nota: color blanco =
1/3 rojo + 1/3 verde + 1/3 azul.

Cada pixel tiene asociados tres filtros pticos, uno de los cuales deja pasar slo la componente
roja (Red), otro la componente verde (Green) y otro la componente azul (Blue).

Para cada uno de los filtros de color anteriores hay un interruptor electrnico que deja pasar
en mayor o menor medida la componente asociada.
4.2 Dispositivos perifricos 150

La combinacin de las tres componentes, R, G y B, cada una con su magnitud, fija el color y
el brillo de cada pixel. Por ejemplo: amarillo = 1/2 rojo + 1/2 verde, magenta = 1/2 rojo +
1/2 azul, cian = 1/2 verde + 1/2 azul.
Caractersticas: resolucin (ej: 1280x1024), tamao (ej.: 20 pulgadas), brillo (ej.: 300 cd/m2 ) y
contraste (ej.: 800:1), frecuencia de refresco (ej.: 60 Hz).
Impresoras
Las impresoras muestran informacin permanente en papel. Las impresoras modernas usan co-
nectores USB. Los dos tipos de impresora ms habituales son:
Inyeccin de tinta (en color)
Lser monocromo o color.
Las impresoras lser son ms caras, pero a cambio son ms rpidas (imprimen ms pginas por
minuto), imprimen con ms calidad y el coste de impresin por hoja es menor. Las impresoras lser
usan una tinta en polvo denominada tner. Las de tinta usan cartuchos de tinta lquida.
A la hora de adquirir una impresora es importante conocer el precio de la tinta (tner, o lquida)
y la posibilidad de usar cartuchos de otros fabricantes y recargas.
Las impresoras pueden crear cualquier color sobre el papel, mediante la mezcla de solo tres
colores de tinta. Cuando la luz blanca ilumina un papel blanco, todas las componentes de la luz son
reflejadas, y el ojo percibe esa suma como blanco. Si se ilumina un papel rojo, todas las componentes
de la luz son absorbidas por el papel, excepto la de color rojo que es la nica reflejada y la que el
ojo percibe.
Las impresoras usan tintas de unos colores especficos que actan como filtros ante la luz reflejada
por el papel. Estos colores son el Cian, Amarillo y Magenta (sus iniciales en ingls son CYM). La
tinta de color cian absorbe (no deja pasar) la componente roja de la luz, pero deja pasar todas
las dems. La tinta amarilla no deja pasar la componente azul. La tinta magenta no deja pasar la
componente verde. Observa que los colores que cada tinta impide son rojo, verde y azul, justo los
colores que el monitor usa para componer su imagen.
Si un monitor quiere mostrar el color cian, activar las componentes verde y azul del pixel, y no
activar la roja. Justamente lo que hace la tinta cian al dejar pasar las componentes verde y azul
sin dejar pasar la roja.
Si un monitor quiere mostrar el rojo, activar la componente roja del pixel. Pero y si una
impresora quiere mostrar el rojo? No tiene tinta roja. Deber usar dos tintas que combinadas slo
dejen pasar la componente roja. Se trata de las tintas amarilla y magenta, ya que el amarillo no
deja pasar el azul (pero s el verde y el rojo), mientras que la magenta no deja pasar el verde, con
lo que al final la nica que pasa es el rojo.
De este modo, depositando sobre el papel tintas de colores CMY en las proporciones adecuadas,
la impresora puede crear cualquier otro color (fig. 4.12).
Muchas impresoras aaden una cuarta tinta negra (y usa entonces las iniciales CMYK) pues,
aunque tericamente es posible crear el negro mezclando las tres tintas CMY (la mezcla no dejara
pasar ninguna componente), lo cierto es que el negro resultante es menos intenso que el de una tinta
negra, adems de que se gastara ms tinta.
4.2.3. Perifricos de almacenamiento
A diferencia de la memoria principal del sistema (RAM) que pierde todos sus contenidos si
se desconecta la alimentacin, los perifricos de almacenamiento conservan la informacin digital
almacenada incluso cuando se apaga el computador.
Los ms empleados son: discos duros, unidades pticas (CD/DVD/Blu-ray) y memorias Flash.
Los discos duros y unidades pticas internas suelen utilizar conectores SATA, mientras que los
dispositivos externos, incluyendo las memorias Flash, suelen emplear USB (ver figura 4.13).
4.2 Dispositivos perifricos 151

Figura 4.12: Mezcla de tintas en una impresora a color

Figura 4.13: Perifricos de almacenamiento

Discos duros
Almacenan grandes cantidades de informacin, del orden de 1 Tbyte. La velocidad de lectura y
escritura es del orden de 100 Mbytes/segundo.
Su funcionamiento se basa en el magnetismo. En la superficie de unos platos rgidos se deposita
material magntico. Para cada plato se dispone de una cabeza de lectura y escritura en el extremo
de unos brazos (ver figura 4.14). Estas cabezas pueden producir variaciones en el campo magntico,
que queda registrado en el material magntico que cubre el disco, o pueden detectar las variaciones
del campo magntico que se generan al hacer desplazarse (girar) el disco bajo la cabeza lectora. Los
platos giran a alta velocidad, del orden de 10000 rpm (revoluciones por minuto).
Discos pticos
Hay tres generaciones: CD, DVD y Blu-ray. Las capacidades tpicas son: 700 Mbytes, 8,4 Gbytes
y 50 Gbytes. La velocidad de lectura y escritura de los discos Blu-ray (los ms rpidos) es de unos
15 Mbytes/segundo.
Principio de funcionamiento Su funcionamiento se basa en las propiedes pticas de la superficie
de estos discos, es decir, en la forma en que reflejan o dejan de reflejar la luz que incide sobre ellos.
La informacin se almacena en forma de espiral. Los ceros y unos se codifican como cambios de
reflexin de un haz lser. Dependiendo del tipo de disco, ROM, grabable o regrabable, los cambios
de reflexin se consiguen con surcos (pits), o cambios qumicos en el material.
La figura 4.15 muestra el aspecto idealizado de los pits y lands de un CD-ROM y un DVD-ROM.
En el caso de un BD-ROM la diferencia es que las distancias an son ms ajustadas. Las imgenes
4.3 Interconexin de sistemas 152

Figura 4.14: Interior de un disco duro

hechas con microscopio son similares, pero menos educativas, ya que son mucho ms ennegrecidas
y difusas, y obviamente no muestran curvatura.
Memorias Flash
Actualmente tienen capacidades tpicas comprendidas entre 4 Gbytes y 64 Gbytes y crecen r-
pidamente. Su velocidad de lectura y escritura suele ser inferior a la de los discos duros. Suelen
presentarse en dos formatos: tarjetas de memoria (fig. 4.16) y memorias USB (pendrives, fig. 4.17).
La memoria FLASH es un tipo de memoria electrnica no voltil, es decir, que mantiene la infor-
macin almacenada incluso cuando desaparece la alimentacin.

4.3. Interconexin de sistemas


Muchas de las aplicaciones del computador necesitan acceder a informacin que se encuentra en
otros computadores. Por ejemplo, correo electrnico, web, etc. Para llevar a cabo la fsicamente la
comunicacin, el computador necesita una interfaz de red. Las tpicas son Ethernet y WiFi.
La interfaz Ethernet requiere un cable y un conector como los mostrados en la figura 4.18.
La interfaz WiFi requiere una antena que muchas veces no es visible, pues se encuentra en el
interior del dispositivo. En los dispositivos que llevan antena externa, puede tener el aspecto de la
figura 4.19.
Actualmente, la mayor parte de los computadores estn conectados a travs de una red que se
extiende por todo el planeta, a la cual se le denomina Internet.
Para comunicar de forma eficiente millones de computadores hay dos dispositivos de red funda-
mentales:

Switches (conmutadores). Comunican de forma eficiente equipos cercanos, tpicamente en la


misma sala o edificio. La figura 4.20 muestra un tpico switch para uso domstico.

Routers (enrutadores). Permiten comunicar computadores distantes, moviendo la informacin


por las rutas adecuadas, dentro de la red.

Existen tambin dispositivos hbridos, que pueden realizar ambas funciones. Por ejemplo, un
router domstico que permite conectar la red local de una casa con internet, a menudo tiene tambin
funciones de switch para permitir que se conecten a l varios ordenadores del mbito domstico.
4.3 Interconexin de sistemas 153

Figura 4.15: CD-ROM al microscopio

Figura 4.16: Memoria FLASH en forma Figura 4.17: Memoria FLASH incrustada en un
de tarjeta lpiz USB

Figura 4.18: Conector Ethernet Figura 4.19: Antena WiFi externa

Figura 4.20: Switch para uso domstico


4.4 Tipos de software 154

Figura 4.21: El sistema operativo en relacin a las aplicaciones y al hardware

Cada computador conectado a Internet tiene una direccin, denominada direccin IP, que sirve
para identificarlo. Por ejemplo, la direccin 156.35.94.131. Puesto que es ms fcil recordar nombres
que secuencias de nmeros, las direcciones IP tienen nombres asociados. Por ejemplo, www.uniovi.es.
Para convertir nombres en direcciones IP se emplean computadores que actan como servidores de
nombres. Por ejemplo, uno de los servidores de nombres de la Universidad de Oviedo es el equipo
con direccin IP 156.35.14.2.

4.4. Tipos de software


El computador es una mquina que permite ejecutar varias aplicaciones (programas) simult-
neamente. Por ejemplo, un procesador de textos, cliente web, etc. La ejecucin de las aplicaciones
directamente sobre el hardware del computador no es adecuada, pues aparecen varios problemas:

Cmo puede ejecutar el computador varios programas a la vez sin que interfieran unos con
otros?

Cmo evita el programador de una aplicacin el tener que distribuir miles de variantes de su
aplicacin, debido a las variaciones existentes en el hardware del computador?

Cmo puede tratar un programador con los detalles de cualquier dispositivo del computador?
Por ejemplo, para escribir un archivo en un disco duro SATA, debera programar su interfaz,
lo que requerira el manejo de miles de pginas de manuales.

La solucin a los problemas anteriores es el empleo de un programa especial denominado sistema


operativo. El sistema operativo gestiona todo el hardware del computador.
La figura 4.21 muestra la relacin entre el Sistema Operativo, las diferentes aplicaciones, y el
hardware de la mquina. Como se puede ver, el Operativo es quien tiene acceso directo al hardware,
mientras que las aplicaciones no. Esto implica que, si una aplicacin necesita por ejemplo dibujar (o
escribir) algo en la pantalla, en lugar de incluir las instrucciones especficas para acceder al hardware
del interfaz de vdeo y escribir all la informacin, lo que contiene son llamadas a funciones del
Sistema Operativo, a las que les pasa qu quiere mostrar y dnde, y es el Operativo el que se ocupa
del hablar con el interfaz apropiado.
Esto libera al programador de aplicaciones de tener que conocer los detalles de funcionamiento
del hardware, y hace posible que una misma aplicacin pueda ejecutarse sobre diferentes configura-
ciones de hardware. A la vez, el operativo puede orquestar los accesos al hardware solicitados por
diferentes aplicaciones, de modo que no se interfieran unos con otros (por ejemplo, en el caso de
4.4 Tipos de software 155

la pantalla, destinando una ventana diferente para cada aplicacin de modo que cada una slo
pueda solicitar escribir en su propia ventana).
Como vemos, existen diferentes tipos de software:

Software de aplicacin: es el que el usuario final utiliza para realizar su trabajo o su


entretenimiento. Por ejemplo, en esta categora tendramos:

Aplicaciones Ofimticas (procesadores de texto, hojas de clculo, aplicaciones de presen-


tacin de diapositivas, etc.)
Sistemas Gestores de Bases de Datos (dedicaremos un captulo posterior a estudiar qu
funcin desempean este tipo de aplicaciones).
Programas para comunicacin en red (navegadores web, gestores de correo, mensajera
instantnea o chat, descarga de ficheros, etc.)
Aplicaciones de Control y Automatizacin industrial. Son programas diseados para con-
trolar un proceso industrial especfico, tomando medidas de diferentes variables del proce-
so y mostrndolas en pantalla de una forma comprensible para el operador, posiblemente
activando alarmas cuando alguna se sale de los rangos deseables, o incluso tomando
acciones de control para corregirlas.
Software Educativo. Permiten utilizar el ordenador como herramienta de aprendizaje.
Software mdico.
Software empresarial
Software de clculo numrico
Software de diseo asistido (CAD)
Software de control numrico (CAM), que permite materializar los diseos realizados por
CAD.
Videojuegos, que permiten el uso del computador como plataforma de ocio.

Software de Sistema: el que permite hacer funcionar el sistema y que otras aplicaciones
puedan ejecutarse (y crearse) sobre l. Comprende:

El Sistema Operativo, cuyas funciones hemos expuesto someramente en prrafos ante-


riores, y al cual dedicaremos un captulo completo ms adelante.
Los Controladores de Dispositivo. Se trata de software que se integra con el Sistema
Operativo, permitiendo a ste interactuar con diferentes componentes del hardware. En
muchas ocasiones este software lo escribe el propio fabricante de cada componente hard-
ware.
Utilidades. Realizan diversas funciones para resolver problemas especficos (por ejemplo,
localizacin y reparacin de fallos en el disco duro, eliminacin de software no deseado,
etc.) Muchas de estas herramientas se incluyen al instalar un Sistema Operativo, pero
otras pueden ser desarrolladas por terceros.
Herramientas de desarrollo. Permiten la creacin del propio sistema operativo, de los
controladores, de las aplicaciones, de los programas utilitarios, etc. Entre estas herra-
mientas se cuentan los compiladores, ensambladores, intrpretes de diferentes lenguajes,
depuradores, etc.
4.4 Tipos de software 156

4.4.1. Desarrollo de software


La CPU es la encargada de ejecutar los programas, ya sean aplicaciones o el sistema operativo.
La CPU ejecuta el cdigo mquina de los programas. El cdigo mquina es adecuado para la
CPU, pero no para el desarrollo del software. Sera tremendamente tedioso y se cometera infinidad
de errores. Una solucin inicial es el empleo de mnemnicos para las instrucciones mquina. Por
ejemplo, XOR R5, R5, R5 es el mnemnico de la instruccin mquina 0110010110110100.
A la programacin empleando mnemnicos se la conoce como programacin ensamblador. Un
programa escrito en lenguaje ensamblador es un archivo de texto, en el que cada lnea es el
mnemnico de las instrucciones que la CPU debe ejecutar. Hay una herramienta denominada com-
pilador de ensamblador (o simplemente ensamblador), encargada de convertir los mnemnicos en
cdigo mquina. La programacin en ensamblador, aunque es un avance importante con respecto a
la programacin directa en cdigo mquina, adolece de los siguientes defectos:

Las instrucciones son muy elementales. Hacen operaciones muy simples, y por tanto se requiere
una gran cantidad de ellas para realizar cualquier clculo mnimamente complejo. Adems, su
funcionamiento es poco intuitivo, por lo que la programacin sigue siendo tediosa y propensa
a errores.

La programacin depende de la CPU empleada. Cada marca y modelo de CPU tiene su propio
lenguaje mquina, y por tanto su propio ensamblador. El programador debera aprender los
diferentes lenguajes ensambladores existentes, y reescribir su programa para cada uno de ellos.

La solucin es la programacin empleando lenguajes ms cercanos al de las personas, y con


una mayor capacidad expresiva (es decir, que unas pocas lneas de cdigo puedan implementar una
funcionalidad compleja). Por ejemplo, python.
Compara los listados siguientes. En primer lugar, mostramos cmo sera un programa python
que implementa el algoritmo para encontrar cul es el nmero mayor de una lista dada de nme-
ros, suponiendo que todos los nmeros son positivos (en realidad no necesitamos implementar tal
algoritmo en python, puesto que ste ya tiene la funcin max(), por lo que el listado an podra
reducirse ms y quedar simplemente como maximo=max(lista), pero continuemos con el ejemplo
como si python no tuviera la funcin max()):
1 lista=[3,5,2,1,7]
2 maximo=0
3 for d in lista:
4 if d>maximo:
5 maximo=d

Compara el listado anterior con el siguiente, que muestra la implementacin de ese algoritmo
usando el lenguaje ensamblador de una CPU intel (no te preocupes, no tienes por qu entender
nada):
1 mov dword ptr [ebp-1Ch],3
2 mov dword ptr [ebp-18h],5
3 mov dword ptr [ebp-14h],2
4 mov dword ptr [ebp-10h],1
5 mov dword ptr [ebp-0Ch],7
6 mov dword ptr [ebp-34h],0
7 mov dword ptr [ebp-28h],0
8 jmp wmain+64h
9 mov eax,dword ptr [ebp-28h]
10 add eax,1
11 mov dword ptr [ebp-28h],eax
12 cmp dword ptr [ebp-28h],5
13 jge wmain+82h
14 mov eax,dword ptr [ebp-28h]
4.5 Tipos de sistemas informticos y sus mbitos de aplicacin 157

15 mov ecx,dword ptr [ebp+eax*4-1Ch]


16 cmp ecx,dword ptr [ebp-34h]
17 jle wmain+80h
18 mov eax,dword ptr [ebp-28h]
19 mov ecx,dword ptr [ebp+eax*4-1Ch]
20 mov dword ptr [ebp-34h],ecx
21 jmp wmain+5Bh

No solo el ensamblador es mucho ms largo y difcil de entender. Adems depende de la CPU


concreta en la que se vaya a ejecutar. El listado anterior es vlido para cualquier CPU fabricada por
Intel a partir de la denominada 386, pero CPUs de otros fabricantes podran requerir instrucciones
diferentes.
Un lenguaje de alto nivel permite escribir los programas en un lenguaje ms simple y potente,
e independiente de la CPU que los va a ejecutar. Un programa llamado compilador o intrprete se
ocupa de traducir el lenguaje de alto nivel al lenguaje mquina concreto de la CPU que lo ejecutar.
Si el lenguaje es compilado (como el C, o C++), el compilador escribe en un fichero la versin en
cdigo mquina. Una vez finalizada la compilacin, ese cdigo mquina resultante en un fichero se
denomina ejecutable y ya puede ser ejecutado directamente por la CPU para la cual fue compilado.
Para poder ejecutarlo en otras CPUs, basta compilarlo de nuevo para ellas (suponiendo que exista
un compilador de ese lenguaje para la CPU en la que queremos ejecutar el programa, pero existen
compiladores de C para todas las CPUs existentes). Una vez se tiene el ejecutable, el compilador
no es necesario para ejecutar el programa. El compilador por tanto solo lo necesita el desarrollador,
y no el usuario final.
Si el lenguaje es interpretado (como el python, o el javascript), el intrprete es un programa que
ya se ejecuta en la CPU final, y que va leyendo de un fichero lneas del lenguaje de alto nivel, y
las va convirtiendo sobre la marcha a cdigo mquina de esa CPU para que sean ejecutadas. No
se almacena ningn fichero ejecutable, por lo que para ejecutarlo en cualquier CPU es necesario
el intrprete. La ventaja es que cualquier CPU para la cual exista el intrprete podr ejecutar el
programa (python tiene intrpretes para prcticamente todas las CPUs existentes).

4.5. Tipos de sistemas informticos y sus mbitos de aplicacin


En muchas ocasiones identificamos el computador con un PC, ya sea de sobremesa o porttil. Sin
embargo, hay otros muchos tipos de computadores. Prcticamente todos los dispositivos electrnicos
actuales incorporan algn tipo de computador con caractersticas especficas. Por ejemplo: telfonos
mviles (reducido consumo y tamao), sistemas de control industriales (robustez), electrodomsticos
(pequeos y de bajo coste).
Cuando el computador est integrado en un dispositivo que sirve a un propsito concreto (por
ejemplo, una consola de videojuegos, un simulador de vuelo para entramiento de pilotos, el sistema
computerizado de un automvil, un navegador GPS, etc.), se dice que es un computador de propsito
especfico. Si por el contrario el computador est abierto a cualquier posible uso, mediante la carga
de los programas adecuados, se habla de un computador de propsito general.
Hoy da, los computadores de propsito especfico no son diferentes desde el punto de vista
de la arquitectura de los de propsito general. Se componen de CPU, memoria, dispositivos de
entrada/salida. Lo que les hace especficos es que generalmente vienen con unos programas pre-
cargados que no se pueden sustituir por otros (o no fcilmente) y que sus interfaces de entrada/salida
estn especficamente diseados para un uso concreto. Es habitual que su memoria y capacidad de
cmputo estn limitadas y sean las estrictamente necesarias para poder ejecutar los programas
especficos que les dan su funcionalidad.
Los computadores de propsito general son los que habitualmente conocemos. Sus capacidades
de programacin y potencia suelen ser mucho mayores que las de los computadores para aplicaciones
especficas. Los ordenadores de propsito general podemos dividirlos a grandes rasgos en dos tipos
(ver figuras 4.22 y 4.23):
158

Figura 4.22: Computador personal Figura 4.23: Servidor

1. Ordenadores personales. Los ordenadores personales se emplean en el mbito domstico, o


como medio de conexin a los servidores en el mbito profesional. Se puede indicar que los
ordenadores personales habitualmente se encuentran en dos formatos: sobremesa y porttil.

2. Servidores. Los servidores tienen muchas ms capacidades: disco, memoria, CPU, etc. En el
caso de los servidores, lo habitual es usar sistemas en rack que permiten una fcil sustitucin y
ampliacin de las caractersticas del sistema, as como tolerancia a fallos. La parte mecnica y
de refrigeracin es importante en el caso de los servidores, puesto que est previsto que estn
fucnionando permanentemente, 24 horas al da durante todos los das del ao.
Los servidores gestionan la informacin de empresas y organizaciones: bancos, hospitales,
universidades, etc.
Parte V
Introduccin a los sistemas
operativos

159
CAPTULO 5

Introduccin a los Sistemas Operativos

5.1. Concepto y funciones que desempea un sistema operativo


Los conceptos que se estudiarn en este captulo se pueden extraer de la lectura del libro [15],
y en menor medida, de [16].
Antes de nada, es conveniente definir una serie de conceptos adicionales que sern de utilidad
en el resto del captulo.
software de sistema es el conjunto de programas que realizan tareas comunes al computador,
incluyendo el software de control y las utilidades.
software de control programas que gestionan el correcto funcionamiento del computador. Incluye
el sistema operativo, el lenguaje de control y el software de diagnstico y mantenimiento.
sistema operativo es el software que controla la ejecucin de los programas de aplicacin. Acta
como interfaz entre las aplicaciones del usuario y el hardware de la mquina.
interprete de lenguaje de control es un programa o conjuntos de programas que permiten al
usuario introducir rdenes para su proceso por el sistema. Por ejemplo, desde una consola de
comandos (en Windows, el programa cmd) se puede introducir el comando dir para visualizar
el contenido de un directorio o carpeta del sistema de archivos.
software de diagnstico y mantenimiento son los programas que utilizan las personas que se
responsabilizan del buen funcionamiento tanto del hardware como del software. Estas personas
se llaman administradores. Ejemplos de estas tareas: crear un usuario, limitar la cuota de
disco de un usuario, actualizar programas, instalar y mantener el antivirus, etc.
utilidades programas que permiten realizar tareas de gestin y administracin de un computador.
Por ejemplo, las utilidades de anlisis de discos, de configuracin de dispositivos de red, etc.
software de aplicaciones es el conjunto de programas que realizan tareas concretas objetivo l-
timo por el que un usuario utiliza un computador. Ejemplos: programa de edicin grfica,
navegador web, etc.
proceso es un programa en ejecucin en un computador en un instante dado. Los sistemas opera-
tivos actuales permiten multitarea, esto es, el tiempo de cmputo de la CPU se reparte entre
los procesos lanzados en una mquina.
sistema computarizado es el conjunto de computador (es decir, hardware) y software (incluyendo
el sistema operativo y todas las aplicaciones necesarias) que est instalado en aqul.
En adelante, los trminos mquina, computador y ordenador se utilizarn indistintamente.

160
5.1 Concepto y funciones que desempea un sistema operativo 161

5.1.1. Estructura de un sistema computarizado


En temas anteriores se ha estudiado cmo es la arquitectura de un computador. Sin embargo, y
como se ha visto, un computador contiene tanto un hardware como un software. Cmo se integra
esto?
En la figura 5.1 se intenta representar el conjunto hardware y software de un computador. El
harware representa todo elemento electrnico que, interconectado, es capaz de interactuar conjun-
tamente.
As, si de un computador de usuario se trata, en el hardware se tendr la placa madre con-
teniendo las CPUs, la memoria RAM, la memoria ROM, los controladores de los dispositivos de
entrada/salida, etc. Entre los dispositivos de entrada/salida se tienen los discos duros, las unidades
USB de memoria, etc.
La ROM de la placa madre es una parte bsica del ordenador. En esta ROM reside el programa
de inicializacin del ordenador y la librera de funciones para acceso a la entrada y salida de la
mquina. En algunos ordenadores, esta ROM es lo que se conoce como BIOS (Basic Input/Output
System) y es suministrada con la placa madre. El programa de inicializacin es el que realiza los
primeros pasos para poner en funcionamiento el Sistema Operativo, y es propio de cada placa. En
realidad, este programa de inicializacin se conoce como programa de arranque, pero lo denominaremos de
inicializacin para evitar confundirlo con el programa de arranque del sistema operativo.
Y, qu hace el hardware? Pues ejecutar el sistema operativo y tantos procesos como se le haya
indicado. El sistema operativo es el conjunto de programas que acta de interfaz entre el hardware
y el exterior (incluyendo en el exterior al usuario que lo explota): toda accin que el computador
debe ejecutar se le debe indicar al sistema operativo.
El sistema operativo se compone, entre otros, de un ncleo; ste es un programa que se ejecuta
en memoria de la mquina responsable de atender las acciones y tareas del sistema computarizado.
Cmo se comunica el ncleo con los dispositivos de entrada/salida? Pues utilizando la BIOS o
los drivers especficos de una tarjeta electrnica concreta.
Un driver es un conjunto de funciones para configurar el dispositivo y para intercambiar datos
entre ste y el sistema computarizado.
Los sistemas operativos actuales permiten la carga y activacin o desactivacin de mdulos o
drivers para control de dispositivos. Es por ello que cuando se instala un nuevo dispositivo en la
mquina (e.g., un nuevo lpiz de memoria USB), el sistema operativo busca el driver adecuado para
interactuar con l, cargndolo y activndolo. Esta tarea de descubrir automticamente hardware es
tarea del sistema operativo.
Por encima de todo esto tenemos las utilidades de sistema operativo y de diagnstico y man-
tenimiento, las cules pueden interactuar con el usuario, as como las aplicaciones de usuario, es
decir, los programas que un usuario ha lanzado y que se estn ejecutando en un computador en un
momento dado. Ejemplos de aplicaciones de usuario: un navegador web, el Word , c etc.
5.1.2. Arranque de un sistema computarizado
En un computador normal de usuario, el sistema operativo reside (o est almacenado) en un
disco duro de la mquina. El programa de inicializacin de la BIOS, la memoria ROM que est
integrada en la placa madre, es el responsable de ejecutar un programa de arranque (gestor de
arranque) del Sistema Operativo. Este programa de arranque, que est almacenado en un sitio
predeterminado y estandarizado del disco duro principal, es el que lanza el sistema operativo.
En un sistema computarizado, en el momento en que se pulsa sobre el botn de encendido,
ejecuta la siguiente serie de pasos:

Tras el encendido del ordenador se ejecuta la BIOS: chequeo del hardware.

Se ejecuta el gestor de arranque, responsable de cargar el ncleo del sistema operativo.


5.1 Concepto y funciones que desempea un sistema operativo 162

3$"/"2&2%#(
.*/"0&0"-1%#(2%((
3#4&+"-(

!"#$%&'(
560/%-(
)*%+&$",-(

9:8;<:!(
78)!( Reloj

Memoria
CPU
E/S
Perifricos

Bus de direcciones

Bus de datos
=.:9>.:<( Bus de control

Figura 5.1: Estructura de un sistema computarizado. Por un lado, se dispone de hardware sobre el
que se ejecuta el software. El sistema operativo es el software que permite explotar un hardware.

El ncleo del sistema operativo permanece residente en memoria y en constante ejecucin.


Como se ha dicho antes, el ncleo es el que se responsabiliza del control del equipo.

Ante acciones de usuario, el sistema operativo arranca aplicaciones de usuario.

El sistema operativo carga de forma controlada las aplicaciones de usuario.

Las aplicaciones de usuario son ficheros ejecutables que residen en memoria secundaria (disco
duro, lpiz USB, etc.). Los ficheros ejecutables contienen el cdigo mquina del programa a ejecutar
junto con sus datos.
Para que la CPU pueda ejecutar el cdigo ste debe ser cargado en la memoria principal.
Una funcin importante del S.O. es cargar, a peticin del usuario, las aplicaciones desde memoria
secundaria a memoria principal, lo que se conoce como carga de aplicaciones.
Una vez que el cdigo y los datos de un fichero ejecutable han sido cargados en memoria principal
pasan a tener entidad propia para el S.O., lo que se denomina proceso o tarea. Un proceso es, por
tanto, una aplicacin en ejecucin.
Para un sistema operativo, un proceso incluye:

programa lanzado y los datos del fichero ejecutable. Por ejemplo, el Word
c mas los datos de
una carta que se est redactando.

diversa informacin relevante para el S.O.: identificacin del programa en ejecucin, estado
del mismo, punto de ejecucin actual, usuario que lo lanz, etc. El usuario es el propietario
del proceso.

Si el usuario puede lanzar ms de una aplicacin a la vez entonces estamos ante un sistema
operativo multiproceso o sistema operativo multitarea.
Si un sistema operativo puede tener a la vez procesos que han sido lanzados por diferentes
usuarios entonces tenemos un sistema operativo multiusuario.
Se conoce como usuario un identificador nico de perfil o personalidad en la mquina que tiene
privilegio o derecho de ejecutar una serie de programas y de acceder a una serie de recursos de la
mquina.
5.2 Funciones que el sistema operativo presta a los programas 163

Por ejemplo, es usual que exista un usuario administrador, el cul es el responsable de tener
la mquina siempre lista para su correcta explotacin. Un usuario administrador suele tener dere-
cho de ejecutar todo programa instalado en una mquina as como acceder a toda la informacin
almacenada en los discos del computador, etc.
Un S.O. multiusuario debe garantizar que los procesos de usuario no interfieran con procesos
de otros usuarios, as como la privacidad de los datos. Para esto se implementan los permisos y
privilegios de usuario.
Generalmente se asigna a cada usuario una zona privada en memoria secundaria (esto es, discos
duros, etc.), que se determina en el perfil de usuario. El perfil de usuario es la informacin que
el S.O. almacena de cada usuario, incluyendo su zona privada, los permisos y privilegios que tiene,
etc. En el perfil de usuario se puede almacenar tanto archivos privados como la configuracin de las
aplicaciones.
5.1.3. Funciones de un sistema operativo
Desde el punto de vista del hardware, el sistema operativo se encarga de la administracin de
los recursos de la mquina:

Administracin de procesos y de la CPU.

Administracin de memoria principal.

Administracin del sistema de ficheros.

Administracin de dispositivos perifricos.

Esto es, el hardware slo se encarga de existir, el S.O. es el que lo gestiona y lo hace funcionar
tal y como se espera que lo haga.
Desde el punto de vista del usuario, el sistema operativo ofrece un interfaz entre el usuario y el
ordenador:

Intrprete de comandos y/o Interfaz grfica.

Ejecucin de aplicaciones.

Acceso a dispositivos perifricos.

Acceso controlado a ficheros.

Utilidades relativas a la seguridad del sistema.

En las siguientes secciones se estudiarn cada una de las funciones del S.O.

5.2. Funciones que el sistema operativo presta a los programas


5.2.1. Administracin de procesos
En los SSOO multitarea tenemos ms de un proceso en ejecucin de manera simultnea. De
hecho, en una mquina es habitual que se ejecuten muchos ms procesos que el nmero de CPUs
disponibles. Y recordar que muchos computadores actuales tienen varias CPUs (o ncleos) integra-
das.
Por lo tanto, el tiempo de cmputo de una CPU es un recurso escaso por el que compiten los
procesos en ejecucin en una mquina. El responsable que administrar el tiempo asignado a cada
proceso es el S.O., en lo que se conoce como planificacin de la CPU.
En los sistemas operativos modernos el S.O. asigna la CPU a cada proceso durante un muy
breve lapso de tiempo (quantum). Sin embargo, realiza esto de forma tan rpida que para un
usuario humano la sensacin es que todos los procesos se ejecutan de manera simultnea.
5.2 Funciones que el sistema operativo presta a los programas 164

Por otra parte, es el S.O. el responsable de ofrecer a los procesos (aplicaciones) un entorno
seguro de ejecucin, donde se garantiza que:

1. Un proceso no podr interferir en la ejecucin de otros procesos.

2. Un proceso no podr acceder de forma incorrecta o descontrolada al hardware. Por ejemplo,


en un S.O. multiusuario, con dos usuarios no adminitradores actualmente trabajando en la
mquina:

un proceso de usuario no puede borrar los datos de otro usuario


un proceso de usuario no puede desinstalar programas.
un proceso de usuario no puede reconfigurar un dispositivo hardware.

Si se produce alguna de las situaciones anteriores el sistema operativo genera una excepcin
(error) con dos posibles acciones:

Se da al proceso la oportunidad de corregir el error. Si no lo hace se termina el proceso.

En casos graves el S.O. toma el control y finaliza al proceso, normalmente el S.O. registra este
tipo de evento para control por parte del administrador.

5.2.2. Administracin de memoria


Cunta memoria RAM tiene instalada una mquina (memoria principal)? Cunto ocupa un
programa? Cuntos programas se ejecutan simultneamente? Qu pasa si la memoria principal
de la mquina es menor que lo que ocupan los procesos en ejecucin?
Todos los procesos deben residir total o parcialmente en memoria principal. Es decir, que no es
necesario que todo el programa (que pueden ser muchos, muchos MB) est cargado en memoria.
Realmente, un programa se carga de bloque en bloque, cada bloque es un nmero de bytes impor-
tante, que contiene muchas instrucciones en lenguaje mquina, y que permite ejecutar durante un
tiempo el programa. Cuando el bloque se ejecuta al completo, el bloque actual se desecha y se carga
el siguiente bloque de programa.
An as, y dado que la memoria principal de un computador est limitada, el S.O. debe admi-
nistrar la memoria principal disponible de la manera ms eficiente posible, asignando memoria para
los bloques de programa a ejecutar y liberando la memoria cuando se finaliza de ejecutar el bloque.
No obstante, cuando la memoria principal est bastante ocupada y se requiere ms memoria,
el S.O. suele realizar lo denominado paginacin de memoria. La paginacin de memoria es el
uso de memoria secundaria, normalmente en el disco duro donde residen los temporales del sistema
operativo, donde se copian bloques de memoria de procesos que actualmente no tienen asignado
tiempo de CPU.
An as, en ciertos casos de sobrecarga de procesos el sistema puede llegar a colapsarse ante la
falta de memoria principal.
5.2.3. Administracin del sistema de ficheros
Existe una parte del S.O. que se encarga de administrar el sistema de ficheros en memoria
secundaria. Los sistemas de archivos o ficheros es la forma de estructurar la informacin en una
unidad de almacenamiento o memoria secundaria. Cada sistema operativo utiliza su propio sistema
de archivos.
As, un sistema de archivos incluye la definicin de cmo se organiza un disco, qu datos se
guardan de cada uno de los directorios y archivos, cmo se almacena la informacin contenida en
un archivo, etc.
Un sistema de archivos admite organizar los datos en una jerarqua de directorios y/o ficheros
propios. Un archivo es el conjunto de datos relacionados con contenido relevante, p.e., un archivo
5.2 Funciones que el sistema operativo presta a los programas 165

>8%*5$:<269#$%*

3=* 3@*

!67898:8$9* 56%"00$))$* 56%"00$))$*


5"#$%* !67898:8$9*
567898:8;9'!$:(* !"#$%&'()%* /0$10"2"'34* ?$9#0"#$'#877* :$230"%'()%*
/06%<3<6%#$'()%* !"#$%+'()%* 360%$9")'()%*
!"#$%,'()%*
!"#$%-'()%*
!"#$%.'()%*

Figura 5.2: Ejemplo de jerarqua de directorios en un sistema de archivos.

o fichero de una imagen o una carta escrita con un editor de textos. Un directorio es totalmente
equivalente a carpeta, un contenedor de elementos del sistema de achivos. Luego un directorio
contiene tanto carpetas como archivos.
Todo sistema de archivos tiene un punto de montaje o de enlace que se conoce como raiz. En
los sistemas unix se tiene como punto raiz un determinado bloque de disco que el sistema operativo
denomina /. En los sistemas windows, se dispone de un sistema de archivos por cada uno de los
discos instalados en el sistema, asignndoles una letra, p.e. C:\.
A partir de estos puntos de montaje se puede crear una jerarqua de directorios y subdirectorios,
de manera que la informacin almacenada est bien organizada.
Para ilustrar esto, pongamos un ejemplo. Sea un usuario que tiene 2 proyectos que llevar a cabo,
los proyectos A y B. Para el proyecto A tiene informacin de definicin del problema (un archivo de
texto), datos extrados de unas pruebas (5 archivos de excel), y un programa que ha desarrollado
para su gestin. Por otro lado, del proyecto B tiene una imagen en formato tiff con el contrato
escaneado, mas unas hojas de excel de gestin de compra de material, y un listado de personal que
est trabajando en el proyecto.
Luego, una buena organizacin permite buscar informacin de cada proyecto de forma rpida. Lo
ms sencillo es crear un directorio para cada proyecto, con nombres que estn altamente relacionados
con sus contenidos. De igual manera, para el proyecto A se debera crear un directorio para la
definicin del problema, otro para los datos, y otro para el programa realizado. Similarmente se
procedera con el proyecto B, lo que generara una jerarqua de directorios como la que se muestra
en la figura 5.2.
Se conoce como ruta o path de un archivo el listado de directorios desde el raz hasta donde
se encuentra dicho archivo, todos ellos separados por un carcter especfico del sistema operativo.
Por ejemplo, si se tratase de Windows, la ruta del archivo Programa.py es MisDocumentos\
Programa\.
Las rutas pueden ser relativas al directorio actual o absolutas desde el directorio raz. En el caso
de la figura 5.2, si suponemos que la carpeta Mis Documentos est en el disco C:\, entonces la
ruta absoluta es del archivo Programa.py es C:\MisDocumentos\Programa\. La ruta rela-
tiva del archivo Programa.py, asumiendo que estoy visualizando el directorio MisDocumentos,
es .\Programa\.
El nombre completo de un archivo es la unin de la ruta absoluta y su nombre: C:\MisDocumentos\
Programa\Programa.py
Los sistemas operativos incluyen herramientas o utilidades para la gestin de los sistemas de
archivos, a modo de ejemplo:

crear, copiar, mover y borrar archivos

comprimir y descomprimir archivos

desfragmentar las unidades de disco


5.3 Funciones que el sistema operativo presta a los usuarios 166

comprobacin de estado

formateado de unidad de disco (se crea un sistema de ficheros inicialmente vaco, donde solo
existe el directorio raz).

Desafortunadamente, como cada sistema operativo tiene su propio sistema de archivos, no se


pueden intercambiar unidades de disco entre sistemas operativos diferentes sin ms, es necesario
utilizar herramientas especficas para ello.
5.2.4. Administracin de dispositivos
El sistema operativo facilita el acceso a los dispositivos perifricos por parte de las aplicacio-
nes, de manera que no es necesario conocer los aspectos tcnicos del dispositivo y realizar con los
dispositivos operaciones de lectura/escritura.
Cada dispositivo perifrico necesita un software especial que funciona como interfaz con el S.O.,
conocido como driver o controlador de dispositivo.
El controlador de dispositivo es especfico del hardware y del S.O. y debe instalarse en el orde-
nador para que el S.O. pueda utilizar el dispositivo. El controlador de dispositivo no forma parte
del S.O. y debe proporcionarlo el fabricante del dispositivo.

5.3. Funciones que el sistema operativo presta a los usuarios


5.3.1. Interfaz usuario-ordenador
Los SSOO incorporan una aplicacin de interfaz entre el usuario y el ordenador. El usuario
realiza operaciones a travs de esta aplicacin:

ejecucin de aplicaciones de usuario

manipulacin de carpetas y ficheros

acceso a dispositivos perifricos.

Los interfaces con los usuarios no forman parte de los SSOO, propiamente dicho, si bien todo
S.O. incluye un tipo de interfaz con el usuario. A modo de ejemplo, para Linux se han desarrollado
varios interfaces de escritorio, pudiendo el usuario elegir cul utiliza en su mquina.
Los interfaces con el usuario pueden ser una interfaz de texto, mediante un intrprete de
comandos de sistema operativo, o bien puede tratarse de una interfaz grfica (tambin conocida
como GUI -interfaz grfica de usuario). En todos los sistemas operativos de usuario actuales
se dispone de ambas; en Windows se dispone de cmd (smbolo de sistema o ventana del DOS), en
UNIX se dispone de varias interfaces (sh, csh, ksh, bash, . . . ).
Las terminales de comandos fueron los primeros interfaces incorporados en los SSOO (por ejem-
plo UNIX y MS-DOS). Esto es as debido a que el coste computacional es muy bajo, y en esos
tiempos no se dispona de mucha potencia computacional. Actualmente estn presentes en todos
los SSOO modernos.
En estos interfaces, todas las rdenes deben realizarse mediante comandos de texto. Estos coman-
dos son rdenes que el sistema operativo entiende perfectamente: nombres de programas, comandos
de sistema, archivos ejecutables, etc.
En cuanto a los comandos y archivos ejecutables, la interfaz de comandos dispone de un lenguaje
de programacin para llevar a cabo tareas de forma secuencial y sin atencin directa por parte del
usuario (desatendida). Por ejemplo, el sistema operativo tiene un comando para listar el contenido
de directorios. Si se desease buscar dnde se encuentran unos ficheros concretos en una jerarqua de
archivos, sera posible generar un cdigo de forma que deje como salida los archivos y su ruta.
A favor de los intrpretes de comandos se pude indicar que a) permite gestionar el sistema
operativo con ms profundidad dado que se tiene control absoluto sobre las opciones, b) permite
5.3 Funciones que el sistema operativo presta a los usuarios 167

realizar operaciones masivas y de forma desatendida, c) incorporan un lenguaje de programacin


para disear comandos ms complejos, y d) requieren un menor consumo de recursos. Por contra,
es necesario un mayor conocimiento tcnico del S.O. y resultan poco intuitivos.
En cuanto a los interfaces grficos se puede decir que son una evolucin del intrprete de co-
mandos, facilitando el acceso y la interaccin del usuario mediante objetos grficos como ventanas,
botones, iconos enlazados, imgenes, etc. Requieren pocos conocimientos tcnicos al ser, por regla
general, muy intuitivos. Por contra, en muchos casos limitan la operatividad y las posibilidades de
configuracin al estar pensados para las labores ms usuales y rutinarias en un computador. Clara-
mente, al manejar recursos grficos requieren mayor consumo de recursos de la mquina. Finalmen-
te, son poco aconsejables para operaciones masivas y permiten directamente realizar operaciones
desatendidas.
5.3.2. Acceso a las Redes de Computadores
Entenderemos por redes de computadores todos los elementos hardware y software que permiten
que los computadores intercambien datos de cualquier ndole. Las redes de computadores se pueden
clasificar de muchas maneras; en este tema no se dar una clasificacin exhaustiva sino que se
mostrar una clasificacin basada en el alcance de la red. Seguidamente se explicar el modelo
de red TCP/IP de forma muy abreviada. Ffinalmente, la configuracin del mismo para el sistema
operativo Windows 8.
Atendiendo al alcance, es decir, la distancia mxima de conexin, podemos clasificar las redes
como:

Personal Area Network (PANs) tienen como objetivo comunicar computadores con perifricos
por lo que se trata de redes de muy limitado alcance y con cierta limitacin en el ancho de
banda. Ejemplos de estas redes: BlueTooth, ANT+.

Local Area Network (LAN) conecta computadores dentro de un rea de trabajo. En cuanto a
alcance, tradicionalmente se asumen distancias de cientos de metros; aunque con la tecnologa
actual las distancias realmente no estn tan acotadas. Ejemplos de estas redes: Ethernet,
Zigbee, la familia IEEE 802, etc.

Wide Area Network (WAN) enlaza tanto LANs como otras WANs para interconectar redes
mediante infraestructura privada o pblica. En este caso, podemos citar redes como ATM,
X.25, etc.

Existen muchos posibles actores en una red pero slo se detallarn los ms relevantes para poder
entender de forma sencilla el funcionamiento de las mismas . Los principales actores que intervienen
en una red son (ver figura 5.3.2):

Computador: elemento a interconectar, incluyendo tanto computadores personales, servidores,


etc.

Punto de Acceso o Access Point (AP): se refiere al elemento que dota de red local inalmbrica
a un rea determinada.

Puerta de enlace o Gateway: es el dispositivo que permite el paso de una red a otra. Si es a
nivel de hardware hablamos de puentes (bridge), si es a niveles de red superior hablamos de
routers, etc.

Enrutador o Router: permite la inteconexin entre redes.


5.3 Funciones que el sistema operativo presta a los usuarios 168

Figura 5.3: Esquema de una red inalmbrica domstica con acceso a Internet.

La red WiFi domstica


Para intentar que se entienda todo esto, usaremos un ejemplo que hoy en da es muy
comn: el acceso a Internet en el hogar mediante un router WiFi (llammosle rWF). Los
rWFs actuales suelen disponer de unos puertos para conectar computadores mediante el
estndar IEEE 802.3 (Ethernet); para ello se utiliza el cable con de 8 hilos con conector
RJ45. Adems, funciona como punto de acceso a la red local inalmbrica (WiFi) segn
el estndar IEEE 802.11. Esto significa que ese dispositivo rWF acta de puente entre
los puertos RJ45 y el acceso inalmbrico, pero todos ellos formarn una red local: todos
ellos se podrn ver e interactuar entre s. Finalmente, para que todos los ordenadores
puedan acceder a Internet, los rWF incluyen: i) la funcin de enrutado, que permite
el intercambio de datos entre computadores pertenecientes a diferentes redes, y ii) un
puerto WAN especfico para conectarse al proveedor -Telecable, MoviStar, Orange, . . . -.

Actualmente, el modelo de red por excelencia es el modelo TCP/IP (es el que utiliza Internet).
Este modelo est basado en capas: la capa 1 de acceso al medio fsico y enlace, la capa 2 de red,
la capa 3 de transporte y la capa 4 de aplicacin. La capa 1 es la que define cmo se conectan
ordenadores a una red local, con posibles diferentes tecnologas como puede ser IEEE 802.3 e IEEE
802.11.
De forma simple, en el modelo TCP/IP cada ordenador tiene un identificador nico o direccin
de red -conocida como direccin IP de la mquina-. Este identificador es un entero de 32 bits
agrupado en 4 grupos de 8 bits. Como 28 = 256, con cada grupo de 8 bits podemos tener 256
valores diferentes, de 0 a 255. Por todo ello, las direcciones IP se indican con esos 4 valores, por
ejemplo, 156.35.33.105 de www.uniovi.es.
Todos los ordenadores de una red local comparten los bits ms significativos de la direccin de
red de 32 bits. Para conocer esta parte comn se utiliza la mscara de red, otros 32 bits expresados
de forma similar a la direccin IP, que permiten saber la direccin de la red local: si se hace al and
lgico entre la direccin IP y la mscara, el resultado es la parte comn. Consecuentemente, en la
mscara de red se ponen a uno todos los bits que son comunes a la direccin de la red, el resto a 0.
Un ejemplo de las operaciones realizadas se visualiza en la tabla 5.1. Tanto la direccin de red como
la mscara de red es un dato que el administrador de red nos indicar si tenemos que especificar
5.3 Funciones que el sistema operativo presta a los usuarios 169

dicha informacin a nuestro ordenador para conectarnos en red.

IP en decimal IP en binario
Direccin de red 156.35.33.105 10011100 00100011 00100001 01101001
Mscara de red 255.255.255.0 11111111 11111111 11111111 00000000
Resultado del AND 156.35.33.0 10011100 00100011 00100001 00000000

Tabla 5.1: Uso de la mscara para determinar la direccin de la red.

Para conectar ordenadores entre diferentes redes se utiliza la capa 2 del modelo TCP/IP, mientras
que la capa 3 de transporte permite disponer de puntos de acceso de red a las aplicaciones o
programas. Cada punto de acceso a la red que proporcional la cada de transporte est formado por
una direccin de red mas un entero de 16 bits denominado puerto. Un puerto que es probable todos
conozcan es el 80, puerto estndar para el servicio HTTP.
Finalmente, est la capa de aplicacin que especifica cmo deben comunicarse los programas. Por
ejemplo, el protocolo HTTP especifica como intercambian informacin un servidor web y un cliente
web. Un servicio imprescindible es el servicio de nombres en Internet. Este servicio permite asignar
nombres -segn una notacin jerrquica- a mquinas o servicios, con lo que no es necesario conocer
la direccin de red sino un nombre, por ejemplo www.uniovi.es. Las mquinas siguen teniendo la
direccin de red, pero se les pone como apodo un nombre ms fcil de recordar por el ser humano.
Este servicio de nombres es el conocido como Servicios de nombres de dominio, DNS.
Resumiendo, la informacin que un ordenador debe tener para poder conectarse a internet es:
1. Direccin de red IP,

2. Mscara de Red,

3. Direccin de red del gateway o puerta de enlace,

4. Direccin o direcciones de red del/de los servidores DNS.


Estos datos los debe aportar el administrador de red. Es posible que se ajusten automticamente,
lo que hoy por hoy es lo ms comn, mediante el protocolo conocido como DHCP, Dynamic Host
Configuration Protocol. El administrador de la red puede indicar que los datos de direccin de red,
mscara y gateway se adquieren dinmicamente -especificando los servidores de nombres- o que
todos los datos se adquieren mediante DHCP, dinmicamente.
En las sucesivas imgenes se ver cmo se configura la red en Windows 8. Hay que acceder al
Panel de Control, y de ah, al Centro de Redes y Recursos Compartidos de Windows.
5.3.3. Aplicaciones relativas a la seguridad del sistema
No forman parte del sistema operativo propiamente dicho, sino que se trata de utilidades desa-
rrolladas por otros que se integran en el sistema operativo. Es habitual que en SSOO modernos se
incorporen este tipo de utilidades de serie.
Algunas de estas herramientas son:
Antivirus es una aplicacin diseada para combatir y evitar de forma activa la infeccin del
ordenador por un virus informtico.
Un virus informtico es un software malintencionado que altera el funcionamiento normal del
ordenador. Aunque existe la creencia que existe algn S.O. al que no atacan los virus, en la
realidad todos los SSOO son susceptibles de tener virus: solo tiene que haber personas que
realicen los programas adecuadamente!
Un virus se camufla en ficheros ejecutables e incluso en el cdigo de arranque del sistema
operativo, y suele modificar otros ejecutables para que incluyan una copia del propio virus.
5.3 Funciones que el sistema operativo presta a los usuarios 170

Figura 5.4: Paso 1.- Acceso a Configuracin desde el escritorio.

Figura 5.5: Paso 2.- Acceso al Panel de Control.


5.3 Funciones que el sistema operativo presta a los usuarios 171

Figura 5.6: Paso 3.- Acceso al Centro de Redes y Recursos Compartidos.

Figura 5.7: Paso 4.- Acceder a las propiedades de la conexin. Tambin se muestra el cuadro de
dilogo de detalles con la informacin de la conexin de red de la interfaz de red -tarjeta de red-.
5.3 Funciones que el sistema operativo presta a los usuarios 172

Figura 5.8: Paso 5.- Acceso a las propiedades de TCP/IP y configuracin de los diferentes datos
dados por el administrador de red.

Tpicas formas de transmisin de virus es mediante el intercambio de ficheros infectados en el


disco o lpiz USB, correo electrnico, acceso a pginas web, etc.
Un virus se activa por primera vez al ejecutar o al acceder a un fichero infectado. Al activarse
el virus queda residente y camuflado en memoria principal. Paulatinamente, toma el control
de los servicios bsicos del S.O. y se propaga infectando otros ficheros. Posteriormente suele
instalarse en el cdigo de arranque del ordenador para tomar el control al encender el equipo.
Un software antivirus dispone de una base de datos con todos los virus conocidos. Permanece
residente en memoria y chequea todos los ficheros abiertos por el S.O. buscando trazas de
algn virus conocido. Es por ello que es de importancia vital actualizar la base de datos de
virus diariamente, bsicamente aprovechando que la mayor parte de los antivirus se actualizan
automticamente a travs de internet.

Anti-spyware es una aplicacin diseada para combatir de forma activa la infeccin del ordenador
por un programa espa de manera similar a un antivirus.
Un spyware o spy es un software malintencionado que recopila informacin de las actividades
del usuario. Su objetivo principal es recopilar informacin de los hbitos y gustos del usuario
para enviarlo a empresas publicitarias.
Existen programas espa no malintencionados, como puede ser la informacin de usuario re-
copilada y enviada por software legal instalado en la mquina (p.e., el paquete informtico
Office).
La informacin que suele recopilarse incluye datos de mensajes y contactos de correo electr-
nico, direccin IP, pginas web visitadas, software instalado, descargas realizadas, etc.
Al igual que los antivirus, los anti-spyware dispone de una base de datos con programas espa
5.4 Sistemas operativos utilizados en entornos profesionales de ingeniera 173

conocidos que conviene mantener actualizada. Su funcionamiento se basa en bloquear el envo


de datos confidenciales a travs de internet (Ej: datos personales), bloquear paneles emergentes
de publicidad no autorizados (anti-adware), etc.

Cortafuegos es una aplicacin que controla el acceso de otros computadores a la mquina actual,
as como la capacidad de las aplicaciones instaladas en sta para comunicarse con el exterior
a travs de la red (habitualmente Internet).
Las aplicaciones de red pueden iniciar la comunicacin en dos sentidos:

1. Conexiones salientes.- Nuestra aplicacin solicita a otro ordenador de la red que le enve
cierta informacin (Ej: Navegador web).
2. Conexiones entrantes.- Otro ordenador de la red solicita a una aplicacin de nuestro
ordenador que le enve cierta informacin (Ej: escritorio remoto, aplicacin P2P, juegos).

Salvo las procedentes de programas spy-ware, las conexiones salientes no representan un pro-
blema de seguridad que no est controlado por el usuario (p.e., evitar acceder a sitios web de
seguridad comprometida, no abrir correos de procedencia desconocida o sospechosa, etc.).
Sin embargo, las conexiones entrantes son potencialmente peligrosas por varios motivos. En
primer lugar, pueden acceder a nuestro ordenador para coger informacin. Por otra parte,
pueden controlar remotamente el ordenador (escritorio remoto).
El cortafuegos o firewall controla de forma activa las conexiones de red realizadas en nuestro
ordenador. Al igual que otras aplicaciones de seguridad permanece residente en memoria
principal.
Su misin fundamental es la de notificar al usuario intentos de conexin de aplicaciones de
red desconocidas. Una vez que el usuario decide si permite o no la conexin se memoriza la
respuesta creando una regla. Algunos cortafuegos solo notifican conexiones de entrada y no
de salida (Ej.: Firewall de windows).

5.4. Sistemas operativos utilizados en entornos profesionales de inge-


niera
5.4.1. Sistemas operativos en tiempo real
Los sistemas operativos en tiempo real dan soporte a aplicaciones en tiempo real, y por lo tanto
deben responder correctamente dentro de un intervalo de tiempo determinado.
En este tipo de sistemas operativos se da prioridad a las aplicaciones (procesos) frente al usuario,
dada la importancia de las tareas controladas. Por lo tanto, en estos SSOO el interfaz de usuario es
poco importante.
Algunos campos de aplicacin son el trfico (tanto areo, terrestre o natico), sistemas de gestin
y control de trenes, o los actuales sistemas de fabricacin integrada.
Algunos ejemplos de sistema operativo en tiempo real son:

VxWorks S.O. basado en UNIX, creado por Wind River Systems.

LynxOS S.O. basado en UNIX, creado por LynuxWorks.

eCos basado en Linux Red Hat.

Ubuntu Studio basado en Linux Ubuntu.


174

5.4.2. Sistemas operativos empotrados


Se conoce como sistema empotrado los sistemas informticos integrados en un sistema de inge-
niera ms general. El ejemplo clsico es el de los automviles actuales, donde un computador de a
bordo de un automvil gestiona todos los subsistemas: frenado, suspensiones, motor, confort, etc.
El sistema de ingeniera ms general es el automvil, el sistema empotrado es el computador de a
bordo.
Los sistemas empotrados no son computadores de propsito general como los usuales en todas
las oficinas (p.e., un PC), sino que estn diseados especficamente para un determinado propsito.
Es usual que los sistemas empotrados se encarguen de realizar funciones de control, procesamiento
y/o monitorizacin. A los sistemas empotrados con restricciones de tiempo real se les conoce como
sistemas empotrados de tiempo real.
Ejemplos de sistemas empotrados:

Electrnica de consumo: videos, lavadoras, frigorficos, ...

Automviles: Control de velocidad, climatizacin, ABS, ...

Telecomunicaciones: Radios, telfonos mviles, ...

A los sistemas operativos utilizados en sistemas empotrados se les denomina sistemas opera-
tivos empotrados, los cules deben adaptarse para las restricciones de tamao, memoria principal
disponible, energa a consumir, etc. Los sistemas operativos empotrados pueden ser:

Software muy pequeo desarrollado especficamente para algn sistema embebido en particu-
lar.

Versin reducida de algn sistema operativo de propsito general (Ejemplos: Windows C.E.,
Linux embebido).

Algunos ejemplos de sistema operativo empotrado son:

Symbian O.S.

Windows C.E.

Palm O.S.

Linux embebido.

iOS (S.O. del iTouch, iPad, iPhone)


Parte VI
Referencias

175
Referencias

[1] R. A. Espaola, Diccionario de la Lengua Espaola. Website, 2010. http://buscon.rae.


es/draeI/.

[2] J. A. Lpez-Frez, Los dioses griegos y sus mitos en Galeno. Revistas de la UCM, 2010.
http://revistas.ucm.es/fll/11319070/articulos/CFCG0404110155A.PDF.

[3] R. Graves, Dioses y hroes de la antigua Grecia. Biblioteca Upasika, 2010. http://www.
upasika.com/robertgraves.html.

[4] M. E. et al, The Antikythera Mechanism Research Project. Website, 2010. http://www.
antikythera-mechanism.gr.

[5] S. Al-Hassani, Al-Jazari: The mechanical genious. The Muslims Heritage Website, 2010.
http://muslimheritage.com/topics/default.cfm?ArticleID=188.

[6] G. Nadarajan, Islamic automation: A reading of Al-Jazaris The Book of Knowledge of Inge-
nious Mechanical Devices (1206). The First International Conference on the Histories of Media
Art, Science and Technology, The Banff Centre, 2010. http://www.banffcentre.ca/bnmi/
programs/archives/2005/refresh/docs/conferences/Gunalan_Nadarajan.pdf.

[7] M. Taddei, Leonardo da Vincis robots. New mechanics and new automata found in codices.
Leonardo3, 2010. http://www.leonardo3.net.

[8] T. Computer History Museum, First Data Storage Mechanism. The Computer History
Museum Website, 2010. http://courses.coe.uh.edu/smcneil/cuin7317/students/
museum/slong.html.

[9] C. Babbage, The Analytical Engine. The Science Museon of South Kensinton,
2010. http://www.sciencemuseum.org.uk/objects/computing_and_data_processing/
1992-556.aspx.

[10] F. da Cruz, Herman Hollerith. Columbia University Computing History, 2010. http://www.
columbia.edu/acis/history/hollerith.html.

[11] T. F. E. Team, Computer programming. Wikipedia, 2010. http://en.wikipedia.org/


wiki/Computer_programming.

[12] H. B. Enderton, Alonzo Church: Life and Work. Introduction to the Collected Works of Alonzo
Church. The MIT Press, 2010. http://www.math.ucla.edu/~hbe/church.pdf.

[13] . Lvnez, The History of Programming Languages. OReilly Media, Inc, 2008. http:
//oreilly.com/pub/a/oreilly/news/languageposter_0504.html.

[14] . Lvnez, The History of Programming Languages. OReilly Media, Inc, 2008. http:
//www.levenez.com/lang/.

176
REFERENCIAS 177

[15] A. Silberschatz, P. Galvin, and G. Gagne, Fundamentos de Sistemas Operativos, 7ma Edicin.
McGraw Hill, 2006.

[16] A. Prieto and B. Prieto, Conceptos de Informtica. McGraw Hill, 2005.

Potrebbero piacerti anche