Python Closures: ¿Cómo usarlo y por qué?

En este tutorial, aprenderá sobre el cierre de Python, cómo definir un cierre y las razones por las que debería usarlo.

Variable no local en una función anidada

Antes de entrar en lo que es un cierre, primero tenemos que entender qué es una función anidada y una variable no local.

Una función definida dentro de otra función se llama función anidada. Las funciones anidadas pueden acceder a variables del ámbito adjunto.

En Python, estas variables no locales son de solo lectura por defecto y debemos declararlas explícitamente como no locales (usando una palabra clave no local) para poder modificarlas.

A continuación se muestra un ejemplo de una función anidada que accede a una variable no local.

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) printer() # We execute the function # Output: Hello print_msg("Hello")

Salida

 Hola

Podemos ver que la printer()función anidada pudo acceder a la variable msg no local de la función adjunta.

Definición de una función de cierre

En el ejemplo anterior, ¿qué pasaría si la última línea de la función print_msg()devolviera la printer()función en lugar de llamarla? Esto significa que la función se definió de la siguiente manera:

 def print_msg(msg): # This is the outer enclosing function def printer(): # This is the nested function print(msg) return printer # returns the nested function # Now let's try calling this function. # Output: Hello another = print_msg("Hello") another()

Salida

 Hola

Eso es inusual.

La print_msg()función se llamó con la cadena "Hello"y la función devuelta se enlazó con el nombre de otro. Al llamar another(), el mensaje aún se recordaba aunque ya habíamos terminado de ejecutar la print_msg()función.

Esta técnica mediante la cual algunos datos ( "Helloen este caso) se adjuntan al código se llama cierre en Python .

Este valor en el ámbito adjunto se recuerda incluso cuando la variable sale del ámbito o la función en sí se elimina del espacio de nombres actual.

Intente ejecutar lo siguiente en el shell de Python para ver el resultado.

 >>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined

Aquí, la función devuelta todavía funciona incluso cuando se eliminó la función original.

¿Cuándo tenemos cierres?

Como se ve en el ejemplo anterior, tenemos un cierre en Python cuando una función anidada hace referencia a un valor en su alcance adjunto.

Los criterios que deben cumplirse para crear un cierre en Python se resumen en los siguientes puntos.

  • Debemos tener una función anidada (función dentro de una función).
  • La función anidada debe hacer referencia a un valor definido en la función adjunta.
  • La función adjunta debe devolver la función anidada.

¿Cuándo usar cierres?

Entonces, ¿para qué sirven los cierres?

Los cierres pueden evitar el uso de valores globales y proporcionan alguna forma de ocultación de datos. También puede proporcionar una solución orientada a objetos al problema.

Cuando hay pocos métodos (un método en la mayoría de los casos) para implementar en una clase, los cierres pueden proporcionar una solución alternativa y más elegante. Pero cuando la cantidad de atributos y métodos aumenta, es mejor implementar una clase.

Aquí hay un ejemplo simple donde un cierre podría ser más preferible que definir una clase y crear objetos. Pero la preferencia es toda tuya.

 def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # Multiplier of 3 times3 = make_multiplier_of(3) # Multiplier of 5 times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2)))

Salida

 27 15 30

Los decoradores de Python también hacen un uso extensivo de los cierres.

Como nota final, es bueno señalar que se pueden averiguar los valores que se incluyen en la función de cierre.

Todos los objetos de función tienen un __closure__atributo que devuelve una tupla de objetos de celda si es una función de cierre. Con referencia al ejemplo anterior, conocemos times3y times5somos funciones de cierre.

 >>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)

El objeto de celda tiene el atributo cell_contents que almacena el valor cerrado.

 >>> times3.__closure__(0).cell_contents 3 >>> times5.__closure__(0).cell_contents 5

Articulos interesantes...