En programación, el uso de funciones globales con datos desacoplados puede ocundir a comportamientos inesperados. Considérese un ejemplo donde funcionse genéricas operan sobre estructuras de datos como diccionarios, sin restricciones de tipo.
Problema con funciones globales
def emitir_sonido(criatura):
print("%s emite un sonido" % criatura["nombre"])
def consumir_alimento(criatura):
print("Un %s [%s] está consumiendo alimento" % (criatura["especie"], criatura["nombre"]))
animal1 = {
"nombre": "Rex",
"especie": "canino",
"género": "masculino"
}
objeto1 = {
"nombre": "Silla",
"especie": "mueble",
"material": "madera"
}
emitir_sonido(animal1) # Rex emite un sonido
consumir_alimento(objeto1) # Un mueble [Silla] está consumiendo alimento - aplicación errónea
La función consumir_alimento se invoca incorrectamente con un objeto no relacionado, evidenciando la falta de encapsulamiento. Para solucionarlo, se puede emplear el ámbito léxico de funciones anidadas.
Encapsulamiento con funciones anidadas
def crear_animal(nombre, especie, género):
def rugir(ser):
print("%s está rugiendo" % ser["nombre"])
def ingerir(ser):
print("Un %s [%s] está ingiriendo" % (ser["especie"], ser["nombre"]))
ser = {
"nombre": nombre,
"especie": especie,
"género": género,
"rugir": rugir,
"ingerir": ingerir
}
return ser
criatura = crear_animal("Tigre", "felino", "masculino")
print(criatura)
criatura["ingerir"](criatura)
Aquí, las funciones rugir e ingerir se definen dentro de crear_animal, limitando su acceso. El diccionario resultante incluye estas funciones como métodos, y se retorna para uso externo.
Refinamiento con inicialización separada
def crear_animal(nombre, especie, género):
def rugir(ser):
print("%s está rugiendo" % ser["nombre"])
def ingerir(ser):
print("Un %s [%s] está ingiriendo" % (ser["especie"], ser["nombre"]))
def inicializar_datos(nom, esp, gen):
ser = {
"nombre": nom,
"especie": esp,
"género": gen,
"rugir": rugir,
"ingerir": ingerir
}
return ser
return inicializar_datos(nombre, especie, género)
criatura_nueva = crear_animal("Águila", "ave", "femenino")
criatura_nueva["rugir"](criatura_nueva)
Este diseño separa la lógica de inicialización, mejorando la claridad. La función externa crear_animal actúa como un constructor, mientras que las funciones internas son métodos atados al objeto, simulando los princcipios de la programación orientada a objetos en Python.