Closures
Closures
Los closures en Python son funciones anidadas capaces de acceder a variables libres. Es importante destacar que las funciones closure son funciones que son devueltas por la función que las contiene. También es importante destacar que las variables libres son aquellas definidas en el módulo y por lo tanto son globales para todas las funciones dentro del módulo. Debido a que las variables libres no pertenece al ámbito local es necesario usar la palabra reservada NONLOCAL que las funciones closures funcionen con variables inmutables. Las funciones closures ayudan a evitar el uso valores globales y ofrece una especie de mecanismo de ocultación de datos. Es común su uso en los decoradores que se verán mas adelante. Veamos el siguiente ejemplo:
import os
os.system('cls')
def funcion_externa(sMensaje):
sMensaje='Saludos'
def funcion_closure():
print(sMensaje)
return funcion_closure
mi_impresion = funcion_externa('Hola')
mi_impresion()
mi_impresion()
mi_impresion()
Resultado:
Saludos
Saludos
Saludos
Como podemos ver de código anterior hay dos funciones, una función contenedora que crea y devuelve a otra función. Esta otra función se conoce como función anidada y es la función closure. la función externa devuelve la función closure y es asignada a la variable mi_impresion, momento en el cual termina su ejecución. Sin embargo la función funcion_cosure aun tiene acceso a la variable sMensaje.
Veamos otro ejemplo con una aplicación práctica:
import os
os.system('cls')
def saludo_bienvenida(sNombreUsuario):
sMensaje = 'Bienvenido estimado ' + sNombreUsuario
def saludo():
print(sMensaje)
return saludo
ejecutar_saludo = saludo_bienvenida('César Gamboa')
ejecutar_saludo()
Resultado:
Bienvenido estimado César Gamboa
Como podemos ver el código anterior tiene una función llamada saludo_bienvenida que esta anidada dentro de otra función llamada saludo. Dicha función anidada muestra por pantalla una variable que pertenece al ámbito de la función que la contiene y ademas esta misma función anidada es devuelta por su sentencia return. Cabe mencionar que en el ámbito de la función contenedora (saludo_bienvenida) se antepone la cadena 'Bienvenido estimado ' a la variable pasada por el parámetro sNombreUsuario.
Al ejecutar el cuerpo del código la función contenedora es asignada a una variable llamada ejecutar_saludo con el parámetro, lo cual la convierte en dicha función, además recibiendo el argumento 'César Gamboa'. Al ejecutar la función invocándola en la instrucción ejecutar_saludo() podemos ver que muetra por pantalla el mensaje 'Bienvenido estimado César Gamboa'.
Tras el análisis del código anterior y ver sus características y comportamiento podemos concluir que la función saludo es una función closure, ya que cumple con los tres requisitos para serlo: es una función anidada, utiliza una variable del ámbito de la función que la contiene recordando su contenido incluso luego de la terminación del ciclo de vida de la función que la contiene y la propia función saludo es devuelta tras la instrucción return.
En resumen una función closure o cierre es una función anidada que recuerda los valores en los ámbitos a los que pertenece.
Veamos otro ejemplo para aclarar un poco mas el panorama, ya que este tema suele ser bastante confuso. En este caso vamos paso a paso partiendo simplemente de una función anidada.
import os
os.system('cls')
def transmision(msg):
'Función contenedora'
def objeto_transmisor():
'Función anidada'
print(msg)
objeto_transmisor()
print(transmision('Mensaje de prueba'))
Resultado:
Mensaje de prueba
Mensaje de prueba
None
Como podemos comprobar la función anidada objeto_transmisor() puede acceder a la variable llamada msg perteneciente al ámbito superior. Sin embargo para poder modificar dicha variable dentro de la función anidada habría que hacer uso de la palara reservada NONLOCAL. Veamos el siguiente ejemplo:
Sin el uso de NONLOCAL:
import os
os.system('cls')
def imprime_numero(iNumero):
def modifica_impresion():
'Aquí está comentado el uso de la palabra reservada NONLOCAL'
#nonlocal iNumero
iNumero=3
print(iNumero)
modifica_impresion()
print(iNumero)
imprime_numero(9)
Resultado:
3
9
Con el uso de NONLOCAL:
import os
os.system('cls')
def imprime_numero(iNumero):
def modifica_impresion():
'Aquí se usa la palabra reservada NONLOCAL'
nonlocal iNumero
iNumero=3
print(iNumero)
modifica_impresion()
print(iNumero)
imprime_numero(9)
Resultado:
3
3
Como podemos comprobar con el uso de la palabra reservada NONLOCAL se ha logrado modificar permanentemente el contenido de la variable iNumero dentro de la función modifica_impresion. Sin embargo es posible hacer que la función modifica_impresion sea retornada tras su sentencia RETURN, y la función que la contiene puede ser asignada a una variable llamada ejecucion, pasando un entero como argumento. Una vez se ejecute el objeto ejecucion(), este devolverá como resultado el valor pasado como argumento incluso luego de haber finalizado el ciclo de vida de la función contenedora y su función anidada. Veamos el ejemplo en la práctica:
import os
os.system('cls')
def imprime_numero(iNumero):
'Función contenedora'
def modifica_impresion():
'Función anidada'
print(iNumero)
return modifica_impresion
ejecucion=imprime_numero(49)
ejecucion()
Resultado:
49
Como podemos comprobar se ha hecho uso de una función closesure logrando así evitar el uso de variables globales consiguiendo cierta ocultación de datos.
Veamos el siguiente ejemplo:
import os
os.system('cls')
def cantidad(iCantidad: int):
def cadena(sCadena: str):
return sCadena*iCantidad
return cadena
Imprimir2 = cantidad(2)
Imprimir5 = cantidad(5)
print(Imprimir2('Python'))
print(Imprimir5('Lenguaje'))
Resultado:
PythonPython
LenguajeLenguajeLenguajeLenguajeLenguaje
Como podemos comprobar Python recuerda en los objetos imprimir2 e imprimir5 los valores enteros que va a usar al momento de devolver la multiplicación de las cadenas por dicho entero en la función closure llamada cadena. Otro punto destacable de código anterior es que Python ofrece la posibilidad de definir el tipo de variable que va a recibir como argumento en la definición de la función, escribiendo luego del nombre de la variable dos puntos (:) y luego el tipo de valor esperado en el parámetro.
Comentarios
Publicar un comentario