AnteriorPosterior

10 - Funciones

Por: Nacho Cabanes
Actualizado: 15-08-2020 16:12
Tiempo de lectura estimado: 18 min.

 

Versión en video (10:48 min):

Fund.Prog con Python 2020

10 - Funciones

En esta entrega vamos a hablar de lo que es una función y de cómo podemos crearlas y utilizarlas desde Python.

La palabra función, con pequeños matices que veremos más adelante, es casi casi un sinónimo de procedimiento o de subrutina.

La idea básica es que con frecuencia vamos a encontrarnos fragmentos repetitivos en un programa. En esos casos, será preferible sacarlo a un bloque distinto, un bloque con nombre, para poderlo reutilizar en vez de escribirlo muchas veces. Vamos a ver un ejemplo: imagina, por ejemplo, que yo quiero escribir varios textos subrayados.

Yo podría poner, por ejemplo, un primer texto que fuera "Hola, Como estas?".

print("Hola, como estas?")

Recuerda que los acentos en más de un entorno serán un poco peligrosos... y luego quiero poner debajo una serie de guiones para subrayarlo.

Pues podría decir "quiero que haya un contador que vaya, por ejemplo, en el rango desde 0 hasta 15". Y lo que quiero hacer es escribir varios guiones.

for i in range(0, 15):
    print("-")

Primer matiz: Esto escribiría varios guiones, cada uno en la línea; yo quiero todos ellos en la misma línea. La forma de hacer eso será añadirle: coma "end", "igual" comillas, comillas.

print("Hola", end="")

Es decir, quiero que mi final de línea sea nada. Eso hará que escriba y no avance a la siguiente línea.

Después de escribir esos 15 guiones, ya sí que querré bajar a la línea siguiente, con lo cual podría terminar con un "print" que realmente no escriba nada:

for i in range(0,15):
    print("-", end="")
print()

Vamos a comprobar que funciona: eso debería escribir "Hola, cómo estás?" y debajo 15 guiones.

print("Hola, como estas?")
for i in range(0,15):
    print("-", end="")
print()
Hola, como estas?
---------------

Ahora yo quiero aplicar esa misma idea para otro texto, pues podría copiar y pegar, pero haciéndolo con el texto "Hola, que tal".

print("Hola, como estas?")
for i in range(0,15):
    print("-", end="")
print()

print("Hola, que tal?")
for i in range(0,15):
    print("-", end="")
print()

Pero empieza a haber partes del programa que son repetitivas, además de ser más o menos complicadas.

Si quiero un tercer texto, vuelvo a repetir la idea, vuelvo a copiar y pegar aquí abajo y ahora pongo, por ejemplo, un texto que sea "hasta otro día" y cada vez va habiendo más fragmentos repetitivos.

print("Hola, como estas?")
for i in range(0,15):
    print("-", end="")
print()

print("Hola, que tal?")
for i in range(0,15):
    print("-", end="")
print()

print("Hasta otro día")
for i in range(0,15):
    print("-", end="")
print()

Vamos primero a comprobar que funciona...

Hola, como estas?
---------------
Hola, que tal?
---------------
Hasta otro día
---------------

Tenemos "Hola, cómo estás?", "Hola, qué tal?", "Hasta otro día"... Todo ello subrayado, pero imaginemos que ahora quiero hacer cambios. Digo "es que el cómo estás se queda un poco corto".

Voy a subir todo, en vez de 15 guiones, a 17... pues me tocaría cambiarlo tres veces, recorrer todos los fragmentos uno por uno para ir cambiando, con el agravante de que la primera ya me ha salido fuera de la pantalla y es posible que me despiste y no la cambie.

print("Hola, como estas?")
for i in range(0,15):
    print("-", end="")
print()

print("Hola, que tal?")
for i in range(0,17):
    print("-", end="")
print()

print("Hasta otro día")
for i in range(0,17):
    print("-", end="")
print()

Cuanto más código repetitivo haya en nuestros programas, más propensos serán a errores de ese estilo, a despistes de no corregir cosas cuando haya que hacer cambios en varios sitios.

Vuelvo a lanzar... Y me doy cuenta de que el primero sigue saliendo demasiado corto y me toca buscar por aquí y analizar... cierto... que había aquí otro que era un 17.

Conclusión: es deseable no repetir código.

