Usando las Funciones getattr() y setattr()
Python proporciona funciones integradas para acceder y modificar dinámicamente los atributos de los objetos. Estas son particularmente útiles cuando deseas trabajar con nombres de atributos que no se conocen hasta el tiempo de ejecución.
La Función getattr()
La función getattr() te permite acceder a un atributo usando su nombre como una cadena. La sintaxis es:
getattr(object, attribute_name, default_value)
object: El objeto cuyo atributo deseas acceder
attribute_name: Una cadena que contiene el nombre del atributo
default_value: Un valor opcional para devolver si el atributo no existe
Creemos un nuevo archivo llamado dynamic_attributes.py en el directorio /home/labex/project:
class Person:
def __init__(self, name, age, job):
self.name = name
self.age = age
self.job = job
def greet(self):
return f"Hello, my name is {self.name} and I am {self.age} years old."
## Create a Person object
john = Person("John", 30, "Developer")
## List of attributes to access
attributes = ["name", "age", "job", "address"]
## Access attributes using getattr()
print("Accessing attributes using getattr():")
for attr in attributes:
## The third parameter is the default value if the attribute doesn't exist
value = getattr(john, attr, "Not available")
print(f"{attr.capitalize()}: {value}")
## Call a method using getattr
greet_method = getattr(john, "greet")
greeting = greet_method()
print(f"Greeting: {greeting}")
Ejecuta este código:
python3 /home/labex/project/dynamic_attributes.py
Deberías ver:
Accessing attributes using getattr():
Name: John
Age: 30
Job: Developer
Address: Not available
Greeting: Hello, my name is John and I am 30 years old.
Observa que para el atributo address, que no existe, getattr() devuelve nuestro valor predeterminado "Not available" en lugar de generar un error.
La Función setattr()
La función setattr() te permite establecer un atributo usando su nombre como una cadena. La sintaxis es:
setattr(object, attribute_name, value)
object: El objeto cuyo atributo deseas establecer
attribute_name: Una cadena que contiene el nombre del atributo
value: El valor a asignar al atributo
Modifiquemos nuestro archivo dynamic_attributes.py para incluir ejemplos de uso de setattr():
class Person:
def __init__(self, name, age, job):
self.name = name
self.age = age
self.job = job
def greet(self):
return f"Hello, my name is {self.name} and I am {self.age} years old."
## Create a Person object
john = Person("John", 30, "Developer")
print("Original attributes:")
print(f"Name: {john.name}")
print(f"Age: {john.age}")
print(f"Job: {john.job}")
## Modify attributes using setattr()
print("\nModifying attributes using setattr():")
setattr(john, "name", "John Smith")
setattr(john, "age", 31)
setattr(john, "job", "Senior Developer")
## Add a new attribute using setattr()
setattr(john, "address", "123 Main St")
## Print the modified attributes
print("\nModified attributes:")
print(f"Name: {john.name}")
print(f"Age: {john.age}")
print(f"Job: {john.job}")
print(f"Address: {john.address}")
## Access attributes using getattr()
print("\nAccessing attributes using getattr():")
for attr in ["name", "age", "job", "address"]:
value = getattr(john, attr, "Not available")
print(f"{attr.capitalize()}: {value}")
Ejecuta el código actualizado:
python3 /home/labex/project/dynamic_attributes.py
Deberías ver:
Original attributes:
Name: John
Age: 30
Job: Developer
Modifying attributes using setattr():
Modified attributes:
Name: John Smith
Age: 31
Job: Senior Developer
Address: 123 Main St
Accessing attributes using getattr():
Name: John Smith
Age: 31
Job: Senior Developer
Address: 123 Main St
Observa que pudimos modificar los atributos existentes y también agregar un atributo completamente nuevo (address) que no estaba definido en la clase.
Ejemplo Práctico
Creemos un ejemplo más práctico donde el acceso y la modificación dinámica de atributos son útiles. Crea un archivo llamado data_processor.py en el directorio /home/labex/project:
class DataRecord:
def __init__(self):
## Start with no attributes
pass
## Create a function to process a dictionary into an object
def dict_to_object(data_dict):
record = DataRecord()
for key, value in data_dict.items():
setattr(record, key, value)
return record
## Sample data (could come from a database, API, etc.)
user_data = {
"user_id": 12345,
"username": "johndoe",
"email": "john@example.com",
"active": True,
"login_count": 27
}
## Convert the dictionary to an object
user = dict_to_object(user_data)
## Access the attributes
print(f"User ID: {user.user_id}")
print(f"Username: {user.username}")
print(f"Email: {user.email}")
print(f"Active: {user.active}")
print(f"Login Count: {user.login_count}")
## We can also add or modify attributes
setattr(user, "last_login", "2023-09-15")
setattr(user, "login_count", 28)
print("\nAfter modifications:")
print(f"Login Count: {user.login_count}")
print(f"Last Login: {user.last_login}")
## We can also access all attributes dynamically
print("\nAll attributes:")
for attr in ["user_id", "username", "email", "active", "login_count", "last_login"]:
value = getattr(user, attr, None)
print(f"{attr}: {value}")
Ejecuta este código:
python3 /home/labex/project/data_processor.py
Deberías ver:
User ID: 12345
Username: johndoe
Email: john@example.com
Active: True
Login Count: 27
After modifications:
Login Count: 28
Last Login: 2023-09-15
All attributes:
user_id: 12345
username: johndoe
email: john@example.com
active: True
login_count: 28
last_login: 2023-09-15
Este ejemplo muestra cómo puedes convertir datos de un diccionario (que podrían provenir de una base de datos, una API o un archivo) en un objeto, y luego acceder o modificar sus atributos dinámicamente.