[Tutor] Simple bank account oriented object

Steven D'Aprano steve at pearwood.info
Tue Apr 6 01:15:29 CEST 2010


On Tue, 6 Apr 2010 06:31:30 am Marco Rompré wrote:
> Hi im doin a programmin course at university and in one on my
> exercise i have to do that
>
> I had to define a class CompteBancaire(CompteBancaire is bankaccount
> in french), that would allow me to create objects Compte1,
> Compte2,etc.
[...]

I do not understand French, so if I have misunderstood something, please 
excuse me. My comments are added in between yours.


> #Exercice 3,2 - Gestion d'un compte bancaire pour étudiant avec marge
> de crédit disponible de 1000$CDN
>
> class CompteBancaire:
>     "définition d'un compte bancaire"

This docstring is not very useful. The reader already knows that you are 
defining a CompteBancaire. What else can you tell them? How about basic 
usage?

class CompteBancaire:
    """définition d'un compte bancaire

    Example: create a cheque account with $1000 balance.

    >>> compte = CompteBancaire('cheque', 1000)

    Deposit $100, then withdraw $80:

    >>> compte.depot(100)
    >>> compte.retrait(80)

    """


>     def __init__(self,nom,solde,interet):       #Nous allons
> instancier et initialiser les objets à la classe
>         self.nom, self.solde, self.interet = nom,solde,interet

It is not clear to me whether interet (French for interest?) is meant to 
be a percentage rate, or an amount. I will assume it is an amount (how 
much interest the bank has paid you). Every new account will always 
start with interet = 0, so we should write this:

def __init__(self, nom, solde):
    self.nom, self.solde = nom, solde
    self.interet = 0

It is not clear to me what nom (name?) is for, but I have left it in.



>     def depot(self,somme=0):                    #Méthode pour
> additionner les dépôts au compte
>         self.solde=self.solde+somme

Do you need the default value for deposits? Will it ever be useful for 
the user to call compte.depot() without an amount?

I would think it would be more useful to add the default values to the 
initialiser __init__:

def __init__(self, nom='', solde=0):
    ...

and take it away from the depot and retrait methods:

def depot(self, somme):
    ...
def retrait(self,somme):
    ...


But this is just my opinion.


>     def retrait(self,somme=0):                  #Méthode pour
> soustraire les retraits au compte
>         if self.nom == 'Sandon':
>             if self.solde-somme<0:
>                 print "Les fonds sont insuffisants. Essayez un autre
> montant pour votre retrait!"
>             else:
>                 self.solde=self.solde-somme

This comment might be more advanced than you have learned. If so, you 
can safely ignore this part. If you have not learned about exceptions 
yet, you can safely ignore this.

When programming, you should separate the "back-end" from 
the "front-end". The back-end should report errors using exceptions, in 
a form which is useful to the programmer, and the front-end should 
catch those exceptions and print an error message in a form which is 
useful to the user.

So we should write:

def retrait(self, somme):
    if somme > self.solde:
        raise ValueError('fonds sont insuffisants')
    else:
        self.solde = self.solde - somme


>         elif self.nom =='Étudiant':             #Vérifie s'il s'agit
> d'un compte étudiant

This part is not good. The CompteBancaire class MUST NOT know anything 
about the CompteEtudiant subclass. Each class should only know about 
itself, and superclasses (parent classes).

So all the code dealing with the Étudiant account must go inside the 
CompteEtudiant class, not the CompteBancaire.


>             if self.solde - somme < -self.margeCre:      # Vérifie si
> le retrait dépasse la marge de crédit maximum
>                 print "Désolé, votre retrait dépasse la marge de
> crédit autorisé"
>             else:                               # sinon déuit le
> montant retirer de la marge de crédit
>                 self.margeCre = self.solde - somme
>                 self.solde = 0


>     def calculInteret(self,calculInteret=0):     #Méthode qui calcule
> les intérêts et le solde résiduel
>         self.interet=self.solde*calculInteret/100
>         self.solde=(self.solde*calculInteret/100)+self.solde

There is a small problem with Python here, depending on what version you 
are using. In older versions of Python, division is "integer division", 
so that:

1/2 -> 0
9/4 -> 2

and so forth. This will give you the wrong result for calculating 
interest. In newer versions of Python (version 3.0 and better) division 
is "true division":

1/2 -> 0.5
9/4 -> 2.5

The easiest way to make your code work correctly is to change 100 to 
100.0 (a float instead of an int) and then it will calculate as you 
expect in all versions.


>     def affiche_solde(self):                    #Méthode qui affiche
> le solde et le montant d'intérêt accumulé
>         print "Le solde du compte bancaire de %s est de %d $CAD"
> %(self.nom,self.solde)
>         print "Vous avez récolté %d $CDN en intérêt"%(self.interet)


Now we look at the Étudiant account, and add the extra functionality.


> class CompteEtudiant(CompteBancaire):
>     "définition du compte bancaire pour étudiant dérivé du compte
> bancaire standard"
>     def __init__(self, nom='', solde=0, margeCre=0):
>         CompteBancaire.__init__(self, nom='Nom', solde=0, interet=0)
>         self.nom, self.solde, self.margeCre = nom, solde, margeCre

The CompteEtudiant class can let the CompteBancaire do some of the work. 
This is called "inheritance" -- the subclass inherits code from the 
parent class.


def __init__(self, nom='', solde=0, margeCre=0):
    # Call the parent class method.
    CompteBancaire.__init__(self, nom, solde)
    # Do the extra work this class needs.
    self.margeCre = margeCre

Calling CompteBancaire.__init__ does everything the CompteBancaire 
understands. It sets nom, solde and interet, but not margeCre because 
CompteBancaire does not know anything about margeCre. Then the subclass 
sets margeCre itself.


>     def affiche_solde(self, somme=0):           #Méthode constructeur
> qui redéfini la fonction affiche_solde pour le compte étudiant
>         print "%s--Votre solde bancaire est de %d $CAD"
> %(self.nom,self.solde)
>         print "Le solde de votre marge de crédit est de %d $CAD"
> %(self.margeCre)


The CompteEtudiant should print the same information as the 
CompteBancaire class, plus extra. Again, inheritance makes it easy:

def affiche_solde(self):
    # Display everything the super class understands.
    CompteBancaire.affiche_soldeafficheself)
    # Display the parts that only the subclass understands.
    print "Le solde de votre marge de crédit est de %d $CAD" % 
(self.margeCre)


And one more method needs to be defined: we have to change the retrait 
method to allow negative balance, but only up to a maximum of margeCre.

def retrait(self, somme):
    if somme > self.solde + self.margeCre:
        raise ValueError('fonds sont insuffisants')
    else:
        self.solde = self.solde - somme



-- 
Steven D'Aprano


More information about the Tutor mailing list