Introducción
Esta sección introduce la idea de utilizar funciones para crear otras funciones.
This tutorial is from open-source community. Access the source code
💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí
Esta sección introduce la idea de utilizar funciones para crear otras funciones.
Considere la siguiente función.
def add(x, y):
def do_add():
print('Adding', x, y)
return x + y
return do_add
Esta es una función que devuelve otra función.
>>> a = add(3,4)
>>> a
<function add.<locals>.do_add at 0x7f27d8a38790>
>>> a()
Adding 3 4
7
Observe cómo la función interna se refiere a las variables definidas por la función externa.
def add(x, y):
def do_add():
## `x` y `y` se definen arriba de `add(x, y)`
print('Adding', x, y)
return x + y
return do_add
Observe además que esas variables siguen existiendo de alguna manera después de que add()
haya terminado.
>>> a = add(3,4)
>>> a
<function do_add at 0x6a670>
>>> a()
Adding 3 4 ## ¿De dónde provienen estos valores?
7
Cuando una función interna se devuelve como resultado, esa función interna se conoce como una cerradura.
def add(x, y):
## `do_add` es una cerradura
def do_add():
print('Adding', x, y)
return x + y
return do_add
Característica esencial: Una cerradura retiene los valores de todas las variables necesarias para que la función funcione correctamente más adelante. Piense en una cerradura como una función más un entorno adicional que contiene los valores de las variables en las que depende.
Las cerraduras son una característica esencial de Python. Sin embargo, su uso suele ser sutil. Aplicaciones comunes:
Considere una función como esta:
def after(seconds, func):
import time
time.sleep(seconds)
func()
Ejemplo de uso:
def greeting():
print('Hello Guido')
after(30, greeting)
after
ejecuta la función suministrada... más tarde.
Las cerraduras llevan información adicional.
def add(x, y):
def do_add():
print(f'Adding {x} + {y} -> {x+y}')
return do_add
def after(seconds, func):
import time
time.sleep(seconds)
func()
after(30, add(2, 3))
## `do_add` tiene las referencias x -> 2 e y -> 3
Las cerraduras también se pueden utilizar como técnica para evitar la excesiva repetición de código. Puedes escribir funciones que generen código.
Una de las características más poderosas de las cerraduras es su uso en la generación de código repetitivo. Si se vuelve a revisar el Ejercicio 5.7, recuerde el código para definir una propiedad con comprobación de tipos.
class Stock:
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
...
@property
def shares(self):
return self._shares
@shares.setter
def shares(self, value):
if not isinstance(value, int):
raise TypeError('Expected int')
self._shares = value
...
En lugar de escribir repetidamente ese código una y otra vez, se puede crear automáticamente utilizando una cerradura.
Cree un archivo typedproperty.py
y coloque el siguiente código en él:
## typedproperty.py
def typedproperty(name, expected_type):
private_name = '_' + name
@property
def prop(self):
return getattr(self, private_name)
@prop.setter
def prop(self, value):
if not isinstance(value, expected_type):
raise TypeError(f'Expected {expected_type}')
setattr(self, private_name, value)
return prop
Ahora, pruébelo definiendo una clase como esta:
from typedproperty import typedproperty
class Stock:
name = typedproperty('name', str)
shares = typedproperty('shares', int)
price = typedproperty('price', float)
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Intente crear una instancia y verificar que la comprobación de tipos funcione.
>>> s = Stock('IBM', 50, 91.1)
>>> s.name
'IBM'
>>> s.shares = '100'
... debería obtener un TypeError...
>>>
En el ejemplo anterior, los usuarios pueden encontrar llamadas como typedproperty('shares', int)
un poco verbosas para escribir, especialmente si se repiten muchas veces. Agregue las siguientes definiciones al archivo typedproperty.py
:
String = lambda name: typedproperty(name, str)
Integer = lambda name: typedproperty(name, int)
Float = lambda name: typedproperty(name, float)
Ahora, reescriba la clase Stock
para usar estas funciones en lugar de las anteriores:
class Stock:
name = String('name')
shares = Integer('shares')
price = Float('price')
def __init__(self, name, shares, price):
self.name = name
self.shares = shares
self.price = price
Ah, eso es un poco mejor. La principal lección aquí es que las cerraduras y lambda
a menudo se pueden usar para simplificar el código y eliminar la repetición molesta. Esto suele ser bueno.
¡Felicitaciones! Has completado el laboratorio de Funciones de Retorno. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.