Funciones anidadas de Python

Las funciones son uno de los "ciudadanos de primera clase" de Python, lo que significa que las funciones están al mismo nivel que otros objetos de Python como enteros, st...

¿Qué es una función anidada?

Las funciones son uno de los "ciudadanos de primera clase" de Python, lo que significa que las funciones están al mismo nivel que otros objetos de Python como números enteros, cadenas, módulos, etc. Se pueden crear y destruir dinámicamente, pasar a otras funciones , devueltos como valores, etc.

Python admite el concepto de una "función anidada" o "función interna", que es simplemente una función definida dentro de otra función. En el resto del artículo, usaremos las palabras "función interna" y "función anidada" indistintamente.

Hay varias razones por las que a uno le gustaría crear una función dentro de otra función. La función interna puede acceder a las variables dentro del alcance adjunto. En este artículo, exploraremos varios aspectos de las funciones internas en Python.

Definición de una función interna

Para definir una función interna en Python, simplemente creamos una función dentro de otra función usando la palabra clave def de Python. Aquí hay un ejemplo:

1
2
3
4
5
6
7
def function1(): # outer function
    print ("Hello from outer function")
    def function2(): # inner function
        print ("Hello from inner function")
    function2()

function1()

Producción

1
2
Hello from outer function
Hello from inner function

En el ejemplo anterior, function2() se ha definido dentro de function1(), lo que la convierte en una función interna. Para llamar a function2(), primero debemos llamar a function1(). La función1() seguirá adelante y llamará a función2() tal como se ha definido en su interior.

Es importante mencionar que se debe llamar a la función externa para que se ejecute la función interna. Si no se llama a la función externa, la función interna nunca se ejecutará. Para demostrar esto, modifique el código anterior a lo siguiente y ejecútelo:

1
2
3
4
5
def function1(): # outer function
    print ("Hello from outer function")
    def function2(): # inner function
        print ("Hello from inner function")
    function2()

¡El código no devolverá nada cuando se ejecute!

Aquí hay otro ejemplo:

1
2
3
4
5
6
7
def num1(x):
   def num2(y):
      return x * y
   return num2
res = num1(10)

print(res(5))

Producción

1
50

El código devuelve la multiplicación de los dos números, es decir, 10 y 5. El ejemplo muestra que una función interna puede acceder a variables accesibles en la función externa.

Hasta ahora, has visto que es posible que accedamos a las variables de la función externa dentro de la función interna. ¿Qué sucede si intentamos cambiar las variables de la función externa desde el interior de la función interna? Veamos qué sucede:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def function1(): # outer function
    x = 2 # A variable defined within the outer function
    def function2(a): # inner function
       # Let's define a new variable within the inner function
       # rather than changing the value of x of the outer function
        x = 6
        print (a+x)
    print (x) # to display the value of x of the outer function
    function2(3)

function1()

Producción

1
2
2
9

El resultado muestra que es posible para nosotros mostrar el valor de una variable definida dentro de la función externa desde la función interna, pero no cambiarla. La instrucción x = 6 nos ayudó a crear una nueva variable x dentro de la función interna function2() en lugar de cambiar el valor de la variable x definida en la función externa function1().

En la siguiente sección, discutiremos las principales razones por las que usamos funciones internas en Python.

