Atributos dinámicos en Python



@eduardo_gpg

Número de visitas 2037

Tiempo de lectura 4 min

26 Marzo 2022

Cuando comenzamos en la programación orientada a objetos con Python, algo muy común de aprender es que utilizando el método __init__ seremos capaces de definir todos aquellos atributos que nuestro objeto puede poseer. 😎

Veamos un ejemplo.

class User:

    def __init__(self, username, email):
        self.username = username
        self.email = email

py = User('PyWombat', 'eduardo78d@gmail.com')

print(py.username)
print(py.email)

En este caso nuestro objeto posee 2 atributos, username y email, atributos los cuales se han creado utilizando el método __init__.

Si ejecutamos el código no obtendremos ningún tipo de error, y el objeto poseerá sus 2 correspondientes atributos.

Salida.

'PyWombat'
'eduardo78d@gmail.com'

Esto funciona bastante bien, ya que el método __init__ es uno de los primeros métodos que son llamados cuando se crea un nuevo objeto, lo cual permite definir todos aquellos atributos que el objeto poseerá.

Hasta aquí nada nuevo.

Sin embargo ¿Sabias que en Python, por default, los atributos de un objeto pueden ser creados de forma dinámica en cualquier parte del código? Sí, así como lo lees. 🤯

El tema de atributos en Python es un tema super interesante, que en muchas ocasiones pasamos por alto. Es por ello que para esta nueva entrega de PyWombat me gustaría habláramos acerca de los atributos. Principalmente del cómo poder crearlos de forma dinámica.

Será un post sumamente interésate, y es probable que te lleve algo nuevo, así que te invito a que te quedes.

Bien, una vez dicho todo esto, y sin más introducción, pongamos manos a la obra.

Atributos dinámicos

Entremos en materia. Lo primero que debemos tener en cuenta es que nosotros seremos capaces de crear nuevos atributos para nuestros objetos en cualquier parte del código donde los necesitemos.

Veamos un ejemplo.

class User:

    def __init__(self, username, email):
        pass

py = User()

py.username = 'PyWombat'
py.email = 'eduardo78d@gmail.com'

print(py.username)
print(py.email)

En este caso creamos los atributos username y email fuera de la clase, una vez el objeto haya sido creado.

Si ejecutamos el código obtendremos exactamente el mismo resultado que de haber utilizado del método __init__ (Como en el primer ejemplo).

Salida.

'PyWombat'
'eduardo78d@gmail.com'

Que si lo piensas bien, ambas formas de crear atributos (ya sea dentro o fuera de la clase) son exactamente lo mismo. 😛 Recordemos que self no es más que el objeto per se. Con esto en mente podemos concluir que, para poder crear un nuevo atributo para nuestro objetos basta con seguir la siguiente estructura.

objecto.atributo = valor

Por lo tanto, la creación de nuevos atributos podemos hacerlo tanto en métodos de instancia como con la instancia misma.

Nota: Los métodos de instancia no son más que los métodos que el objeto puede llamar. Ejemplo: objeto.metodo()

class User:

    def __init__(self, username, email):
        # Creamos los atributos en diferentes métodos

        self.creacion_username(username)
        self.creacion_email(email)


    def creacion_username(self, username):
        self.username = username


    def creacion_email(self, email):
        self.email = email

py = User('PyWombat', 'eduardo78d@gmail.com')

print(py.username)
print(py.email)

Para este nuevo ejemplo creamos los atributos en 2 métodos diferentes. Lo cual para Python, por supuesto, no supone ningún tipo de problema. 🤠

Este tipo de comportamiento podemos aprovecharlo a nuestro favor, pudiendo así crear objetos de un mismo tipo con atributos diferentes.

class User:

    def __init__(self, username, email):
        # Creamos los atributos en diferentes métodos
        self.creacion_username(username)
        self.creacion_edad(email)


    def creacion_username(self, username):
        self.username = username


    def creacion_age(self, age):
        self.age = age


    def creacion_rfc(self, rfc):
        self.rfc = rfc

py = User('PyWombat', 18)

if py.age > 18:
    py.creacion_rfc('1234')

Para este nuevo ejemplo creamos el atributo rfc, sí y solo sí, el usuario posee una edad mayor a 18. Con este tipo de código podemos crear objetos más o menos complejos según necesidades.

Gestión de atributos

Ahora, con todo lo aprendido anteriormente, es probable que te pregunte ¿Cómo es posible conocer que atributos posee un objeto? Bueno, para ello haremos uso del atributo __dict__.

Este atributo no es más que un diccionario donde podremos encontrar todos aquellos atributos que nuestro objeto posee.

>>> py.__dict__ 
{'username': 'PyWombat', 'email': 'eduardo78d@gmail.com'}

Será este atributo quien gestione todos los atributos de un objeto. A través de este diccionario seremos capaces, no solo de conocer lo atributos asociados al objeto, si no también de poder asignar nuevos atributos, eliminarlos o actualizarlos.

Ejemplo.

py = User('PyWombat', 'eduardo78d@gmail.com')

py.__dict__['password'] = 'password123'
py.__dict__['username'] = 'Nuevo username'

del py.__dict__['email']


print(py.__dict__)

Salida.

{'username': 'Nuevo username', 'password': 'password123'}

Es algo curioso ¿No lo crees? Un atributo que gestiona otros atributos. 🤓

Método init

Con todo lo mencionado anteriormente ¿Realmente vale la pena seguir utilizando le método __init_\? Mi respuesta es sí. Como mencionamos anteriormente, el __init__ es uno de los primeros métodos que son llamados cuando un objeto es creado. Lo cual nos viene de maravilla para, no crear atributos, si no para inicializarlos.

Hay que ver al método __init__ como el método que inicializa los atributos, y no como el que los crea. Que si bien esta implícito en el nombre (init) no hay que pasarlo por alto.

Por lo cual, te invito a que si conoces de antemano que atributos poseerá tu objeto los inicialices en el método __init__, ya que hacerlo en otros métodos o fuera de la clase puede ocasionar inconsistencias en los objetos, lo cual sin duda alguna, tarde o temprano, se traducirá en errores, además que es posible que tu código se vuelva mucha más difícil de leer y por ende mucho más difícil de mantener.

Por otro lado, si la aplicación que te encuentras desarrollador no tienen del todo claro que atributos poseerá el objeto en cuestión (Algo así como con las bases de datos no relacionales) entonces allí creo que si vale la pena explorar el crear atributos dinámicos de forma controlada. 🤩


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login

Más Tips y Ejercicios 🐍

Adquiere una subscripción PyWombat por tan solo $3 USD. al mes.

Conoce los beneficios de ser usuario premium:
Niveles desbloqueados: Ten accesos a todos los niveles de ejercicios. 🔓
Nuevo límite: Incrementa tu límite de ejercicios por semana. 🚀
Contenido único: Recibe semanalmente recursos exclusivos de Python (Videos, Artículos y Capitulos del libro PyWombat, comienza como desarrollador Python. 🐍