Usando as Funções getattr() e setattr()
Python fornece funções embutidas para acessar e modificar atributos de objetos dinamicamente. Elas são particularmente úteis quando você deseja trabalhar com nomes de atributos que não são conhecidos até o tempo de execução.
A Função getattr()
A função getattr() permite que você acesse um atributo usando seu nome como uma string. A sintaxe é:
getattr(object, attribute_name, default_value)
object: O objeto cujo atributo você deseja acessar
attribute_name: Uma string contendo o nome do atributo
default_value: Um valor opcional para retornar se o atributo não existir
Vamos criar um novo arquivo chamado dynamic_attributes.py no diretório /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}")
Execute este código:
python3 /home/labex/project/dynamic_attributes.py
Você deve 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.
Observe que, para o atributo address, que não existe, getattr() retorna nosso valor padrão "Not available" em vez de gerar um erro.
A Função setattr()
A função setattr() permite que você defina um atributo usando seu nome como uma string. A sintaxe é:
setattr(object, attribute_name, value)
object: O objeto cujo atributo você deseja definir
attribute_name: Uma string contendo o nome do atributo
value: O valor a ser atribuído ao atributo
Vamos modificar nosso arquivo dynamic_attributes.py para incluir exemplos 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}")
Execute o código atualizado:
python3 /home/labex/project/dynamic_attributes.py
Você deve 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
Observe que fomos capazes de modificar atributos existentes e também adicionar um atributo completamente novo (address) que não foi definido na classe.
Exemplo Prático
Vamos criar um exemplo mais prático onde o acesso e a modificação de atributos dinâmicos são úteis. Crie um arquivo chamado data_processor.py no diretório /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}")
Execute este código:
python3 /home/labex/project/data_processor.py
Você deve 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 exemplo mostra como você pode converter dados de um dicionário (que pode vir de um banco de dados, API ou arquivo) em um objeto e, em seguida, acessar ou modificar seus atributos dinamicamente.