¿Por qué usar funciones internas? {#por qué usar funciones internas}

Encapsulación

Una función se puede crear como una función interna para protegerla de todo lo que sucede fuera de la función. En ese caso, la función se ocultará del ámbito global. Aquí hay un ejemplo:

1
2
3
4
5
6
7
8
9
def outer_function(x):
    # Hidden from the outer code
    def inner_increment(x):
        return x + 2
    y = inner_increment(x)
    print(x, y)

inner_increment(5)
#outer_function(5)

Producción

1
2
3
4
Traceback (most recent call last):
  File "C:/Users/admin/inner.py", line 7, in <module>
    inner_increment(5)
NameError: name 'inner_increment' is not defined

En el código anterior, intentamos llamar a la función inner_increment(), pero obtuvimos un error.

Ahora, comente la llamada a inner_increment() y descomente la llamada a outer_function() como se muestra a continuación:

1
2
3
4
5
6
7
8
9
def outer_function(x):
    # Hidden from the outer code
    def inner_increment(x):
        return x + 2
    y = inner_increment(x)
    print(x, y)

#inner_increment(5)
outer_function(5)

Producción

1
5 7

El script anterior muestra que la función interna, es decir, inner_increment() está protegida de lo que sucede fuera de ella, ya que la variable x dentro de la función inner_increment no se ve afectada por el valor pasado al parámetro x de la función exterior. En otras palabras, las variables dentro de la función interna no son accesibles fuera de ella. Hay una gran ventaja con tal patrón de diseño. Después de verificar todos los argumentos en la función externa, podemos omitir con seguridad la verificación de errores dentro de la función interna.

Cierres y Funciones de Fábrica

Todos los ejemplos que hemos visto hasta ahora solo contienen funciones ordinarias que se han anidado dentro de otras funciones. Es posible que escribamos tales funciones de otra manera en lugar de anidarlas dentro de otras funciones. No tenemos una razón específica de por qué deberíamos anidarlos.

Sin embargo, para el caso de cierres, se deben usar las funciones anidadas.

Podemos vincular/pasar datos a una función sin necesariamente pasar los datos a la función a través de parámetros. Esto se hace usando un cierre. Es un objeto de función que puede recordar valores en los ámbitos adjuntos incluso cuando no están disponibles en la memoria. Esto significa que tenemos un cierre cuando una función anidada hace referencia a un valor que está en su ámbito de aplicación.

El propósito de un cierre es hacer que la función interna recuerde el estado de su entorno cuando se le llama, incluso si no está en la memoria. Un cierre es causado por una función interna, pero no es la función interna. El cierre funciona al cerrar la variable local en la pila, que permanece después de que la creación de la pila ha terminado de ejecutarse.

Las siguientes son las condiciones que deben cumplirse para crear un cierre en Python:

  • Debe haber una función anidada
  • La función interna tiene que hacer referencia a un valor que se define en el ámbito adjunto
  • La función envolvente tiene que devolver la función anidada

Considere el siguiente ejemplo:

1
2
3
4
5
6
7
def function1(name):
    def function2():
        print('Hello ' + name)
    return function2

func = function1('Nicholas')
func()

Producción

1
Hello Nicholas

El código anterior demuestra que con los cierres, podemos generar e invocar una función desde fuera de su alcance mediante el paso de funciones. El alcance de function2() está solo dentro de function1(). Sin embargo, con el uso de clausuras, nos fue posible extender este alcance e invocarlo desde fuera de su alcance.

Las funciones internas nos ayudan a definir [funciones de fábrica] (https://en.wikipedia.org/wiki/Factory_method_pattern). Una función de fábrica es una función que crea otro objeto. Por ejemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def power_generator(num):

    # Create the inner function
    def power_n(power):
        return num ** power

    return power_n

power_two = power_generator(2)
power_three = power_generator(3)
print(power_two(8))
print(power_three(4))

Producción

1
2
256
81

En el script anterior, a partir de la función power_n(power), hemos creado otros dos objetos, power_two y power_tres. Esto hace que power_n(power) sea una función de fábrica ya que genera las funciones power_two y power_tres para nosotros usando el parámetro que le pasamos.

Conclusión

Una función interna es simplemente una función que se define dentro de otra función. La función interna puede acceder a las variables que se han definido dentro del alcance de la función externa, pero no puede cambiarlas. Hay una serie de razones por las que es posible que necesitemos crear una función interna. Por ejemplo, una función interna está protegida de lo que sucede fuera de ella. Las funciones internas también son una buena manera de crear cierres en Python.

Licensed under CC BY-NC-SA 4.0