Introduction
Les fonctionnalités de programmation orientée objet (POO) de Python offrent aux développeurs des outils puissants pour gérer efficacement les données d'instance. L'un de ces outils est l'attribut __dict__, qui vous permet d'accéder et de manipuler dynamiquement les attributs d'un objet Python.
Dans ce tutoriel, nous allons explorer le fonctionnement de l'attribut __dict__ et apprendre différentes façons de l'utiliser pour gérer les données d'instance dans vos projets Python. À la fin de ce lab, vous comprendrez comment tirer parti de cette fonctionnalité pour créer des applications Python plus flexibles et dynamiques.
Comprendre les objets Python et l'attribut __dict__
Commençons par comprendre comment les objets Python stockent leurs attributs et comment nous pouvons y accéder en utilisant l'attribut __dict__.
Qu'est-ce qu'un objet en Python ?
En Python, tout est un objet. Les objets ont des attributs (données) et des méthodes (fonctions). Lorsque vous créez un objet à partir d'une classe, l'objet obtient son propre espace de noms pour stocker ses attributs.
Création d'une classe et d'un objet Python
Créons une classe et un objet Python simples pour commencer à explorer l'attribut __dict__ :
Ouvrez le terminal dans l'environnement LabEx.
Créez un nouveau fichier Python nommé
person.pyen utilisant l'éditeur de code :
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
return f"Hello, my name is {self.name} and I am {self.age} years old."
## Create a Person object
person = Person("Alice", 30)
## Print the person object attributes
print(f"Name: {person.name}")
print(f"Age: {person.age}")
print(f"Greeting: {person.greet()}")
## Let's examine the __dict__ attribute
print("\nThe __dict__ attribute contains:")
print(person.__dict__)
- Exécutez le fichier Python dans le terminal :
python3 person.py
Vous devriez voir une sortie similaire à :
Name: Alice
Age: 30
Greeting: Hello, my name is Alice and I am 30 years old.
The __dict__ attribute contains:
{'name': 'Alice', 'age': 30}
Qu'est-ce que l'attribut __dict__ ?
L'attribut __dict__ est un dictionnaire qui contient tous les attributs définis pour un objet. Chaque clé de ce dictionnaire est un nom d'attribut, et chaque valeur est la valeur d'attribut correspondante.
Comme vous pouvez le voir dans la sortie, l'attribut __dict__ de notre objet person contient les attributs name et age que nous avons définis dans la méthode __init__. Cependant, il ne contient pas la méthode greet car les méthodes sont définies dans la classe, et non dans l'instance.
Exploration des attributs de classe et d'instance
Mettons à jour notre code pour comprendre la différence entre les attributs de classe et d'instance :
- Modifiez le fichier
person.py:
class Person:
## Class attribute - shared by all instances
species = "Human"
def __init__(self, name, age):
## Instance attributes - unique to each instance
self.name = name
self.age = age
def greet(self):
return f"Hello, my name is {self.name} and I am {self.age} years old."
## Create a Person object
person = Person("Alice", 30)
## Print attributes
print(f"Name: {person.name}")
print(f"Age: {person.age}")
print(f"Species: {person.species}") ## Accessing class attribute
## Examine the __dict__ attributes
print("\nInstance __dict__ contains:")
print(person.__dict__)
print("\nClass __dict__ contains:")
print(Person.__dict__)
- Exécutez le fichier mis à jour :
python3 person.py
Vous remarquerez que l'attribut de classe species n'est pas stocké dans le __dict__ de l'instance, mais peut être accessible via l'instance. Le __dict__ de la classe contient tous les attributs et méthodes au niveau de la classe.
Pourquoi __dict__ est-il utile ?
L'attribut __dict__ vous donne un accès direct au mécanisme de stockage sous-jacent des objets Python. Cela peut être utile pour :
- Examiner dynamiquement les attributs d'un objet
- Ajouter ou modifier des attributs au moment de l'exécution
- Sérialiser des objets (les convertir en formats tels que JSON)
- Mettre en œuvre des schémas de programmation avancés
Maintenant que vous comprenez ce qu'est __dict__, apprenons à l'utiliser pour manipuler les attributs d'objets à l'étape suivante.
Accéder et modifier les attributs en utilisant __dict__
Maintenant que nous comprenons ce qu'est l'attribut __dict__, apprenons à l'utiliser pour accéder et modifier dynamiquement les attributs d'un objet.
Accéder aux attributs via __dict__
Il existe deux façons d'accéder aux attributs d'un objet en Python :
- En utilisant la notation pointée :
person.name - En utilisant l'attribut
__dict__:person.__dict__['name']
Créons un nouveau fichier Python pour explorer ces méthodes :
- Créez un nouveau fichier nommé
attribute_access.py:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
## Create a Person object
person = Person("Bob", 25)
## Method 1: Using dot notation
print("Using dot notation:")
print(f"Name: {person.name}")
print(f"Age: {person.age}")
## Method 2: Using __dict__
print("\nUsing __dict__:")
print(f"Name: {person.__dict__['name']}")
print(f"Age: {person.__dict__['age']}")
## Print the entire __dict__
print("\nAll attributes:")
print(person.__dict__)
- Exécutez le fichier :
python3 attribute_access.py
La sortie devrait montrer que les deux méthodes donnent le même résultat :
Using dot notation:
Name: Bob
Age: 25
Using __dict__:
Name: Bob
Age: 25
All attributes:
{'name': 'Bob', 'age': 25}
Modifier les attributs via __dict__
L'attribut __dict__ ne sert pas seulement à lire les attributs, mais aussi à les modifier ou à en ajouter de nouveaux. Voyons comment :
- Créez un nouveau fichier nommé
modify_attributes.py:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
## Create a Person object
person = Person("Charlie", 35)
print("Original attributes:")
print(person.__dict__)
## Modify an existing attribute
person.__dict__['age'] = 36
print("\nAfter modifying age:")
print(person.__dict__)
print(f"Accessing with dot notation: person.age = {person.age}")
## Add a new attribute
person.__dict__['city'] = "New York"
print("\nAfter adding city attribute:")
print(person.__dict__)
print(f"Accessing with dot notation: person.city = {person.city}")
## Delete an attribute
del person.__dict__['city']
print("\nAfter deleting city attribute:")
print(person.__dict__)
## Try to access the deleted attribute (this will cause an error)
try:
print(person.city)
except AttributeError as e:
print(f"Error: {e}")
- Exécutez le fichier :
python3 modify_attributes.py
Vous devriez voir une sortie similaire à :
Original attributes:
{'name': 'Charlie', 'age': 35}
After modifying age:
{'name': 'Charlie', 'age': 36}
Accessing with dot notation: person.age = 36
After adding city attribute:
{'name': 'Charlie', 'age': 36, 'city': 'New York'}
Accessing with dot notation: person.city = New York
After deleting city attribute:
{'name': 'Charlie', 'age': 36}
Error: 'Person' object has no attribute 'city'
Quand utiliser __dict__ par rapport à la notation pointée
Bien que les deux méthodes puissent être utilisées pour accéder et modifier les attributs, il existe des situations où l'utilisation de __dict__ est plus appropriée :
- Lorsque vous devez accéder à un attribut dont le nom est stocké dans une variable
- Lorsque vous souhaitez ajouter ou supprimer dynamiquement des attributs
- Lorsque vous devez itérer sur tous les attributs d'un objet
Créons un exemple pour illustrer ces cas :
- Créez un nouveau fichier nommé
dynamic_attributes.py:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
## Create a Person object
person = Person("David", 40)
## Case 1: Access attribute using a variable name
attr_name = "name"
print(f"Accessing {attr_name}: {person.__dict__[attr_name]}")
## Case 2: Dynamically add attributes
attributes_to_add = {
'city': 'Boston',
'job': 'Engineer',
'salary': 85000
}
for key, value in attributes_to_add.items():
person.__dict__[key] = value
print("\nAfter adding multiple attributes:")
print(person.__dict__)
## Case 3: Iterate over all attributes
print("\nAll attributes and their values:")
for attr_name, attr_value in person.__dict__.items():
print(f"{attr_name}: {attr_value}")
## Let's do something practical - create a function to clean up person data
def sanitize_person(person_obj):
"""Remove any attributes that are not name or age"""
allowed_attrs = ['name', 'age']
attrs_to_remove = [key for key in person_obj.__dict__ if key not in allowed_attrs]
for attr in attrs_to_remove:
del person_obj.__dict__[attr]
sanitize_person(person)
print("\nAfter sanitization:")
print(person.__dict__)
- Exécutez le fichier :
python3 dynamic_attributes.py
La sortie montre comment vous pouvez travailler avec les attributs de manière dynamique en utilisant __dict__.
Comparaison des méthodes de manipulation directe des attributs
Maintenant, créons un autre exemple pour comparer les différentes façons de manipuler les attributs :
- Créez un nouveau fichier nommé
attribute_comparison.py:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
## Create a Person object
person = Person("Eve", 28)
## Method 1: Using dot notation
person.city = "Chicago"
## Method 2: Using __dict__
person.__dict__['job'] = "Designer"
## Method 3: Using setattr
setattr(person, 'hobby', 'Painting')
## Method 4: Using getattr
name_value = getattr(person, 'name')
print("All attributes after different methods of adding:")
print(person.__dict__)
print(f"Retrieved name using getattr: {name_value}")
## You can also check if an attribute exists
if 'city' in person.__dict__:
print("The city attribute exists!")
## Or retrieve a value with a default if it doesn't exist
country = person.__dict__.get('country', 'Unknown')
print(f"Country (with default): {country}")
- Exécutez le fichier :
python3 attribute_comparison.py
Cet exemple montre qu'il existe plusieurs façons de manipuler les attributs d'objets en Python. Bien que __dict__ vous donne un accès direct au stockage des attributs, il existe d'autres fonctions intégrées comme setattr() et getattr() qui fournissent des fonctionnalités similaires d'une manière plus idiomatique en Python.
Dans l'étape suivante, nous allons explorer quelques applications pratiques de l'utilisation de l'attribut __dict__.
Applications pratiques de __dict__ pour la gestion dynamique des attributs
Maintenant que nous savons comment accéder et modifier les attributs en utilisant __dict__, explorons quelques applications pratiques de cette fonctionnalité dans les programmes Python du monde réel.
Application 1 : Sérialisation d'objets (conversion en JSON)
Un cas d'utilisation courant de __dict__ est la sérialisation d'objets, en particulier lors de la conversion d'objets Python au format JSON pour le stockage ou la transmission.
- Créez un nouveau fichier nommé
object_serialization.py:
import json
class Person:
def __init__(self, name, age, city=None):
self.name = name
self.age = age
if city:
self.city = city
def to_json(self):
## Use __dict__ to get all attributes as a dictionary
return json.dumps(self.__dict__)
@classmethod
def from_json(cls, json_str):
## Create a new Person object from a JSON string
data = json.loads(json_str)
return cls(**data)
## Create a Person object
person = Person("Frank", 45, "San Francisco")
## Serialize to JSON
json_data = person.to_json()
print("JSON Data:")
print(json_data)
## Deserialize from JSON
person2 = Person.from_json(json_data)
print("\nDeserialized Person object attributes:")
print(person2.__dict__)
## Let's create multiple people and serialize them
people = [
Person("Grace", 32, "Seattle"),
Person("Henry", 27),
Person("Isla", 39, "Miami")
]
## Serialize the list of people
people_json = [person.to_json() for person in people]
print("\nJSON for multiple people:")
for p_json in people_json:
print(p_json)
## Save to a file
with open('people.json', 'w') as f:
json.dump([p.__dict__ for p in people], f)
print("\nSaved people data to people.json")
## Read from the file
with open('people.json', 'r') as f:
loaded_data = json.load(f)
print("\nLoaded from file:")
print(loaded_data)
## Convert back to Person objects
loaded_people = [Person(**data) for data in loaded_data]
print("\nRecreated Person objects:")
for person in loaded_people:
print(f"{person.name}, {person.age}, {getattr(person, 'city', 'No city')}")
- Exécutez le fichier :
python3 object_serialization.py
Cet exemple montre comment __dict__ facilite la conversion d'objets Python vers et depuis JSON. En utilisant __dict__, nous pouvons facilement obtenir tous les attributs d'un objet sous forme de dictionnaire, qui peut ensuite être converti en JSON à l'aide du module json.
Application 2 : Fabrique d'objets dynamique
Une autre application pratique de __dict__ est la création d'objets dynamiquement en fonction des données :
- Créez un nouveau fichier nommé
dynamic_object_factory.py:
class DynamicObject:
def __init__(self, **kwargs):
## Add all the keyword arguments as attributes
for key, value in kwargs.items():
self.__dict__[key] = value
def __str__(self):
attributes = ", ".join(f"{k}={v}" for k, v in self.__dict__.items())
return f"DynamicObject({attributes})"
## Create objects with different attributes
person = DynamicObject(name="Jennifer", age=29, profession="Developer")
car = DynamicObject(make="Toyota", model="Camry", year=2020, color="Blue")
book = DynamicObject(title="Python Programming", author="John Smith", pages=350)
## Print the objects
print(person)
print(car)
print(book)
## We can add attributes after creation
person.__dict__['country'] = "Canada"
print("\nAfter adding country attribute:")
print(person)
## We can also create an empty object and fill it later
empty_obj = DynamicObject()
print("\nEmpty object:", empty_obj)
## Fill it with data from a dictionary
data = {"type": "Laptop", "brand": "Dell", "ram": "16GB", "storage": "512GB SSD"}
empty_obj.__dict__.update(data)
print("After filling:", empty_obj)
## Let's create a factory function that creates objects from different data sources
def create_object_from_data(data_source):
if isinstance(data_source, dict):
return DynamicObject(**data_source)
elif isinstance(data_source, list) and all(isinstance(item, tuple) and len(item) == 2 for item in data_source):
return DynamicObject(**dict(data_source))
else:
raise ValueError("Unsupported data source type")
## Create objects from different data sources
dict_data = {"name": "Kevin", "age": 35, "email": "kevin@example.com"}
list_data = [("product", "Monitor"), ("price", 299.99), ("in_stock", True)]
obj1 = create_object_from_data(dict_data)
obj2 = create_object_from_data(list_data)
print("\nObjects created from different data sources:")
print(obj1)
print(obj2)
- Exécutez le fichier :
python3 dynamic_object_factory.py
Cet exemple montre comment nous pouvons utiliser __dict__ pour créer des objets dynamiques avec des attributs arbitraires, ce qui est utile lorsque l'on travaille avec des données provenant de sources externes telles que des API, des fichiers ou des bases de données.
Application 3 : Suivi simple des attributs
Nous pouvons utiliser __dict__ pour suivre les modifications apportées aux attributs d'un objet, ce qui peut être utile pour des fonctionnalités telles que la détection des modifications ou la mise en œuvre de la fonctionnalité annuler/rétablir :
- Créez un nouveau fichier nommé
attribute_tracking.py:
class TrackedObject:
def __init__(self, **kwargs):
## Initialize with the provided attributes
self.__dict__.update(kwargs)
## Store the original state
self.__original_state = self.__dict__.copy()
def get_changes(self):
"""Return a dictionary of attributes that have changed"""
changes = {}
for key, current_value in self.__dict__.items():
## Skip the original state attribute itself
if key == '_TrackedObject__original_state':
continue
## Check if the attribute existed originally
if key in self.__original_state:
## Check if the value has changed
if current_value != self.__original_state[key]:
changes[key] = {
'old': self.__original_state[key],
'new': current_value
}
else:
## This is a new attribute
changes[key] = {
'old': None,
'new': current_value
}
## Check for deleted attributes
for key in self.__original_state:
if key not in self.__dict__:
changes[key] = {
'old': self.__original_state[key],
'new': None
}
return changes
def has_changes(self):
"""Check if the object has any changes"""
return len(self.get_changes()) > 0
def reset(self):
"""Reset the object to its original state"""
## Remove all current attributes
for key in list(self.__dict__.keys()):
if key != '_TrackedObject__original_state':
del self.__dict__[key]
## Add back the original attributes
for key, value in self.__original_state.items():
self.__dict__[key] = value
## Create a tracked object
user = TrackedObject(name="Linda", email="linda@example.com", age=31)
## Print the original state
print("Original state:")
print(user.__dict__)
## Make some changes
user.age = 32
user.email = "linda.new@example.com"
user.address = "123 Main St"
del user.name
## Check for changes
print("\nAfter changes:")
print(user.__dict__)
print("\nDetected changes:")
changes = user.get_changes()
for attr, change in changes.items():
print(f"{attr}: {change['old']} -> {change['new']}")
print(f"\nHas changes: {user.has_changes()}")
## Reset to original state
user.reset()
print("\nAfter reset:")
print(user.__dict__)
print(f"Has changes: {user.has_changes()}")
- Exécutez le fichier :
python3 attribute_tracking.py
Cet exemple montre comment nous pouvons utiliser __dict__ pour implémenter le suivi des attributs, ce qui peut être utile dans de nombreuses applications, telles que la validation de formulaires, la gestion d'état ou la mise en œuvre de la fonctionnalité annuler/rétablir.
L'attribut __dict__ est un outil puissant dans l'arsenal de la programmation orientée objet de Python. En comprenant son fonctionnement et comment l'utiliser efficacement, vous pouvez créer du code Python plus flexible, dynamique et maintenable.
Création d'un mini-projet : Gestionnaire de contacts utilisant __dict__
Maintenant que nous avons exploré diverses applications de l'attribut __dict__, mettons nos connaissances en pratique en créant une simple application de gestionnaire de contacts. Ce mini-projet démontrera comment utiliser __dict__ dans un scénario réel.
L'application de gestionnaire de contacts
Notre gestionnaire de contacts nous permettra de :
- Ajouter des contacts avec divers attributs
- Rechercher des contacts
- Mettre à jour les informations de contact
- Supprimer des contacts
- Exporter les contacts en JSON
- Importer les contacts depuis JSON
Étape 1 : Créer les classes Contact et ContactManager
- Créez un nouveau fichier nommé
contact_manager.py:
import json
import os
class Contact:
def __init__(self, name, email=None, phone=None, **kwargs):
self.name = name
self.email = email
self.phone = phone
## Add any additional attributes
for key, value in kwargs.items():
self.__dict__[key] = value
def update(self, **kwargs):
"""Update contact attributes"""
self.__dict__.update(kwargs)
def __str__(self):
"""String representation of the contact"""
attrs = []
for key, value in self.__dict__.items():
if value is not None:
attrs.append(f"{key}: {value}")
return ", ".join(attrs)
class ContactManager:
def __init__(self):
self.contacts = []
def add_contact(self, contact):
"""Add a new contact"""
self.contacts.append(contact)
print(f"Added contact: {contact.name}")
def find_contact(self, **kwargs):
"""Find contacts matching the criteria"""
results = []
for contact in self.contacts:
match = True
for key, value in kwargs.items():
## Skip if the contact doesn't have this attribute
if key not in contact.__dict__:
match = False
break
## Skip if the attribute value doesn't match
if contact.__dict__[key] != value:
match = False
break
if match:
results.append(contact)
return results
def update_contact(self, contact, **kwargs):
"""Update a contact's attributes"""
contact.update(**kwargs)
print(f"Updated contact: {contact.name}")
def delete_contact(self, contact):
"""Delete a contact"""
if contact in self.contacts:
self.contacts.remove(contact)
print(f"Deleted contact: {contact.name}")
else:
print("Contact not found.")
def export_contacts(self, filename):
"""Export contacts to a JSON file"""
contacts_data = []
for contact in self.contacts:
contacts_data.append(contact.__dict__)
with open(filename, 'w') as f:
json.dump(contacts_data, f, indent=2)
print(f"Exported {len(self.contacts)} contacts to {filename}")
def import_contacts(self, filename):
"""Import contacts from a JSON file"""
if not os.path.exists(filename):
print(f"File {filename} not found.")
return
with open(filename, 'r') as f:
contacts_data = json.load(f)
imported_count = 0
for data in contacts_data:
## Create a copy of the data to avoid modifying the original
contact_data = data.copy()
## Get the required parameters
name = contact_data.pop('name', None)
email = contact_data.pop('email', None)
phone = contact_data.pop('phone', None)
if name:
## Create a new contact with remaining attributes as kwargs
contact = Contact(name, email, phone, **contact_data)
self.contacts.append(contact)
imported_count += 1
print(f"Imported {imported_count} contacts from {filename}")
def print_all_contacts(self):
"""Print all contacts"""
if not self.contacts:
print("No contacts found.")
return
print(f"\nAll Contacts ({len(self.contacts)}):")
print("-" * 40)
for i, contact in enumerate(self.contacts, 1):
print(f"{i}. {contact}")
print("-" * 40)
## Let's test our contact manager
if __name__ == "__main__":
## Create a contact manager
manager = ContactManager()
## Add some contacts
manager.add_contact(Contact("John Doe", "john@example.com", "555-1234",
address="123 Main St", city="Boston"))
manager.add_contact(Contact("Jane Smith", "jane@example.com", "555-5678",
company="ABC Corp", role="Developer"))
manager.add_contact(Contact("Bob Johnson", "bob@example.com", "555-9012",
twitter="@bobjohnson", birthday="1985-03-15"))
## Print all contacts
manager.print_all_contacts()
## Find contacts
print("\nContacts with email ending with @example.com:")
for contact in manager.contacts:
if contact.email and contact.email.endswith("@example.com"):
print(f"- {contact.name}: {contact.email}")
## Use the find_contact method
print("\nFinding contacts by name:")
results = manager.find_contact(name="Jane Smith")
for contact in results:
print(f"Found: {contact}")
## Update a contact
if results:
manager.update_contact(results[0], phone="555-NEW-NUM", role="Senior Developer")
print(f"After update: {results[0]}")
## Export contacts to JSON
manager.export_contacts("contacts.json")
## Delete a contact
manager.delete_contact(results[0])
## Print all contacts after deletion
manager.print_all_contacts()
## Create a new manager and import contacts
print("\nCreating a new manager and importing contacts:")
new_manager = ContactManager()
new_manager.import_contacts("contacts.json")
new_manager.print_all_contacts()
- Exécutez le fichier :
python3 contact_manager.py
Vous devriez voir une sortie montrant le gestionnaire de contacts en action, y compris l'ajout, la recherche, la mise à jour et la suppression de contacts, ainsi que l'exportation et l'importation de contacts vers et depuis un fichier JSON.
Étape 2 : Étendre le gestionnaire de contacts avec des fonctionnalités personnalisées
Maintenant, améliorons notre gestionnaire de contacts en ajoutant la possibilité d'ajouter des champs personnalisés pour différents types de contacts :
- Créez un nouveau fichier nommé
extended_contact_manager.py:
from contact_manager import Contact, ContactManager
class BusinessContact(Contact):
def __init__(self, name, email=None, phone=None, company=None, role=None, **kwargs):
super().__init__(name, email, phone, **kwargs)
self.company = company
self.role = role
self.contact_type = "business"
class PersonalContact(Contact):
def __init__(self, name, email=None, phone=None, relationship=None, birthday=None, **kwargs):
super().__init__(name, email, phone, **kwargs)
self.relationship = relationship
self.birthday = birthday
self.contact_type = "personal"
class ExtendedContactManager(ContactManager):
def add_business_contact(self, name, email=None, phone=None, company=None, role=None, **kwargs):
contact = BusinessContact(name, email, phone, company, role, **kwargs)
self.add_contact(contact)
return contact
def add_personal_contact(self, name, email=None, phone=None, relationship=None, birthday=None, **kwargs):
contact = PersonalContact(name, email, phone, relationship, birthday, **kwargs)
self.add_contact(contact)
return contact
def find_by_contact_type(self, contact_type):
"""Find contacts by type (business or personal)"""
return self.find_contact(contact_type=contact_type)
def get_contact_details(self, contact):
"""Get detailed information about a contact"""
details = []
for key, value in contact.__dict__.items():
if value is not None:
if key == "contact_type":
details.append(f"Type: {value.capitalize()}")
else:
## Convert key from snake_case to Title Case
formatted_key = " ".join(word.capitalize() for word in key.split("_"))
details.append(f"{formatted_key}: {value}")
return "\n".join(details)
## Test the extended contact manager
if __name__ == "__main__":
## Create an extended contact manager
manager = ExtendedContactManager()
## Add some business contacts
manager.add_business_contact(
"Alice Johnson",
"alice@company.com",
"555-1111",
"XYZ Corp",
"Marketing Manager",
department="Marketing",
office_location="Building A, 3rd Floor"
)
manager.add_business_contact(
"Bob Williams",
"bob@startup.co",
"555-2222",
"StartUp Inc",
"CEO",
linkedin="linkedin.com/in/bobwilliams"
)
## Add some personal contacts
manager.add_personal_contact(
"Carol Davis",
"carol@gmail.com",
"555-3333",
"Friend",
"1990-05-15",
address="456 Oak St",
favorite_restaurant="Italian Place"
)
manager.add_personal_contact(
"Dave Wilson",
"dave@hotmail.com",
"555-4444",
"Family",
"1982-12-03",
emergency_contact=True
)
## Print all contacts
manager.print_all_contacts()
## Find contacts by type
print("\nBusiness Contacts:")
business_contacts = manager.find_by_contact_type("business")
for contact in business_contacts:
print(f"- {contact.name} ({contact.company})")
print("\nPersonal Contacts:")
personal_contacts = manager.find_by_contact_type("personal")
for contact in personal_contacts:
print(f"- {contact.name} ({contact.relationship})")
## Show detailed information for a contact
if business_contacts:
print("\nDetailed information for", business_contacts[0].name)
print(manager.get_contact_details(business_contacts[0]))
## Export contacts to JSON
manager.export_contacts("extended_contacts.json")
## Import contacts
new_manager = ExtendedContactManager()
new_manager.import_contacts("extended_contacts.json")
print("\nAfter importing:")
new_manager.print_all_contacts()
## Check if we can still identify contact types after import
imported_business = new_manager.find_by_contact_type("business")
print(f"\nImported {len(imported_business)} business contacts")
imported_personal = new_manager.find_by_contact_type("personal")
print(f"Imported {len(imported_personal)} personal contacts")
- Exécutez le fichier :
python3 extended_contact_manager.py
Ce gestionnaire de contacts étendu montre comment nous pouvons utiliser l'attribut __dict__ pour créer des structures de données flexibles capables de gérer différents types de contacts avec des attributs variables.
Étape 3 : Créer une simple interface en ligne de commande
Enfin, créons une simple interface en ligne de commande pour notre gestionnaire de contacts :
- Créez un nouveau fichier nommé
contact_manager_cli.py:
from extended_contact_manager import ExtendedContactManager, BusinessContact, PersonalContact
def print_menu():
print("\n===== Contact Manager =====")
print("1. Add Business Contact")
print("2. Add Personal Contact")
print("3. List All Contacts")
print("4. Find Contact")
print("5. Update Contact")
print("6. Delete Contact")
print("7. Export Contacts")
print("8. Import Contacts")
print("9. Exit")
print("==========================")
def get_contact_details(contact_type):
"""Get contact details from user input"""
details = {}
## Common fields
details['name'] = input("Name: ")
details['email'] = input("Email (optional): ") or None
details['phone'] = input("Phone (optional): ") or None
## Type-specific fields
if contact_type == "business":
details['company'] = input("Company (optional): ") or None
details['role'] = input("Role (optional): ") or None
## Ask for custom fields
print("Add custom fields (leave empty to finish):")
while True:
field_name = input("Field name (or empty to finish): ")
if not field_name:
break
field_value = input(f"{field_name}: ")
details[field_name] = field_value
elif contact_type == "personal":
details['relationship'] = input("Relationship (optional): ") or None
details['birthday'] = input("Birthday (YYYY-MM-DD, optional): ") or None
## Ask for custom fields
print("Add custom fields (leave empty to finish):")
while True:
field_name = input("Field name (or empty to finish): ")
if not field_name:
break
field_value = input(f"{field_name}: ")
details[field_name] = field_value
return details
def select_contact(manager):
"""Let the user select a contact from the list"""
if not manager.contacts:
print("No contacts available.")
return None
print("\nSelect a contact:")
for i, contact in enumerate(manager.contacts, 1):
print(f"{i}. {contact.name}")
try:
selection = int(input("Enter number (0 to cancel): "))
if selection == 0:
return None
if 1 <= selection <= len(manager.contacts):
return manager.contacts[selection - 1]
else:
print("Invalid selection.")
return None
except ValueError:
print("Please enter a valid number.")
return None
def main():
manager = ExtendedContactManager()
while True:
print_menu()
choice = input("Enter your choice (1-9): ")
if choice == '1':
## Add Business Contact
print("\n-- Add Business Contact --")
details = get_contact_details("business")
name = details.pop('name')
email = details.pop('email')
phone = details.pop('phone')
company = details.pop('company')
role = details.pop('role')
manager.add_business_contact(name, email, phone, company, role, **details)
elif choice == '2':
## Add Personal Contact
print("\n-- Add Personal Contact --")
details = get_contact_details("personal")
name = details.pop('name')
email = details.pop('email')
phone = details.pop('phone')
relationship = details.pop('relationship')
birthday = details.pop('birthday')
manager.add_personal_contact(name, email, phone, relationship, birthday, **details)
elif choice == '3':
## List All Contacts
manager.print_all_contacts()
elif choice == '4':
## Find Contact
print("\n-- Find Contact --")
search_term = input("Enter name to search: ")
results = manager.find_contact(name=search_term)
if results:
print(f"\nFound {len(results)} contacts:")
for contact in results:
print(manager.get_contact_details(contact))
print("-" * 30)
else:
print("No contacts found with that name.")
elif choice == '5':
## Update Contact
print("\n-- Update Contact --")
contact = select_contact(manager)
if contact:
print("\nCurrent details:")
print(manager.get_contact_details(contact))
print("\nEnter new details (leave empty to keep current value):")
updates = {}
for key, value in contact.__dict__.items():
if key != "contact_type": ## Don't allow changing the contact type
new_value = input(f"{key} [{value}]: ")
if new_value and new_value != str(value):
updates[key] = new_value
manager.update_contact(contact, **updates)
print("\nContact updated.")
elif choice == '6':
## Delete Contact
print("\n-- Delete Contact --")
contact = select_contact(manager)
if contact:
confirm = input(f"Are you sure you want to delete {contact.name}? (y/n): ")
if confirm.lower() == 'y':
manager.delete_contact(contact)
elif choice == '7':
## Export Contacts
print("\n-- Export Contacts --")
filename = input("Enter filename (default: contacts.json): ") or "contacts.json"
manager.export_contacts(filename)
elif choice == '8':
## Import Contacts
print("\n-- Import Contacts --")
filename = input("Enter filename: ")
manager.import_contacts(filename)
elif choice == '9':
## Exit
print("\nThank you for using Contact Manager!")
break
else:
print("Invalid choice. Please try again.")
if __name__ == "__main__":
main()
- Exécutez l'application CLI :
python3 contact_manager_cli.py
- Essayez d'ajouter des contacts, de rechercher des contacts, de mettre à jour des contacts et d'exporter/importer des contacts à l'aide de l'interface en ligne de commande.
Ce mini-projet démontre à quel point l'attribut __dict__ peut être puissant lors de la création d'applications pilotées par les données et flexibles en Python. Le gestionnaire de contacts permet des champs personnalisés sur les contacts, la sérialisation vers et depuis JSON, et une gestion facile des différents types de contacts, en tirant tous parti de l'attribut __dict__ pour gérer dynamiquement les données d'instance.
Grâce à ce projet, vous avez appris à :
- Utiliser
__dict__pour stocker et récupérer les attributs d'objets - Créer des classes flexibles capables de gérer des attributs variables
- Sérialiser et désérialiser des objets vers et depuis JSON
- Créer une simple application en ligne de commande qui exploite les attributs dynamiques
Ces compétences peuvent être appliquées à de nombreuses applications Python réelles, des outils de traitement de données aux applications Web et aux intégrations d'API.
Résumé
Dans ce laboratoire, vous avez exploré le puissant attribut __dict__ en Python et appris comment il peut être utilisé pour gérer efficacement les données d'instance. Voici un récapitulatif de ce que vous avez appris :
Comprendre
__dict__: Vous avez appris que l'attribut__dict__est un dictionnaire qui stocke les variables d'instance d'un objet, offrant ainsi un moyen d'accéder et de manipuler dynamiquement les attributs d'un objet.Accéder et modifier les attributs : Vous avez découvert diverses façons d'accéder et de modifier les attributs d'un objet, notamment la notation par point, la manipulation directe de
__dict__et les fonctions intégrées telles quesetattr()etgetattr().Applications pratiques : Vous avez exploré des applications pratiques de
__dict__, notamment la sérialisation d'objets, la gestion dynamique des attributs et le suivi des attributs.Création d'un mini-projet : Vous avez mis vos connaissances en pratique en créant une application de gestionnaire de contacts qui exploite l'attribut
__dict__pour le stockage flexible des données, la sérialisation et la gestion dynamique des attributs.
L'attribut __dict__ est un outil puissant qui peut vous aider à écrire du code Python plus flexible et dynamique. En comprenant son fonctionnement et comment l'utiliser efficacement, vous pouvez créer des applications capables de s'adapter aux exigences changeantes et de gérer facilement des structures de données diverses.
Au fur et à mesure que vous poursuivez votre parcours Python, n'oubliez pas que, bien que l'attribut __dict__ offre une grande flexibilité, il doit être utilisé avec discernement. Dans de nombreux cas, des approches plus idiomatiques de Python, telles que l'utilisation de propriétés, de descripteurs ou de fonctions intégrées comme getattr() et setattr(), peuvent fournir des solutions plus propres et plus faciles à maintenir.



