Encapsulamiento en Python y cómo afecta a mi vida sexual

Posted on Dec 28, 2016 | Python

Seguramente a todos nos enseñaron y nos repitieron muchas veces que uno de los principios fundamentales, uno de los pilares del paradigma de programación orientado a objetos, es el Encapsulamiento y debemos aprovecharlo, aplicarlo…

En mi opinión, no me agrada mucho todo esto del encapsulamiento, y creo que a Python tampoco, además pienso que es una pérdida de tiempo (al final del post el porqué ;)).

¿Encapsula..qué?

Basicamente el encapsulamiento consiste en restringir el acceso a ciertos datos de un objeto contra su modificación por quien no tenga derecho a acceder a ellos…

Los programadores Java/C++ consiguen el encapsulamiento con los modificadores de acceso (public, protected y private). Rápidamente, una clase puede tener métodos públicos, éstos métodos pueden ser accedidos desde fuera de la clase (desde la clase misma y desde la instancia). También puede tener métodos privados, que al contrario de los métodos públicos, solo pueden ser accedidos desde la clase. Además existe la posibilidad de tener métodos protegidos, que es como algo intermedio entre lo público y privado, toma un poco de los dos, no se puede acceder desde la instancia, pero si desde las subclases.

Python no tiene ningún mecanismo para aplicar el Encapsulamiento, todo es cuestión de convención.

Public en Py

Todos los atributos y métodos son públicos por default:

class Taza(object):
    def __init__(self):
        self.color = None
        self.contenido = None

    def llenar(self, contenido):
        self.contenido = contenido

    def vaciar(self):
        self.contenido = None

Tenemos una clase Taza que podemos darle un color, llenarla y vaciarla:

taza_azul = Taza()
taza_azul.color = "Azul"
taza_azul.contenido = "Mate Cocido"
taza_azul.vaciar()
taza_azul.lenar("Vino Tinto")  # Si, muchas veces he tomado vino en una taza

Protected en Py

Por convención, decimos que algo es “protected” o “no toques esto a menos que sea una subclase” prefijando _ al nombre del atributo o método:

class Taza(object):
    def __init__(self):
        self.color = None
        self._contenido = None

    def llenar(self, contenido):
        self._contenido = contenido

    def vaciar(self):
        self._contenido = None

Ahora el contenido de la taza está “protegido”, igualmente podemos hacer esto:

taza_blanca = Taza()
taza_blanca.color = "Blanca"
taza_blanca._contenido = "Te"

Estamos diciendo que algo que comience con _ es de uso interno, no forma parte de la API pública, nadie puede tocar el nombre fuera de la clase. Pero recuerda, es solo convención, el lenguaje no le da ningún significado especial.

Private en Py

Python soporta algo llamado name mangling que convierte cualquer nombre que comience con __ a _Clase__nombre:


class Taza(object):
    def __init__(self, color):
        self._color = None
        self.__contenido = None

    def llenar(self, contenido):
        self.__contenido = contenido

    def vaciar(self):
        self.__contenido = None

Ahora la taza puede ser llenada y vaciada solamente usando los métodos llenar() y vaciar(), si se intenta acceder a __contenido desde fuera:

mi_taza = Taza("verde")
mi_taza.llenar("Agua")
print(mi_taza.__contenido)

Traceback (most recent call last):
  File "test.py", line 15, in <module>
    print(t.__contenido)
AttributeError: 'Taza' object has no attribute '__contenido'

Igualmente podrías en algún momento de tu vida ver algo así:

mi_taza = Taza("verde")
mi_taza.llenar("Agua")
mi_taza._Taza__contenido = None

Deberías golpear a quien haga eso.

¿Cómo todo esto afecta mi vida sexual?

Simple es mejor que complejo

Cuando se piensa en el diseño de una clase no podemos predecir todos los usos posibles. Me refiero a que en algún momento, en el futuro puede ser que el código que fue pensado como algo privado, requiera de acceso. Entonces, ¿Por qué hacerlo difícil?, ¿Por qué hacer que sea imposible el acceso a datos cuando otra persona en el futuro o incluso yo los necesite?. Para eso usamos la convención del prefijado, es decir, no estamos impidiendo el acceso a los datos, solo estamos dejando una “advertencia” y se consigue lo mismo que los modificadores de acceso, que a diferencia de otros lenguajes, en Python vemos directamente del nombre si es público o no, podemos romper el encapsulamiento si se quiere, es justificable cuando por ejemplo hacemos tests, en otros lenguajes se tendría que utilizar la reflexión, y esto es igual a más código. Por eso, prohibir el acceso por completo me parece innecesario.

Entonces, puedo hacer practicamente lo mismo, con un poco más de flexibilidad, sin palabras claves. Esto es igual a un lenguaje más chico, el código será más conciso, me ahorro horas de programación y por lo tanto, tengo más tiempo para el sexo :).