En este artículo exploraremos un error común en programación Python que nos ayudará a comprender mejor los conceptos de clases, objetos, atributos y métodos.
Es importante recordar que Python es un lenguaje dinámico, lo que significa que podemos agregar o modificar atributos y métodos en cualquier momento. Además, Python no soporta la sobrecarag de métodos; si definimos varias veces el mismo método, la última definición sobreescribirá las anteriores. Cuando utilizamos decoradores, podemos transformar métodos en propiedades, permitiando crear métodos con el mismo nombre pero diferentes decoradores.
class Empleado():
def __init__(self, nombre, salario):
self._nombre = nombre
self._salario = salario
# @property
def nombre(self):
return self._nombre
# @property
def salario(self):
return self._salario
# @salario.setter
def salario(self, valor):
# Sin el decorador @property, este método sobreescribiría salario(self)
self._salario = valor
trabajador = Empleado('maria', 50000)
# print(trabajador.salario()) # ERROR, porque el método salario(self) fue sobrescrito
trabajador.salario(60000) # Llama al método salario(self, valor), estableciendo el nuevo salario
print(trabajador.salario) # Muestra la dirección del método salario() del objeto
trabajador.nuevosalario = 60000 # El objeto originalmente no tenía el atributo nuevo_salario
trabajador.salario = 60000 # Esto modifica el atributo salario del objeto
# trabajador.salario(70000) # ERROR, 'int' object is not callable. El atributo salario ya no es un método
Claramente, esta capacidad de agregar atributos dinámicamente puede presentar riesgos. Si necesitamos restringir los atributos que un objeto puede tener, podemos definir la varible __slots__ en nuestra clase. Es importante notar que esta restricción solo afecta a los objetos de la clase actual y no a sus subclases.
Ejemplo:
class Empleado():
__slots__ = ('_nombre', '_salario')
def __init__(self, nombre, salario):
self._nombre = nombre
self._salario = salario
def agregar_atributo(self, attr):
self._attr = attr
@property
def nombre(self):
return self._nombre
@property
def salario(self):
return self._salario
@salario.setter
def salario(self, valor):
self._salario = valor
def principal():
trabajador = Empleado('maria', 50000)
trabajador.salario = 60000
# trabajador._nombre = 'luis' # Es posible acceder directamente al atributo
trabajador.agregar_atributo(123) # ERROR, 'Empleado' object has no attribute '_attr'