92 - Funciones de orden superior

Python es un lenguaje multiparadigma: permite programación estructurada, orientado a objetos y también introduce características existentes en los lenguajes funcionales que nos dejan crear un código más claro y expresivo.

Una de las características del paradigma de la programación funcional son las funciones de orden superior.

Las funciones de orden superior son funciones que pueden recibir como parámetros otras funciones y/o devolverlas como resultados.

Veremos una serie de ejemplos muy sencillos para ver como Python implementa el concepto de funciones de orden superior y a medida que avancemos en el curso podremos ver las ventajas de este paradigma.

Problema 1

Definir una función de orden superior llamada operar. Llegan como parámetro dos enteros y una función. En el bloque de la función llamar a la función que llega como parámetro y enviar los dos primeros parámetros.
La función retorna un entero.

Programa: ejercicio320.py

Ver video

def operar(v1,v2,fn):
    return fn(v1,v2)

def sumar(x1,x2):
    return x1+x2

def restar(x1,x2):
    return x1-x2

def multiplicar(x1,x2):
    return x1*x2

def dividir(x1,x2):
    return x1/x2

resu1=operar(10,3,sumar)
print(resu1)

resu2=operar(10,3,restar)
print(resu2)

print(operar(30,10,multiplicar))

print(operar(10,2,dividir))

Tenemos definidas 5 funciones en este problema. La única función de orden superior es la llamada "operar":

def operar(v1,v2,fn):
    return fn(v1,v2)

El tercer parámetro de esta función se llama "fn" y es de tipo función.

El algoritmo de la función operar consiste en llamar a la función fn y pasar los dos valores que espera dicha función:

    return fn(v1,v2)

Como la función operar retorna un valor debemos indicar con la palabra clave return que devuelva el dato que a su vez retorna la función "fn".

Las cuatro funciones que calculan la suma, resta, multiplicación y división no tienen nada nuevo a lo visto en conceptos anteriores:

def sumar(x1,x2):
    return x1+x2

def restar(x1,x2):
    return x1-x2

def multiplicar(x1,x2):
    return x1*x2

def dividir(x1,x2):
    return x1/x2

En el bloque principal de nuestro programa llamamos a la función operar y le pasamos tres datos, dos enteros y uno con la referencia de una función:

resu1=operar(10,3,sumar)
print(resu1)

Como vemos para pasar la referencia de una función solo indicamos su nombre.

La función operar retorna un entero y lo almacenamos en la variable resu1 que mostramos luego por pantalla:

print(resu1)

Es importante imaginar el funcionamiento de la función operar que recibe tres datos y utiliza uno de ellos para llamar a otra función que retorna un valor y que luego este valor lo retorna operar y llega finalmente a la variable "resu1".

Llamamos a operar y le pasamos la referencia a la función restar:

resu2=operar(10,3,restar)
print(resu2)

De forma similar llamamos a operar y le pasamos las referencias a las otras funciones:

print(operar(30,10,multiplicar))

print(operar(10,2,dividir))

Tener en cuenta que para sumar dos valores es mejor llamar directamente a la función sumar y pasar los dos valores, pero el objetivo de este problema es conocer la sintaxis de las funciones de orden superior presentando el problema más sencillo posible.

Las funciones de orden superior se pueden utilizar perfectamente en los métodos de una clase.

Problema 2

Declarar una clase que almacene el nombre y la edad de una persona. Definir un método que retorne True o False según si la persona es mayor de edad o no. Este método debe recibir como parámetro una función que al llamarla pasando la edad de la persona retornará si es mayor o no de edad.
Tener en cuenta que una persona es mayor de edad en Estados Unidos si tiene 21 o más años y en Argentina si tiene 18 o más años.

Programa: ejercicio321.py

Ver video

class Persona:
    def __init__(self,nombre,edad):
        self.nombre=nombre
        self.edad=edad

    def es_mayor(self,fn):
        return fn(self.edad)

def mayor_estadosunidos(edad):
    if edad>=21:
        return True
    else:
        return False

def mayor_argentina(edad):
    if edad>=18:
        return True
    else:
        return False


persona1=Persona("juan", 18)
if persona1.es_mayor(mayor_argentina):
    print(f"{persona1.nombre} es mayor si vive en Argentina")
else:
    print(f"{persona1.nombre} no es mayor si vive en Argentina")
if persona1.es_mayor(mayor_estadosunidos):
    print(f"{persona1.nombre} es mayor si vive en Estados Unidos")
else:
    print(f"{persona1.nombre} no es mayor si vive en Estados Unidos")

Declaramos la clase Persona con dos propiedades llamadas nombre y edad:

class Persona:
    def __init__(self,nombre,edad):
        self.nombre=nombre
        self.edad=edad

La clase persona por si misma no guarda la nacionalidad de la persona, en cambio cuando se pregunta si es mayor de edad se le pasa como referencia una función que al pasar la edad nos retorna true o false:

    def es_mayor(self,fn):
        return fn(self.edad)

Tenemos dos funciones que al pasar una edad nos retornan si es mayor de edad o no:

def mayor_estadosunidos(edad):
    if edad>=21:
        return True
    else:
        return False

def mayor_argentina(edad):
    if edad>=18:
        return True
    else:
        return False

En el bloque principal del programa creamos un objeto de la clase persona:

persona1=Persona("juan", 18)

Llamamos al método es_mayor del objeto persona1 y le pasamos la referencia de la función "mayor_argentina":

if persona1.es_mayor(mayor_argentina):
    print(f"{persona1.nombre} es mayor si vive en Argentina")
else:
    print(f"{persona1.nombre} no es mayor si vive en Argentina")

Ahora llamamos al método es_mayor pero pasando la referencia de la función "mayor_estadosunidos":

if persona1.es_mayor(mayor_estadosunidos):
    print(f"{persona1.nombre} es mayor si vive en Estados Unidos")
else:
    print(f"{persona1.nombre} no es mayor si vive en Estados Unidos")

Como podemos comprobar el concepto de funciones de orden superior es aplicable a los métodos de una clase.