Amigos, adjunto link donde se explica demasiado bien una función decoradora, saludos.
https://www.youtube.com/watch?v=DQXm6bIZgvk
Programación Orientada a Objetos
Lo que aprenderás sobre programación orientada a objetos y algoritmos con Python
Programación Orientada a Objetos
Tipos de datos abstractos y clases, Instancias
Decomposición
Abstracción
Funciones: base de los decoradores
Setters, getters y decorador property
Encapsulación, getters and setters
Herencia
Polimorfismo
Complejidad algorítmica
Introducción a la complejidad algorítmica
Conteo abstracto de operación
Notación asintótica
Clases de complejidad algorítmica
Algoritmos de búsqueda y ordenación
Búsqueda lineal
Búsqueda binaria
Ordenamiento de burbuja
Ordenamiento por inserción
Ordenamiento por mezcla
Ambientes virtuales
Ambientes virtuales
Graficado
¿Por qué graficar?
Graficado simple
Algoritmos de optimización
Introducción a la optimización
El problema del morral
Conclusiones
El concepto de decorador en Python es algo que podríamos ubicar en un nivel “intermedio” en el manejo del lenguaje, por lo que es buena idea que tengas una base sólida, sobre todo en cuanto a funciones al momento de profundizar e implementarlas.
Los decoradores son una forma sencilla de llamar funciones de orden mayor, es decir, funciones que toman otra función como parámetro y/o retornan otra función como resultado. De esta forma un decorador añade capacidades a una función sin modificarla.
Un ejemplo de esto son las llantas de un automóvil. Si les colocas cadenas para la nieve, el automóvil aún puede andar y además extiende su funcionalidad para conducirse en otros terrenos.
Antes de abordar el tema de decoradores haremos un pequeño repaso por las funciones, las cuales retornan un valor ante la entrada de un argumento.
Analicemos este sencillo ejemplo donde una función que multiplica un número se eleva a la tercera potencia:
def elevar_cubo(numero):
return numero * numero * numero
Si damos como argumento el número 3, entonces tendremos como salida el número 27 al ejecutar la función:
>>> elevar_cubo(3)
27
Otro concepto importante a tener en cuenta es que en Python las funciones son objetos de primera-clase, es decir, que pueden ser pasados y utilizados como argumentos al igual que cualquier otro objeto (strings, enteros, flotantes, listas, etc.).
Veamos un ejemplo donde definimos 3 diferentes funciones que utilizaremos de manera conjunta:
def presentarse(nombre):
return f"Me llamo {nombre}"
def estudiemos_juntos(nombre):
return f"¡Hey {nombre}, aprendamos Python!"
def consume_funciones(funcion_entrante):
return funcion_entrante("David")
Las primeras dos funciones son obvias en su resultado, donde nos mostrarán un mensaje con el valor de la variable nombre
. La tercera función puede ser más compleja de predecir, ya que toma otra función como entrada. Veamos que pasa cuando colocamos una función como atributo:
>>> consume_funciones(presentarse)
'Me llamo David'
>>> consume_funciones(estudiemos_juntos)
'¡Hey David, aprendamos Python!'
Pongamos atención en cómo la función consume_funciones()
se escribe con paréntesis para ser ejecutada, mientras que la función presentarse
y estudiemos_juntos
solo hace referencia a estas.
Al igual que los condicionales y bucles también puedes colocar funciones dentro de otra función.
Tómate un minuto para analizar el siguiente código e inferir cuál será el resultado de salida:
def funcion_mayor():
print("Esta es una función mayor y su mensaje de salida.")
def librerias():
print("Algunas librerías de Python son: Scikit-learn, NumPy y TensorFlow.")
def frameworks():
print("Algunos frameworks de Python son: Django, Dash y Flask.")
frameworks()
librerias()
Si llamamos a la función funcion_mayor
tendremos la siguiente salida:
>>> funcion_mayor()
Esta es una función mayor y su mensaje de salida.
Algunos frameworks de Python son: Django, Dash y Flask.
Algunas librerías de Python son: Scikit-learn, NumPy y TensorFlow.
Debemos considerar que las funciones anidadas dentro de funcion_mayor
no se ejecutan hasta que se llama a esta primera, siendo muestra del scope o alcance de las funciones. Si las llamamos obtendremos un error
En la siguiente lectura entraremos al concepto de decoradores, setters y getters, pues al entender mejor las funciones será más fácil asimilar su uso en la implementación del encapsulamiento.
Aportes 37
Preguntas 2
Amigos, adjunto link donde se explica demasiado bien una función decoradora, saludos.
https://www.youtube.com/watch?v=DQXm6bIZgvk
Aquí dejo mi aporte y resumen de la clase:
<h3>Funciones: base de los decoradores</h3>Antes de empezar a hablar de decoradores, recordemos que una función retorna un valor ante la entrada de un argumento:
def al_cuadrado(numero):
return numero ** 2
Esta función recibe el arguemnto numero
y a partir de eso retorna (return
) el argumento numero
elevado al cuadrado (numero ** 2
).
Ahora, probemos esta función. Si damos como parámetro el número 4, tendremos como salida el valor número 16 (es el valor que nos retorna):
>>> al_cuadrado(4)
16
Si no sabes o no te queda claro la diferencia entre argumentos y parámetros de las funciones, te invito a que vayas a este Colab (https://colab.research.google.com/drive/1VyOB8nRWRTscc7k_V-66NIlfKZZZ8AuW?usp=sharing) y que vayas hacia las sección Funciones y dentro vayas a la secciones Argumentos y Parámetros de las funciones y Los argumentos NO son lo mismo que los parámetros. Allí explico esta confusión qué suele ocurrir en programación.
Los decoradores son una forma sencilla de llamar funciones de orden mayor, qué básicamente son funciones que toman otra función como parámetro y/o retornan otra función como resultado. Entonces, un decorador le añade capacidades a una función sin tener que modificarla.
Un ejemplo son las llantas de un coche, a las cuáles les puede añadir cadenas para la nieve. No modificas el comportamiento de que aún pueda andar, porqué sí puede, y además extiendes su funcionalidad a otros terrenos.
<h3>Funciones como objetos de primera clase</h3>Cómo vimos en el curso anterior, las funciones son objetos de primera clase, lo que significa que puede ser pasados y usados como argumentos al igual que cualquier otro objeto(int
, float
, str
). Veamos un ejemplo dónde utilizamos 3 funciones en conjunto:
def presentarse(nombre):
return f'¡Hola! Me llamo {nombre}.'
def aprender(nombre):
return f'¡{nombre}, aprendamos Python!'
def usar_funciones(funcion):
return funcion("Ignacio") #establecemos el parámetro que tomarán las primeras 2 funciones
Las primeras 2 funciones nos retornan strings. Pero la última, se comportará diferente según la función que le pasemos como parámetro. Veamos cómo se puede usar:
>>> print(usar_funciones(presentarse))
¡Hola! Me llamo Ignacio.
>>> print(usar_funciones(aprender))
¡Ignacio, aprendamos Python!
Cómo ves, nos imprime los mensajes que retornaban las 2 primeras funciones con el nombre correspondiente. Fíjate que para referirnos como parámetros a las 2 primeras funciones no ponemos paréntesis, sino que las escribimos así presentarse
y aprender
. Además, automáticamente reciben como parámetro el nombre "Ignacio"
, qué es el argumento nombre
de las funciones.
Esto también lo vimos en el curso anterior, dónde podíamos meter funciones dentro de otras funciones al igual que las condicionales:
numero = 5
if numero > 1:
if numero % 2 == 0:
print("Este número es compuestoo.")
else:
print("Este número es primo.")
else:
print("Este número es igual o menor a 1."
>>> (ejecutamos)
Este número es primo
Ahora veamos cómo aplica este concepto para las funciones:
def funcion_padre(numero):
def doble():
resultado = numero * 2
print('El doble de {numero} es {resultado}.')
def al_cuadrado():
resultado = numero ** 2
print('{numero} al cuadrado es {resultado}.')
En esta función (funcion_padre()
), la cuál recibe el argumento numero
, dentro hay otras 2 funciones (doble
y al_cuadrado
), las cuales sirven para calcular el doble y/o el cuadrado del argumento recibido, respectivamente. Ahora llamaremos a funcion_padre()
para ver qué cosas podemos hacer:
>>> funcion_padre(5)
No se ejecuta nada, y eso es porque debemos agregar a funcion_padre()
que las 2 funciones anidadas deben ejecutarse.
def funcion_padre(numero):
def doble():
resultado = numero * 2
print(f'El doble de {numero} es {resultado}.')
def al_cuadrado():
resultado = numero ** 2
print(f'{numero} al cuadrado es {resultado}.')
doble() #se ejecuta doble()
al_cuadrado() #se ejecuta al_cuadrado()
>>> funcion_padre(5)
El doble de 5 es 10.
5 al cuadrado es 25.
Ahora sí, funcion_padre()
funciona, valga la redundancia. Cómo vemos, las funciones doble()
y al_cuadrado()
no se ejecutan hasta que primero se llama a funcion_padre()
. Esto sigue las reglas del scope o alcance. En este caso, no podemos a acceder a las funciones internas sin antes acceder a la función global que contiene dichas funciones internas.
def decorator_function(func_param):
def internal_function():
# additional actions that decorate
print("Let's to do a calculation")
func_param()
# additional actions that decorate
print('We have finished the calculation ')
return internal_function
@decorator_function
def suma():
print(15+20)
@decorator_function
def resta():
print(30-10)
suma()
resta()
Para el que le interese, si tenemos en cuenta que dentro de una función puedes definir tus propias funciones y a su vez puedes traer funciones como parámetros, ¿Qué pasa si definimos una función interna con el mismo nombre que un parámetro? Nota: No es bueno hacerlo, para nada.
¿Resultado? Es como si reasignara el valor de una variable porqué al momento de definir la función interna sobrescribe a la variable que traía la función externa.
Este fue el código que use:
def funcion1(funcion2):
print('Funcion Externa Nº1')
funcion2()
def funcion2():
print('Funcion Externa Nº1, Funcion Interna Nº2')
funcion2()
def funcion2():
print('Funcion Externa Nº2')
Y este el resultado:
>>>funcion1(funcion2)
Funcion Externa Nº1
Funcion Externa Nº2
Funcion Externa Nº1, Funcion Interna Nº2
¿Conclusión? Evita repetir nombres en tus variables, te ahorrarás muchos problemas
En el ejemplo de Funciones cómo objetos de primera-clase la función consume_funciones debe estar de la siguiente manera:
def consume_funciones(funcion_entrante):
return funcion_entrante("David")
En mi opinión, no es un tema de decoradores, en el tema menciona principalmente sobre las funciones y el papel importante que tienen y explica a groso modo que son los decoradores, que en el siguiente curso es donde se abordará ese tema.
😃
En el ejemplo de la función elevar_cubo, no entendía por qué se escribía numbernumbernumber (Porque ** es para potencias y * solo para multiplicar), además el parámetro en la función se llama numero, no number.
Creería que tendría que ser:
Podemos ver las funciones como una pequeña fábrica, donde le ingresamos un producto y esta fabrica nos devuelve algo fabricado como resultado.
Cuando pasamos una funcion como parametro a otra funcion lo que en realidad hacemos es, pasarle una “caja” chiquita como producto a otra caja más grande.
Y esta caja grande nos devolverá un producto procesado. O en nuestro caso un valor.
En el siguiente enlace puedes alcarar mas duduas referente al tema de decoradores en python
Un objeto de primera clase, es simplemente aquel que podemos pasar como argumento a una función(desde listas hasta objetos más complejos).
Una función decoradora se encarga de añadir funcionalidades extra a una función, y requiere de tres funciones para existir.
Función A, que es la que ejecuta nuestro código, función B, la cual decoraremos y pasamos como argumento a nuestro código y la función C que es la nueva función que retornamos.
def decorator_function(param_function):
def funcion_nueva():
print("esto es una operación matemática")
param_function()
return function_nueva
def suma(a, b):
return a + b
def resta(a, b):
return a - b
Y ahora se imprimirá un mensaje antes de iniciar cualquier función que pasemos como parametro.
Un decorador es el nombre de un patrón de diseño. Los decoradores alteran de manera dinámica la funcionalidad de una función, método o clase sin tener que hacer subclases o cambiar el código fuente de la clase decorada. En el sentido de Python un decorador es algo más, incluye el patrón de diseño, pero va más allá, Bruce Eckel los asimila a las macros de Lisp. Los decoradores y su utilización en nuestros programas nos ayudan a hacer nuestro código más limpio, a autodocumentarlo y, a diferencia otros lenguajes, no requieren que nos aprendamos otro lenguaje de programación distingo (cómo pasa con las anotaciones de Java por ejemplo).
def funcionMayor():
print('Esta es una función mayor y su mensaje de salida.')
def librerias():
print('Algunas librerías de Python son: Scikit-learn, NumPy y TensorFlow.')
def frameworks():
print('Algunos frameworks de Python son: Django, Dash y flask.')
frameworks() #Llama a la función frameworks para su impresión
librerias() #Llama a la función librerias para su impresión
funcionMayor() #Llama a la función 'FUNCIONMAYOR' para su impresión```
Ejemplo de decoradores:
Ejemplo de uso decoradores: Para ello necesitaremos funcion "A", que reciba como parametro otra funcion "B" para devolver otra funcion "C".
Ejemplo codigo:
def decorador(func): #A, #B
def nueva_funcion():
print("Ejecutando la funcion")
#Aqui es donde se agrega la logica que va a ser añadida a la funcion
func()
print("Se ejecuto la funcion")
return nueva_funcion #C
@decorador #Aqui es donde se le agrega la decoracion, la funcion que queramos
def saluda(): #C
print("Hola mundo")
saluda()
El profe david tiene una clase de otro curso donde explica, los decoradores aqui se las dejo por si quieren checar.
En este apartado vemos lo siguiente:
Una duda que me saltó es en qué casos podría utilizar funciones anidadas?
No sé si al decir “decoradores” se está refiriendo al patrón de diseño Decorator jaja, lo veré en la siguiente clase, pero la parte de una función que retorna a otra, si vienes de JavaScript, puedes verla como un callback pues básicamente eso es, tu le puedes mandar la referencia de una función a otra para que está la ejecute internamente a modo de callback 😄
De nuevo una lectura que debería ser una explicación en video…
Para profundizar en el tema de decoradores y funciones anidadas, les recomiendo el curso profesional de Python, el profesor Facundo explica de manera muy sencilla estos temas 😃
dejo un pequeño experimento con l que entendi como funciona el decorador.
def sumar(a,b):
return a+b
def raiz_cuadrada(valor):
return valor**(1/2)
def pitagoras(funcion,a,b):
return raiz_cuadrada(funcion(a**2,b**2))
print(pitagoras(sumar,2,3))
al correr esto desde la consola python, funciona bien. Pero al correrlo desde la terminar. el resultado es 1. Agradezco si alguien me da una luz del porque sucede esto.
estructura:
<code>
def funcion_decorador(funcion):
def funcion_interna():
pass
return funcion_interna
Los decoradores se ven de una manera muy clara en el curso de Python Avanzado.
Para entender decoradores se pueden revisar al menos estas clases de Platzi, sin embargo, en el módulo se ven varios ejemplos muy claros (estos están en otras clases del mismo módulo):
Scope: https://platzi.com/clases/2397-python-profesional/39526-scope-alcance-de-las-variables/
Closures: https://platzi.com/clases/2397-python-profesional/39527-closures/
Decoradores: https://platzi.com/clases/2397-python-profesional/39529-decoradores/
Espero les sea de utilidad compañeros y a nunca parar de aprender.
def funcion_mayor():
print("Esta es una función mayor y su mensaje de salida.")
def librerias():
print("Algunas librerías de Python son: Scikit-learn, NumPy y TensorFlow.")
def frameworks():
print("Algunos frameworks de Python son: Django, Dash y Flask.")
frameworks()
librerias()
El concepto de decorador en Python es algo que podríamos ubicar en un nivel “intermedio” en el manejo del lenguaje, por lo que es buena idea que tengas una base sólida, sobre todo en cuanto a funciones al momento de profundizar e implementarlas.
funcion mayor puede tener funciones dentro que se ejecutaran cuando se llama al mayor porque se encuentra solamente dentro de su scope.
El Scope es el alcance de la función, hasta donde tiene acceso la función y dependiendo de donde se encuentre su nivel varia el llamado de la misma. El Scope es diferente dependiendo el lenguaje de programación aun tienen una similitud.
a(b) → c
a
, b
, c
son funciones.
a
recibe a b
como parámetro y retorna c
Dejo un ejemplo de decoradores, espero le sirva a la comunidad
<def decorador(func2): #definimos el decorador con la función argumento func2
def nueva_funcion(self, presentacion): #definimos la nueva función con los parametros que llevara la funcion func2
print("El profesor comenta:") #codigo del decorador
func2(self, presentacion) #Agregamos los parametros con los que trabaja
return nueva_funcion #regresa la nueva funcion
class profesor(object): #se crea la clase heraedando object
def __init__(self, nombre): #Constructor con el atributo nombre
self.nombre = nombre
@decorador #se coloca el decorador antes del metodo
def ensena(self, presentacion): #Metodo enseñar del objeto profesor
self.presentacion = presentacion
print(presentacion) #imprime el mensaje del objeto
print("Hoy aprenderemos a programar en Python")
utonio = profesor("Utonio") #instanciamos
utonio.ensena("Bienvenido a tu curso de programación") # al llamar al metodo ensena añadira el decorador
#es decir en el decorador se debe incluir la instanciación self y el argumento presentación
# para nueva función y func2>
Función que se le pasa por parametro una función y devuelve otra función diferente
decorator_function: funcion decoradora
externa
def funcion_decoradora(funcion_por_parametro):
def funcion_interna():
print('Aqui hacemos cosas')
print('Acciones randoom')
print('Tambien aqui usamos nuestra funcion externa')
funcion_por_parametro(1, 2)
print('Terminado')
#Ten cuidado con la identacion
return funcion_interna
#Para llamarla se puede hacer de dos formas
#-----primera------
def suma(num1, num2)
return print(num1 + num2)
p = funcion_decoradora(suma)
p()
#-----segunda-------
#El arroba le dice que suma sera el parametro de la funcion decoradora y cada vez que llamemos a suma se comportara como si escribieramos la primera opción
@funcion_decoradora
def suma(num1, num2)
return print(num1 + num2)
suma()
Decoradores
Funciones que toman otra función cómo parámetro y/o retornan otra función como resultado.
Funciones anidadas
Recursividad. Funciones dentro de funciones.
Los argumentos son las variables con las que trabajará la función, mientras que los parámetros son los valores que le asignaremos a esas variables.
defines las funciones pero no las llamas, dentro de su scope claro
Alguien sabe por que solo imprime la primera si llamo a la funcion mayor, cuando llamo la funcion librerias o frameworks me dice que no estan definidas...
def funcion_mayor():
print("Esta es una funcion mayor")
def librerias():
print("Algunas librerias de python son... Tkinter, TensorFlow")
def frameworks():
print("Algunos framework de python son... Django dash y flask")
funcion_mayor()```
print('Funciones básicas: ')
def presentar(nombre):
print(f'Me llamo {nombre}')
presentar('David')
def estudiemos_juntos(nombre):
print(f'Hey {nombre}, aprendamos Python!')
estudiemos_juntos('Edgar')
#TOMA UNA FUNCIÓN COMO ENTRADA
def consume_funciones(funcion_entrante):
return funcion_entrante('Luis') #Este nombre se asignara a los dos llamados siguientes
print('\nFunción de funciones: ')
consume_funciones(presentar) #Me llamo Luis
consume_funciones(estudiemos_juntos) #Hey Luis aprendamos Python!```
Este código no corre, no hay ningún vinculo entre funcion_entrante(“David”) y la función presentarse() o estudiemos_juntos()
def presentarse(nombre):
return f"Me llamo {nombre}"
def estudiemos_juntos(nombre):
return f"¡Hey {nombre}, aprendamos Python!"
def consume_funciones(funcion_entrante):
return funcion_entrante("David")
consume_funciones(presentarse)
consume_funciones(estudiemos_juntos)```
No se si soy solo yo pero siento que el articulo no le da la verdadera importancia a los decoradores, no se muestra un ejemplo de verdad de como es que se modifica el comportamiento de una función con un decorador, dejo yo este pequeño codigo
def my_decorator(fun):
def wrapper(*args, **kwargs):
print("antes")
result = fun(*args, **kwargs)
return 1 + result
return wrapper
@my_decorator
def suma(a, b):
return a + b
if __name__ == '__main__':
print(suma(1,2))
Tal vez no es mucho pero aquí se ve como si se modifica el comportamiento por default de una función, es decir el resultado por si mismo de la función debería ser 4 pero después de decorar la función el resultado es 4, esto por que la función intermedia wrapper toma el resultado original y le suma un 1 mas.
Espero esto ayude a comprender un poco mejor el verdadero poder de los decoradores, además de que no solo aplica a funciones si no también a clases y también podemos pasar parámetros a los decoradores, aqui dejo un articulo que muestra un poco esto https://medium.com/@LuisMBaezCo/decoradores-con-clases-y-funciones-en-python-2fafb22dba43
toca estudiar un poco mas este tema
En Java recuerdo que creabamos un archivo aparte con todas las funciones uqe utilizaría nuestro programa y nadamas las ibamos invocando cuando las utilizabamos., tambien recuerdoque podíamos escribirle que significa cada parametro como una ayuda al usuario. Espero que más adelante veamos eso. 😄
¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.