¿Qué haremos para no repetir código? Decir "pues todo esto de aquí va a ser un bloque que voy a reutilizar".

Esos bloques que voy a reutilizar son lo que llamaremos funciones, o procedimientos o subrutinas.

El nombre más habitual en funciones, pero insisto: entre función y procedimiento habrá un pequeño detalle que matizaremos después.

¿Qué hago para definir una función?

Pues copio el fragmento repetivo, vuelvo al principio y digo "voy a definir algo". Ese "definir", la palabra, depende de cada lenguaje concreto.

En el caso de Python, es con la palabra "def". Voy a definir algo que se va a llamar, por ejemplo, subrayar. Y a continuación pongo paréntesis vacíos.

def subrayar()

Ya veremos más adelante para qué son esos paréntesis.

Y, al igual que hacíamos con los "if", con los "for", etc., pongo "dos puntos" para decirle "y aquí te voy a dar los detalles". Y entonces pego esos detalles de antes:

def subrayar():

Esos detalles serían algo parecido a esto.

def subrayar():
    for i in range(0,17):
        print("-", end="")
    print()

Es decir, subrayar lo que va a hacer es: Diecisiete veces escribir guiones y luego bajar de línea.

¿Qué haría ahora? Pues cambiaría cada bloque por un "quiero subrayar":

def subrayar():
    for i in range(0,17):
        print("-", end="")
    print()

print("Hola, cómo estás")
subrayar()

print("Hola, qué tal?")
subrayar()

print("Hasta otro día")
subrayar()

Por una parte, el programa ha quedado más compacto que antes, ocupa menos. Cuanto menos tecleamos, menos posibilidad de errores, pero lo menos importante, con diferencia es el teclear menos. Es el que ahora, en un vistazo nada más, se entiende lo que estoy haciendo. Estoy escribiendo, estoy subrayando, escribiendo otro texto y subrayando, otro texto y subrayando.....

He ganado en legibilidad. Pero además, he ganado en mantenibilidad, en facilidad de hacer cambios, porque yo ahora digo "no, 17 es demasiado, quiero que sean 16". Lo cambio sólo en un sitio, y todos los sitios que se apoyan en "subrayar", todo lo que llamaremos las "llamadas a esta función" que he creado aquí arriba, automáticamente van a aprovechar esos cambios:

def subrayar():
    for i in range(0,16):
        print("-", end="")
    print()

print("Hola, cómo estás")
subrayar()

print("Hola, qué tal?")
subrayar()

print("Hasta otro día")
subrayar()

Vamos a probarlo, lanzo...

Hola, cómo estás
----------------
Hola, qué tal?
----------------
Hasta otro día
----------------

Y ahora todos ellos tienen 16 automáticamente.

Esto, por supuesto, se puede mejorar, la primera mejora es indicar lo que llamaremos "parámetros". Los parámetros son detalles adicionales para una función.

Por ejemplo, yo podría decir que a la hora de subrayar que indicarle cuántos espacios quiero. Entonces simplemente pondría aquí, "quiero subrayar y te voy a indicar cuántos espacios":

def subrayar(espacios):

¿Qué cambio habría? Pues que en el "range", ya no llegaría siempre hasta 16, sino hasta los espacios que se me indiquen en la llamada, de forma que en cada una de estas llamadas a la función yo indicaría el detalle exacto de cuántos espacios quiero subrayar. Por ejemplo, podría decir que en la primera quiero subrayar con 16 guiones, en la segunda con 14 guiones... y en la tercera con 15 guiones.

def subrayar(espacios):
    for i in range(0,espacios):
        print("-", end="")
    print()

print("Hola, cómo estás")
subrayar(16)

print("Hola, qué tal?")
subrayar(14)

print("Hasta otro día")
subrayar(15)

Esta es una función que tiene parámetros.

Ese paréntesis que hemos puesto antes vacío era para indicar que la función no tenía parámetros, no recibía detalles adicionales. En cambio, esta segunda versión de la función sí que recibe detalles adicionales y los utiliza aquí dentro, de modo que ahora tendremos tres secuencias de guiones, cada una con tamaño distinta de la anterior.

Vamos a comprobarlo.

Hola, cómo estás
----------------
Hola, qué tal?
--------------
Hasta otro día
---------------

Verás que la primera tiene 16, la segunda tiene 14 y la tercera, que en realidad bastaría con 14, por variar, le hemos puesto 15.

