Menu
Coddy logo textTech

Membres Publics, Protégés, Privés

Fait partie de la section Object Oriented Programming du Journey Python de Coddy — leçon 28 sur 64.

Python dispose de trois niveaux de contrôle d'accès pour les membres de classe : public, protected et private. Ceux-ci contrôlent la manière dont les attributs et les méthodes peuvent être accédés.

Voici un exemple d'une classe avec les trois niveaux d'accès :

class BankAccount:
    def __init__(self, owner, balance, account_id):
        self.owner = owner           # Public - accessible partout
        self._balance = balance      # Protégé - usage interne
        self.__account_id = account_id  # Privé - classe uniquement
    
    def deposit(self, amount):       # Méthode publique
        self._balance += amount
    
    def _calculate_interest(self):   # Méthode protégée
        return self._balance * 0.02
    
    def __validate_transaction(self, amount):  # Méthode privée
        return amount > 0 and amount <= self._balance

Accédez aux membres publics de n'importe où :

account = BankAccount("Alice", 1000, "12345")
print(account.owner)        # Alice
account.deposit(500)        # Fonctionne correctement

Accéder aux membres protégés (underscore simple - convention uniquement) :

print(account._balance)     # 1500 - fonctionne mais n'est pas recommandé
result = account._calculate_interest()  # Fonctionne mais n'est pas recommandé
print(result)               # 30.0

Essayez d'accéder aux membres privés (double soulignement - nom déformé) :

# Cela ne fonctionnera pas :
# print(account.__account_id)  # AttributeError

# Mais ceci fonctionne (déformation de nom) :
print(account._BankAccount__account_id)  # 12345

Créez une sous-classe pour montrer l'accès protégé par rapport à l'accès privé :

class SavingsAccount(BankAccount):
    def show_balance(self):
        return self._balance        # Protégé - accessible dans la sous-classe
    
    def show_id(self):
        # return self.__account_id  # Cela ne fonctionnera pas - privé
        return "Cannot access private member"
savings = SavingsAccount("Bob", 2000, "67890")
print(savings.show_balance())  # 2000
print(savings.show_id())       # Impossible d'accéder au membre privé

Sortie :

Alice
30.0
12345
2000
Cannot access private member

Point clé : Les membres publics n'ont pas de préfixe et sont accessibles partout. Les membres protégés utilisent un simple souligné (_) et ne devraient être utilisés qu'au sein de la hiérarchie des classes. Les membres privés utilisent un double souligné (__) et subissent un masquage de nom (name-mangling) pour une confidentialité accrue. Le contrôle d'accès de Python est basé sur des conventions et n'est pas strictement appliqué.

challenge icon

Défi

Moyen

Dans ce défi, vous allez implémenter une classe BankAccount qui démontre l'utilisation appropriée des niveaux d'accès public, protégé et privé en Python.

  • bankaccount.py - Contient la définition de la classe avec des commentaires TODO guidant votre implémentation
  1. Suivez les commentaires TODO dans bankaccount.py pour implémenter la fonctionnalité requise
  2. Implémentez les niveaux d'accès appropriés (public, protégé, privé) comme spécifié
  3. Assurez-vous que toutes les méthodes gèrent les cas limites de manière appropriée (dépôts négatifs, etc.)

Aide-mémoire

Python dispose de trois niveaux de contrôle d'accès pour les membres de classe :

  • Public : Aucun préfixe, accessible partout
  • Protégé : Un seul souligné (_), usage interne au sein de la hiérarchie de classes
  • Privé : Double souligné (__), nom déformé (name-mangling) pour un accès réservé à la classe
class BankAccount:
    def __init__(self, owner, balance, account_id):
        self.owner = owner           # Public
        self._balance = balance      # Protégé
        self.__account_id = account_id  # Privé
    
    def deposit(self, amount):       # Méthode publique
        self._balance += amount
    
    def _calculate_interest(self):   # Méthode protégée
        return self._balance * 0.02
    
    def __validate_transaction(self, amount):  # Méthode privée
        return amount > 0 and amount <= self._balance

Accès aux membres :

account = BankAccount("Alice", 1000, "12345")

# Accès public
print(account.owner)        # Fonctionne correctement

# Accès protégé (fonctionne mais n'est pas recommandé)
print(account._balance)     # 1500

# Accès privé (nom déformé)
print(account._BankAccount__account_id)  # 12345

Dans les sous-classes :

class SavingsAccount(BankAccount):
    def show_balance(self):
        return self._balance        # Protégé - accessible
    
    def show_id(self):
        # return self.__account_id  # Privé - non accessible
        return "Cannot access private member"

Essayez vous-même

from bank_account import BankAccount

# Gestionnaire de cas de test complet
test_case = input()

if test_case == "basic_test":
    # Test de fonctionnalité de base
    account = BankAccount("John Doe", "12345")
    print(account.account_holder)  # Attribut public
    print(account.deposit(100))    # Méthode publique
    print(account.get_balance())   # Méthode publique

elif test_case == "transaction_count":
    # Test de l'attribut protégé
    account = BankAccount("Jane Smith", "67890")
    account.deposit(50)
    account.deposit(100)
    account.deposit(200)
    print(account._transaction_count)  # Attribut protégé
    print(account.get_balance())

elif test_case == "invalid_deposit":
    # Test de la validation dans la méthode deposit
    account = BankAccount("Bob Johnson", "54321")
    print(account.deposit(-50))  # Devrait retourner None
    print(account.deposit(0))    # Devrait retourner None
    print(account.deposit(75))   # Devrait retourner 75
    print(account.get_balance())

elif test_case == "private_access":
    # Test de l'accès aux attributs privés
    account = BankAccount("Alice Brown", "98765")
    try:
        print(account.__balance)  # Cela lèvera une AttributeError
    except AttributeError:
        pass
    
    try:
        print(account.__account_number)  # Cela lèvera une AttributeError
    except AttributeError:
        pass
    
    print("Private attributes are not directly accessible")
    account.deposit(500)
    print(account.get_balance())  # Accès via une méthode publique

elif test_case == "name_mangling":
    # Démonstration du name mangling pour les attributs privés
    account = BankAccount("Charlie Green", "13579")
    print(account._BankAccount__balance)        # Accès à un attribut privé via le name mangling
    print(account._BankAccount__account_number)  # Accès à un attribut privé via le name mangling
    account.deposit(300)
    print(account._BankAccount__balance)  # Devrait afficher le solde mis à jour

elif test_case == "multiple_accounts":
    # Test de plusieurs comptes
    account1 = BankAccount("David White", "24680")
    account2 = BankAccount("Eva Black", "86420")
    account3 = BankAccount("Frank Red", "97531")
    
    account1.deposit(150)
    account2.deposit(250)
    account2.deposit(50)
    account3.deposit(500)
    account3.deposit(300)
    account3.deposit(200)
    
    print(f"{account1.account_holder}: {account1.get_balance()}")
    print(f"{account2.account_holder}: {account2.get_balance()}")
    print(f"{account3.account_holder}: {account3.get_balance()}")
    
    print(f"Account 1 transactions: {account1._transaction_count}")
    print(f"Account 2 transactions: {account2._transaction_count}")
    print(f"Account 3 transactions: {account3._transaction_count}")

elif test_case == "stress_test":
    # Test de performance avec de nombreuses transactions
    account = BankAccount("Stress Tester", "11111")
    for _ in range(1000):
        account.deposit(1)
    print(f"Final balance: {account.get_balance()}")
    print(f"Transaction count: {account._transaction_count}")
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Object Oriented Programming