Programación Estructurada
Programación Estructurada
Programación estructurada
Programación estructurada
Índice general
4. Funciones imperativas 16
4.1. Definición de funciones imperativas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.2. Llamadas a funciones imperativas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.3. Paso de argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.4. La sentencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.5. Ámbito de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.5.1. Variables locales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.5.2. Variables globales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4.6. Funciones locales a funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.6.1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.7. Docstrings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1
Programación estructurada 1. Aspectos teóricos de la programación estructurada
Si un programa se escribe de cualquier manera, aun siendo correcto desde el punto de vista de su
funcionamiento, puede resultar engorroso, críptico, ilegible y casi imposible de modificar.
Lo que hay que hacer, en primer lugar, es impedir que el programador pueda escribir programas de
cualquier manera, y para ello hay que restringir sus opciones a la hora de construir programas de
forma que el diagrama resultante sea fácil de leer, entender y mantener.
Ese diagrama, una vez terminado, debe estar construido combinando sólo unos pocos tipos de blo‐
ques y cumpliendo una serie de restricciones.
Acción
Condición
Agrupamiento
Aquí se observa otro programa que no es propio, ya que existen bloques (los A, C y q) que no tienen
un camino hasta la salida; si el programa llegara hasta esos bloques se bloquearía, pues no es posible
terminar la ejecución:
Aquí aparece un programa que contiene bloques inaccesibles desde la entrada del diagrama:
1.4. Estructura
Una estructura es una construcción sintáctica (o un bloque constructivo) que se puede anidar com‐
pletamente dentro de otra.
Eso significa que, dadas dos estructuras cualesquiera, o una está incluida completamente dentro de
la otra, o no se tocan en absoluto.
A B C D E F
Estructuras
Secuencia
Selección
Iteración
En pseudocódigo:
– Secuencia:
A
B
– Selección:
si p entonces
A
sino
B
– Iteración:
mientras p hacer
A
Cada una de las acciones que aparecen en una estructura pueden ser, a su vez, estructuras.
– Esto es así porque se considera que una estructura es, también, una acción (compuesta, a dife‐
rencia de las acciones simples).
– Por tanto, una estructura puede aparecer en cualquier parte donde se espere una acción.
Resumiendo, en un programa podemos tener dos tipos de acciones:
– Acciones simples
– Estructuras de control, que son acciones compuestas formadas a su vez por otras acciones (que
podrán ser, a su vez, simples o compuestas, recursivamente).
Por consiguiente, todo programa puede verse como una única acción, simple o compuesta por otras.
Un programa estructurado equivalente al del ejemplo anterior, pero mucho más claro, sería:
inicio
leer a
leer b
mientras a != b hacer
si a < b entonces
b←b−a
sino
a←a−b
escribir a
fin
Teorema de la estructura:
Todo programa propio es equivalente a un programa estructurado.
Por tanto, los programas estructurados son suficientemente expresivos como para expresar cual‐
quier programa razonable.
Y además, por su naturaleza estructurada resultan programas más sencillos y claros.
En consecuencia, no hay excusa para no estructurar nuestros programas.
Concepto fundamental:
En Python, la estructura del programa viene definida por la indentación del código.
Ejemplo:
Estas cuatro sentencias, al estar todas al mismo nivel de indentación, actúan como una sola sentencia
en bloque y se ejecutan en orden de arriba abajo.
2.2. Selección
La selección (o estructura alternativa) tiene varias sintaxis en Python:
Selección simple:
condición
sentencia
Selección doble:
condición
sentencia
sentencia
Selección múltiple:
condición
sentencia
[ condición
sentencia ]
[
sentencia ]
Ejemplos:
2.3. Iteración
La iteración (estructura iterativa o repetitiva) en Python tiene la siguiente sintaxis:
condición
sentencia
produce:
2.4.2.
La sentencia se usa para saltarse el resto del código dentro de un bucle en la iteración
actual.
El bucle no finaliza sino que continúa con la siguiente iteración.
produce:
2.4.3. Excepciones
Incluso aunque una sentencia o expresión sea sintácticamente correcta, puede provocar un error
cuando se intente ejecutar o evaluar.
Los errores detectados durante la ejecución del programa se denominan excepciones y no tienen
por qué ser incondicionalmente fatales si se capturan y se gestionan adecuadamente.
En cambio, la mayoría de las excepciones no son gestionadas por el programa y, por consiguiente,
provocan mensajes de error y la terminación de la ejecución del programa.
Por ejemplo:
sentencia
( [ excepcion [ identificador ]]
sentencia )+
[
sentencia ]
[
sentencia ]
donde:
Su funcionamiento es el siguiente:
– Se intenta ejecutar el bloque de sentencias del .
– Si durante su ejecución no se levanta ninguna excepción, se saltan los y se ejecutan
las sentencias del (si existe).
– Si se levanta alguna excepción, se busca (por orden de arriba abajo) algún que cua‐
dre con el tipo de excepción que se la lanzado y, si se encuentra, se ejecutan sus sentencias
asociadas.
– Finalmente, y en cualquier caso (se haya levantado alguna excepción o no), se ejecutan las
sentencias del (si existe).
Por ejemplo, el siguiente programa pide al usuario que introduzca un número entero por la entrada.
Si el dato introducido es correcto (es un número entero), lo muestra a la salida multiplicado por tres
y dice que la cosa acabó bien. Si no, muestra un mensaje de advertencia:
Con esta técnica, los programas se crean en distintos niveles de refinamiento, de forma que cada
nuevo nivel define la solución de forma más concreta y subdivide las operaciones en otras menos
abstractas.
Los programas se diseñan de lo general a lo particular por medio de sucesivos refinamientos o des‐
composiciones que nos van acercando a las instrucciones finales del programa.
El último nivel permite la codificación directa en un lenguaje de programación.
El refinamiento acaba cuando la solución se encuentra completamente definida usando los elemen‐
tos del lenguaje de programación (ya no hay recursos abstractos).
3.3. Ejemplo
Supongamos que queremos escribir un programa que muestre una tabla de multiplicar de tamaño
n × n.
Por ejemplo, para n = 10 tendríamos:
1 2 3 ··· 10
2 4 6 ··· 20
3 6 9 ··· 30
.. .. .. .. ..
. . . . .
10 20 30 ··· 100
inicio
leer n
construir la tabla de n × n
fin
donde el programa se plantea como una secuencia de dos acciones: preguntar el tamaño de la tabla
deseada y construir la tabla propiamente dicha.
La instrucción leer n ya está suficientemente refinada (se puede traducir a un lenguaje de programa‐
ción) pero la segunda no (por tanto, es un recurso abstracto).
La construcción de la tabla se puede realizar fácilmente escribiendo en una fila los múltiplos de 1,
en la fila inferior los múltiplos de 2, y así sucesivamente hasta que lleguemos a los múltiplos de n.
Por tanto, el siguiente paso es refinar la instrucción abstracta construir la tabla de n × n, creando un
nuevo nivel de refinamiento:
inicio
leer n
# construir la tabla de n × n:
i←1
mientras i ≤ n:
escribir la fila de i
i←i+1
fin
donde ahora aparece la acción escribir la fila de i, que escribe cada una de las filas de la tabla, y que
habrá que refinar porque no se puede traducir directamente al lenguaje de programación.
En este (último) nivel refinamos la acción que nos falta, quedando:
inicio
leer n
{ construir la tabla de n × n: }
i←1
mientras i ≤ n:
{ escribir la fila de i: }
j←1
mientras j ≤ n:
escribir i × j
j←j+1
escribir un salto de línea
i←i+1
fin
O mejor aún:
4. Funciones imperativas
4.1. Definición de funciones imperativas
En programación imperativa también podemos definir funciones.
Al igual que ocurre en programación funcional, una función en programación imperativa es una
construcción sintáctica que acepta argumentos y produce un resultado.
Pero a diferencia de lo que ocurre en programación funcional, una función en programación impera‐
tiva contiene sentencias.
Las funciones en programación imperativa conforman los bloques básicos que nos permiten des‐
componer un programa en partes que se combinan entre sí.
Todavía podemos construir funciones mediante expresiones lambda, pero las funciones imperativas
tienen ventajas:
– Podemos escribir sentencias dentro de las funciones imperativas.
– Podemos escribir funciones que no devuelvan ningún resultado porque su cometido es provo‐
car algún efecto lateral.
La definición de una función imperativa tiene la siguiente sintaxis:
nombre [ parámetros ]
cuerpo
donde:
Por ejemplo:
La definición de una función imperativa es una sentencia compuesta, es decir, una estructura (como
las estructuras de control , , etc.).
Por tanto, puede aparecer en cualquier lugar del programa donde pueda haber una sentencia.
Como en cualquier otra estructura, las sentencias que contiene (las que van en el cuerpo de la
función) van indentadas (o sangradas) dentro de la definición de la función.
Por tanto (de nuevo como en cualquier otra estructura), el final de la función se deduce al encontrarse
una sentencia menos indentada que el cuerpo, o bien el final del script.
3. El flujo de control del programa se transfiere al bloque de sentencias que forman el cuerpo de la
función y se ejecuta éste.
Cuando se finaliza la ejecución de las sentencias que forman el cuerpo de la función:
1. Se genera su valor de retorno (en breve veremos cómo).
2. Se saca su registro de activación de la pila.
3. Se devuelve el control de la ejecución a la línea de código que llamó a la función.
4. Se sustituye, en dicha línea, la llamada a la función por su valor de retorno.
5. Se continúa la ejecución del programa desde ese punto.
Por ejemplo:
1
2
3
4
1
2
3
4
Por ejemplo:
1
2
3
4
5
6
7
La función es capaz de cambiar el estado interno de la lista que se ha pasado como argumento
porque:
– Al llamar a la función, el argumento se pasa a la función asignándola al parámetro
como si hubiera hecho .
– Eso hace que ambas variables sean alias una de la otra (se refieren al mismo objeto).
– Por tanto, la función está modificando la misma variable que se ha pasado como argumento
( ).
4.4. La sentencia
Para devolver el resultado de la función al código que la llamó, hay que usar una sentencia .
Cuando el intérprete encuentra una sentencia dentro de una función:
– se finaliza la ejecución de la función,
– se devuelve el control al punto del programa en el que se llamó a la función y
– la función devuelve como resultado el valor de retorno definido en la sentencia .
Por ejemplo:
1
2
3
4
5
6
7
La función se define en las líneas 1–2. El intérprete lee la definición de la función pero no ejecuta
las sentencias de su cuerpo en ese momento (lo hará cuando se llame a la función).
En la línea 6 se llama a la función pasándole como argumentos los valores de y , asignándo‐
seles a e , respectivamente.
Dentro de la función, se calcula la suma y la sentencia finaliza la ejecución de la
función, devolviendo el control al punto en el que se la llamó (la línea 6) y haciendo que su valor de
retorno sea el valor calculado en la suma anterior (el valor de la expresión que acompaña al ).
El valor de retorno de la función sustituye a la llamada a la función en la expresión en la que aparece
dicha llamada, al igual que ocurre con las expresiones lambda.
Por tanto, una vez finalizada la ejecución de la función, la línea 6 se reescribe sustituyendo la llamada
a la función por su valor.
Si, por ejemplo, suponemos que el usuario ha introducido los valores y en las variables y ,
respectivamente, tras finalizar la ejecución de la función tendríamos que la línea 6 quedaría:
imprime:
imprime:
Cuando se alcanza el final del cuerpo de una función sin haberse ejecutado antes ninguna sentencia
, es como si la última sentencia del cuerpo de la función fuese un sin valor de retorno.
Por ejemplo:
equivale a:
Esa última sentencia nunca es necesario ponerla ya que la ejecución de una función termina
automáticamente (y retorna al punto donde se la llamó) cuando ya no quedan más sentencias que
ejecutar en su cuerpo.
1
2
3
4
5
6
Fuera de la función, la variable no está definida en el entorno (que está formado sólo por el
marco global) y por eso da error en la línea 6.
Eso significa que se crea un nuevo marco en el entorno que contendrá, en principio, los parámetros,
las variables locales y las ligaduras locales a la función.
1
2
3
4
5
6
Marco global
suma función
resultado 7
Entorno en la línea 6
Marco de suma
x 4
Marco global
y 3 suma función
res
Pero para poder modificar una variable global es necesario que la función la declare previamente
como global.
De no hacerlo así, el intérprete supondría que el programador quiere crear una variable local que
tiene el mismo nombre que la global:
Como en Python no existen las declaraciones de variables, el intérprete tiene que averiguar por sí
mismo qué ámbito tiene una variable.
Lo hace con una regla muy sencilla:
Si hay una asignación a una variable dentro de una función, esa variable se considera local.
El siguiente código genera un error «UnboundLocalError: local variable ‘x’ referenced before assignment».
¿Por qué?
4.5.2.1.
Para informar al intérprete que una determinada variable es global, se usa la sentencia :
Si la variable global no existe en el momento de realizar la asignación, se crea. Por tanto, una función
puede crear nuevas variables globales usando :
Cambiar el estado de una variable global es uno de los ejemplos más claros y conocidos de los
llamados efectos laterales.
Recordemos que una función tiene (o provoca) efectos laterales cuando provoca cambios de estado
observables desde el exterior de la función, más allá de devolver su valor de retorno. Típicamente:
– Cuando cambia el valor de una variable global
– Cuando cambia un argumento mutable
– Cuando realiza una operación de entrada/salida
Una función que provoca efectos laterales es una función impura, a diferencia de las funciones
puras, que no tienen efectos laterales.
Una función también puede ser impura si su valor de retorno depende de algo más que de sus
argumentos (p. ej., de una variable global).
Un ejemplo de función impura (con un efecto lateral provocado por una operación de entrada/salida)
podría ser:
Cualquiera que no sepa cómo está construida internamente la función , se podría pensar que
lo único que hace es calcular la suma de dos números, pero resulta que también imprime un mensaje
en la salida, por lo que el resultado final que se obtiene no es el que se esperaba:
que hacer:
Igualmente, el uso de la sentencia supone otra forma más de perder transparencia refe‐
rencial, puesto que, gracias a ella, una función puede cambiar el valor de una variable global, lo que
la convertiría en impura porque podría provocar un efecto lateral (la modificación de la variable
global).
En consecuencia, la función podría producir resultados distintos en momentos diferentes ante los
mismos argumentos:
4.6.1.
Una función local puede acceder al valor de las variables locales a la función que la contiene.
En cambio, cuando una función local quiere modificar el valor de una variable local a la función que
la contiene, debe declararla previamente como no local con la sentencia .
Es algo similar a lo que ocurre con las variables globales.
La función local puede acceder a la variable , que es local a la función (para ello
no es necesario declararla previamente como no local).
Como la variable está declarada no local en , también puede modificarla.
De esta forma, ya no es necesario pasar el valor de como argumento a la función y
puede modificarla directamente.
4.7. Docstrings
Python implementa un mecanismo muy sencillo y elegante para documentar partes del código ba‐
sado en cadenas llamadas docstrings (cadenas de documentación).
En funciones, únicamente tenemos que insertar una cadena en la primera línea del cuerpo:
Las reglas de estilo dictan que esa cadena debe escribirse con triples comillas.
Para consultar la documentación se usa la función pasándole como argumento la función a
consultar:
También se puede documentar un script añadiendo un docstring al principio del mismo (en la primera
línea):
Ejercicios
Ejercicios
1. Considérese la siguiente fórmula (debida a Herón de Alejandrı́a), que expresa el valor de la super‐
ficie S de un triángulo cualquiera en función de sus lados, a, b y c:
! " #" #" #
a+b+c a+b+c a+b+c a+b+c
S= −a −b −c
2 2 2 2
Escribir una función que obtenga el valor S a partir de a, b y c, evitando el cálculo repetido del
semiperı́metro, sp = a+b+c
2 , y almacenando el resultado finalmente en la variable S.
2. Escribir tres funciones que impriman las siguientes salidas en función de la cantidad de líneas que
se desean ( es un espacio en blanco):
y escriba ese polinomio. Y, en segundo, lea el valor de x y escriba qué valor toma el polinomio
para esa x.
Para facilitar la salida, se supondrá que los coeficientes y x son enteros. Por ejemplo, si los coefi‐
cientes y x son 1, 2, 3 y 2, respectivamente, la salida puede ser:
y entonces, ese Domingo es el 22 de marzo + + días, que podrı́a caer en abril. Escriba un
programa que realice estos cálculos, produciendo una entrada y salida claras.
$%
8. Escribir una función para hallar nk , donde n y k son datos enteros positivos,
n!
a. mediante la fórmula (n−k)!k!
n(n−1)···(k+1)
b. mediante la fórmula (n−k)!
Bibliografía
Pareja Flores, Cristóbal, Manuel Ojeda Aciego, Ángel Andeyro Quesada, and Carlos Rossi Jiménez.
1997. Desarrollo de Algoritmos Y Técnicas de Programación En Pascal. Madrid: Ra‐Ma.