Este es un uso mucho mucho más habitual de las funciones, el además poder hacer pequeñas variaciones en su comportamiento, indicando parámetros, indicando detalles adicionales.

El tercer detalle que me interesa que conozcas de las funciones es que además, realmente, esto que estamos haciendo, en terminología otros lenguajes, realmente no es una "función". Se suele usar la palabra función para algo que devuelve un resultado. Por ejemplo, la función raíz cuadrada. Tú le indicas un detalle como el número 4 y te devuelve un resultado: la raíz cuadrada de 4 es 2. Aquí no estamos devolviéndo nada, estamos dando una serie de pasos, pero no obtenemos ningún resultado, ni numérico, ni cadena, ni arrays, ni nada por el estilo. Este tipo de funciones, que no devuelven resultado en la nomenclatura de otros lenguajes de población se llama un "procedimiento" o una "subrutina".

Se suele reservar la palabra "funciones" para cuando devuelven un valor. Vamos a ver una función que devuelve un valor...

Vamos a hacer una función, que, a partir de dos números, devuelve otro número distinto, por ejemplo, podría ser su suma. Pero para que tenga algo más de gracia, vamos a hacer algo que realmente haga algún cálculo interno o alguna comprobación. Podría ser, por ejemplo, calcular el máximo de los números.

Pues podría decir "yo quiero definir una función que voy a llamar máximo y ese máximo va a recibir dos detalles: un primer número y un segundo número".

def maximo(n1, n2):

¿Y qué es lo que va a hacer? Pues va a comprobar primero cuál es el mayor de los dos: si n1 es mayor que n2, el resultado será n1. Pues ese resultado, lo indicamos con la palabra return: "Quiero que me devuelvas como resultado n1"

def maximo(n1, n2):
  if n1 > n2:
    return n1

Y si no fuera así, si n1 no es mayor que n2, es decir, si n2 es mayor o incluso si son iguales, devolveremos el valor de n2, con lo cual pondremos "else :", en ese caso devuélveme el valor de n2.

def maximo(n1, n2):
  if n1 > n2:
    return n1
  else:
    return n2

¿Qué haremos para usar esa función? Pues calcular el máximo de dos números... por ejemplo, yo podría poner print. "Quiero que me escribas el máximo de el número 5, por ejemplo, y el número 12". Lo ideal, como siempre, es avisar antes al usuario, con lo cual pondría "print el máximo de 5 y 12,"

def maximo(n1, n2):
  if n1 > n2:
    return n1
  else:
    return n2

print("El máximo de 5 y 12")
print( maximo(5, 12) )

Ya sabes, cuidado con los acentos... Si usas algún entorno que te regaña por usar acentos, de momento limítate a quitarlos. Más adelante veremos como cambiar la codificación. Pero esa sería la idea.

Vamos a hacer otra llamada distinta para que veas que lo podemos utilizar, al igual que hicimos en el ejemplo anterior. Ahora voy a calcular el máximo, por ejemplo, de 25 y 12, para que sean números parecidos, pero el resultado sea distinto, que el primer número de los dos sea el mayor y compruebe que se comporta bien tanto si el mayor es el segundo, como es el mayor es el primero.

def maximo(n1, n2):
  if n1 > n2:
    return n1
  else:
    return n2

print("El máximo de 5 y 12")
print( maximo(5, 12) )

print("El máximo de 25 y 12")
print( maximo(25, 12) )

Lanzamos ese programa...

El máximo de 5 y 12
12
El máximo de 25 y 12
25

Primero me dice que el máximo de 5 y 12 el 12 y luego que el máximo de 25 y 12 el 25.

Pues esta es una función propiamente dicha, esta es una función que realmente sí que devuelve resultados a partir de ciertas operaciones, ciertas comprobaciones, ciertas... lo que sea.

Ejercicio propuesto 10.1. Crea una función que reciba 3 números y devuelva su suma.

Ejercicio propuesto 10.2. Crea una función que reciba una cadena de texto y una letra, y devuelva la cantidad de veces que la letra aparece dentro de la cadena.

Ejercicio propuesto 10.3. Crea un procedimiento que escriba una línea formada por 2 letras, repetidas varias veces. Por ejemplo, para "-", "=" y 3, escribiría "-=-=-=".

36 visitas desde el 15-08-2020

AnteriorPosterior