<string>

Table des matières

Mission 9 - Héritage

Mission 9 : Héritage

Mission 9 : Héritage

1   Introduction

Le traitement de données commerciales et financières est un des champs majeurs d'application de l'informatique. De nos jours, la moindre PME utilise l'informatique pour gérer sa comptabilité, ses commandes et sa facturation, et l'infrastructure informatique est devenue un élément critique de toute grande entreprise, dont la supervision représente un poste clé au sein de l'exécutif, celui de Chief Information Officer ou CIO.

Invoice Manager, un logiciel de facturation pour PME. (© Hillstone Software)

PCLine s.p.r.l., une société de vente de matériel et de service informatique locale de Louvain-la-Neuve, fait appel à vos services pour développer ses applications informatisées de facturation. Les gérants de PCLine disposent déjà d'un programme pour imprimer leurs factures et calculer la TVA et les totaux. Ils désirent développer également la livraison des articles et de pièces, en intégrant l'impression des bordereaux de livraison dans leur logiciel de facturation existant, sans devoir écrire complètement leur logiciel existant. Heureusement, leur logiciel étant écrit en Python dans un style orienté objets, leur consultant de l'UCLouvain leur a confirmé qu'il était possible de l'étendre sans le modifier au moyen des mécanismes d'héritage de Python. Ils ont donc confié aux étudiants de 1er Bac la tâche d'ébaucher la représentation des pièces en catalogue, leur intégration dans la facturation, ainsi que l'impression des bordereaux de livraison en plus de l'impression des factures.

2   Objectifs

A l'issue de cette mission, chacun d'entre vous :

  • pourra masquer les variables d'instance d'une classe et écrire des méthodes pour y accéder;

  • aura appris la notion de variable de classe et son utilité;

  • pourra expliquer en ses propre mots et illustrer par l'exemple les principes de l'héritage en Python:

    * l'héritage d'une classe;
    * la redéfinition de méthodes;
    * l'utilisation de ``self`` et ``super()``;
    
  • sera capable d'utiliser l'héritage pour étendre un programme Python;

  • pourra utiliser les méthodes magiques comme

    * ``__init__`` pour initialiser les objets d'une classe;
    * ``__str__`` pour retourner une représentation textuelle d'un instance d'une classe;
    * ``__eq__`` pour définir l'égalité entres objets d'une classe.
    

3   Préparation, étude et apprentissage

La matière relative à cette mission est décrite dans les sections suivantes de la partie Objects du syllabus en ligne:

ainsi que les annexes:

4   Questionnaire de démarrage

4.1   Questions à choix multiple

Les questions à choix multiples de cette mission sont accessibles en ligne depuis https://inginious.info.ucl.ac.be/course/LSINF1101-PYTHON/Session10_QCM


        
        

4.2   Questions ouvertes

4.2.1   Egalité

Considérez une classe Pair :

class Pair:

    def __init__(self, x, y):
        self.a = x
        self.b = y

    def __str__(self):
        return str(self.a) + ", " + str(self.b)

Maintenant considérez le code suivant :

p1 = Pair(9, 42)
p2 = Pair(9, 42);
print(p1 == p2)

La dernière instruction affichera False. (Pourquoi?)

Ajoutez une méthode __eq__(self, p) à la classe Pair qui compare la valeur de deux paires, de manière à ce que print(p1 == p2) imprimera True au lieu de False.

Dans l'implémentation de votre méthode pensez également à gérer le cas où p == None.


        
        

4.2.2   L'héritage

L'héritage est un principe de base de la programmation orientée objet. Considérons les classes A, B, C et D ci-dessous :

class A :

  def m1(self) :
      print("A 1")

  def m2(self) :
      print("A 2")

  def m3(self) :
      self.m1()   # appel à la méthode m1 sur la même instance

  def nom(self) :
      return "A"

class B(A) :

  def m2(self):
      print("B 2")

class C(A):

    def m1(self) :
        print("C 1")

    def nom(self):
        return "C"

class D(C) :

    def m2(self) :
        print("D 2")

Considérant ces quatre classes, on vous demande de :

  • Expliquez ce que représente le mot self dans la définition de ces différentes méthodes.
 
 
 
 

  • Dessiner un diagramme reprenant ces quatre classes.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  • Expliquer ce qui sera affiché lors de l'exécution des instructions Python ci-dessous :
a = A()
print(a.nom())
a.m1()
a.m2()
a.m3()
b = B()
print(b.nom())
b.m1()
b.m2()
b.m3()
c = C()
print(c.nom())
c.m1()
c.m2()
c.m3()
d = D()
print(d.nom())
d.m1()
d.m2()
d.m3()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

4.2.3   C'est super !

  • Expliquez le rôle de la fonction spécial super() dans le langage Python. Donnez un exemple.
 
 
 
 
 

  • Considérons les classes E et F ci-dessous :
class E :

    def m(self) :
        print("E 1")

    def n(self) :
        print("E 2")

    def p(self) :
        self.n()   # appel à la méthode n sur la même instance

class F(E) :

   def q(self) :
       print("F 1")

   def n(self) :
       super().n() # appeler la méthode définie sur la classe mère
       print("F 2")

   def r(self) :
        self.m() # appel à la méthode m sur la même instance

Expliquer ce qui sera affiché lors de l'exécution des instructions Python suivantes :

f = F()
f.q()
f.m()
f.r()
f.n()
f.p()
 
 
 
 
 
 
 

4.2.4   Rectangle

Considérons la classe Figure reprise ci-dessous :

class Figure:

    def __init__(self,x,y,visible=False) :
        """
        @pre x, y sont des entiers représentant des positions sur l'écran
        @post Une figure a été créée avec centre de gravité aux coordonnées x,y.
              Cette figure n'est initialement pas visible.
        """
        self.x = x
        self.y = y
        self.__visible = visible

    def est_visible(self) :
        """
        @pre -
        @post a retourné la visibilité de cette figure
        """
        return self.__visible

    def surface(self) :
        """
        @pre -
        @post la surface (un float) de la figure a été calculé et retournée
        """
        pass            # code non fourni

Cette classe Figure est la classe mère d'un ensemble de classes permettant de représenter des figures géométriques. Chaque figure géométrique est placée à une position (x,y) (centre de gravité) sur l'écran et la classe contient des variables d'instance et des méthodes permettant de manipuler cette figure géométrique (notamment des méthodes permettant d'afficher la figure à l'écran, mais ces méthodes ne sont pas reprises dans les extraits présentés dans cet exercice). Parmi ces figures géométriques, on trouve notamment la classe Rectangle qui hérite de la classe Figure et dont un fragment est repris ci-dessous :

class Rectangle(Figure):

    def __init__(self,longueur,largeur,x,y) :
        """
        @pre longueur et largeur sont des entiers positifs
             x, y sont des entiers représentant des positions sur l'écran
        @post un rectangle dont le centre de gravite est en x,y
              et ayant comme longueur lo et comme largeur la a été créé
        """
        super().__init__(x,y)
        self.longueur = longueur
        self.largeur = largeur

    def __str__(self) :
        return str((self.longueur,self.largeur,self.x,self.y,self.est_visible()))

>>> r = Rectangle(10,20,0,0)
>>> print(r)
(10, 20, 0, 0, False)

Maintenant expliquez :

  • Quelles sont les variables d'instance qu'une instance de la classe Rectangle peut utiliser ?
  • Que se passe-t il lorsqu'une instance r de la classe Rectangle est créé?
  • Que fait l'appel à super() dans la méthode __init__ de la classe Rectangle ?
  • Que se passe-t il si on met cet appel à super() comme dernière instruction dans la méthode __init__ de la classe Rectangle ?
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Dans la classe Rectangle, faut-il redéfinir les méthodes suivantes (si oui, écrivez le code de la nouvelle méthode - si non, expliquez pourquoi ):

  • surface()
 
 
 
 
 
 
 
 

  • est_visible()
 
 
 
 

4.2.5   Variables privés


        
        

4.2.6   Carré

Comment feriez-vous maintenant pour définir une classe Carre qui étend la classe Rectangle et permet de représenter un carré ?

  • Ecrivez la méthode d'initialisation de la classe Carre (un carré se construit en indiquant les coordonnées de son centre de gravité et la longueur de son côté)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

  • Quelles sont les méthodes que vous devez redéfinir dans la classe "Carre" ?
 
 
 
 

  • Soient deux classes Circle et Ellipse. Quelles relations peut-on envisager entre ces deux classes ?
 
 
 
 

  • Ecrivez une méthode perimetre() de la classe Rectangle qui retourne le périmètre du rectangle.
 
 
 
 

  • Que faudrait-il faire pour avoir une méthode perimetre de la classe Carre?
 
 
 
 

4.2.7   Similitude

Définissez une méthode __eq__ pour la classe Figure, telle que deux figures sont égales si leur surface est égale.

 
 
 
 

Que se passe-t il si on veut comparer deux rectangles ayant la même surface? Par exemple:

>>> r1 = Rectangle(10,40,0,0)
>>> r2 = Rectangle(2,200,0,0)
>>> r1 == r2
 
 
 
 

Que se passe-t il si on veut comparer un rectangle avec un carré ayant la même surface? Par exemple:

>>> r = Rectangle(10,40,0,0)
>>> c = Carre(20,0,0)
>>> print(r == c)
 
 
 
 

4.2.8   Variable de classe

Et voici finalement une dernière question pour illustrer l'utilisation d'une variable de classe.

Complétez la classe Ticket ci-dessous:

"""
Un ticket de parking
"""
class Ticket :

    __prochain_numero = 1  # variable de classe pour générer le numéro du ticket

    def __init__(self) :
        """
        @pre  -
        @post Crée un ticket avec un nouveau numéro.
              Les numéros sont attribués séquentiellement à partir de 1.
        """
            # A COMPLETER

    def numero(self):
        """
        @pre  -
        @post retourne le numero de billet
        """
        return self.__numero


        
        

Mission 9 : Héritage

Mission 9 : Héritage

1   Description

Pour cette mission, vous disposez au départ d'un programme simple mission9.py permettant d'imprimer des factures. Ce programme comporte principalement deux classes:

  1. l'une représente un Article, c'est-à-dire une ligne dans la facture (correspondant à l'achat d'un article comme un laptop, ou les frais pour une service comme l'installation d'un réseau wifi);
  2. l'autre représente une Facture sous forme d'une liste d'articles (ou de services) et offre des méthodes permettant de l'imprimer.

Un fichier de test initiale test.py est également fournie. Exécuter ce fichier test produira l'exemple de facture suivant:

Facture PC Store - 22 novembre
===================================================================================
| Description                              |  prix HTVA |        TVA |  prix TVAC |
===================================================================================
| laptop 15" 8GB RAM                       |     743.79 |     156.20 |     899.99 |
| installation windows                     |      66.11 |      13.88 |      79.99 |
| installation wifi                        |      45.22 |       9.50 |      54.72 |
| carte graphique                          |     119.49 |      25.09 |     144.58 |
===================================================================================
| T O T A L                                |     974.61 |     204.67 |    1179.28 |
===================================================================================

Partant de ce code déjà fonctionnel, l'objectif principal de cette mission est de développer des classes qui héritent de la classe Article , en offrant des fonctionnalités supplémentaires tout en restant utilisables par la classe Facture . Dans un deuxième temps, vous ajouterez aussi une méthode à la classe Facture qui exploite ces nouvelles fonctionnalités.

Votre programme final devrait être capable de calculer et générer des factures plus complets comme

Facture No 1 : Facture PC Store - 22 novembre
===================================================================================
| Description                              |  prix HTVA |        TVA |  prix TVAC |
===================================================================================
| laptop 15" 8GB RAM                       |     743.79 |     156.20 |     899.99 |
| installation windows                     |      66.11 |      13.88 |      79.99 |
| installation wifi                        |      45.22 |       9.50 |      54.72 |
| carte graphique                          |     119.49 |      25.09 |     144.58 |
| Réparation (0.75 heures)                 |      46.25 |       9.71 |      55.96 |
| 1 * disque dur 350 GB @ 49.99            |      49.99 |      10.50 |      60.49 |
| 3 * souris bluetooth @ 15.99             |      47.97 |      10.07 |      58.04 |
| 5 * adaptateur DVI - VGA @ 12.00         |      60.00 |      12.60 |      72.60 |
| 2 * Java in a Nutshell @ 24.00           |      48.00 |       2.88 |      50.88 |
| 5 * souris bluetooth @ 15.99             |      79.95 |      16.79 |      96.74 |
===================================================================================
| T O T A L                                |    1306.77 |     267.22 |    1573.99 |
===================================================================================

et des bordereaux de livraison tels que celui-ci

Livraison - Facture No 1 : PC Store - 22 novembre
===================================================================================
| Description                              |  poids/pce |     nombre |      poids |
===================================================================================
| disque dur 350 GB @ 49.99 (!)            |    0.355kg |          1 |    0.355kg |
| souris bluetooth @ 15.99                 |    0.176kg |          3 |    0.528kg |
| adaptateur DVI - VGA @ 12.00             |    0.000kg |          5 |    0.000kg |
| Java in a Nutshell @ 24.00               |    0.321kg |          2 |    0.642kg |
| souris bluetooth @ 15.99                 |    0.176kg |          5 |    0.880kg |
===================================================================================
| 5 articles                               |            |         16 |    2.405kg |
===================================================================================
 (!) *** livraison fragile ***

2   Etapes

Voici les étapes à suivre.

2.1   Fichiers

Chargez les fichiers mission9.py et test.py et étudiez leurs contenus. Vous disposez des classes et fonctions suivants:

  • Article : cette classe représente un article de la facture. Elle contient une description et un prix et offre des méthodes permettant d'obtenir ces données et de calculer le prix de l'article avec TVA. Analysez attentivement le code de cette classe. Remarquez comment les différentes méthodes font appel à la méthode prix() . Ceci est important quand on hérite de cette classe: en redéfinissant la méthode prix() on modifiera aussi indirectement les autres méthodes qui y font appel.
  • Facture : cette classe représente une facture. Elle contient une liste d'articles. Elle offre principalement une méthode __str__ qui retourne un string détaillé représentant la facture, qui peut être imprimé avec la méthode print(), ainsi que plusieurs méthodes auxiliaires utilisées par cette méthode __str__.
  • test_articles(l) : une fonction de test de la classe Article qui imprime une liste d'articles l.
  • test_facture(f) : une fonction de test de la classe Facture qui produit l'impression d'une facture reprise dans le premier exemple ci-dessus.

Vous devrez vous-mêmes créer au moins deux classes ArticleReparation et ArticlePiece qui héritent de la classe Article, une classe Piece (utilisée par la classe ArticlePiece), ainsi que deux méthodes supplémentaires dans Facture , selon les instructions qui suivent.

2.2   La classe ArticleReparation

  • Au fichier mission9.py , ajoutez une nouvelle classe ArticleReparation qui hérite de la classe Article . Cette nouvelle classe représente une prestation de réparation de durée donnée (un float, en heures).

  • Définissez une méthode d'initialisation avec la durée en paramètre.

  • Re-définissez la méthode description() pour fournir un descriptif adéquat comme Reparation (0.75 heures).

  • Re-définissez la méthode prix() pour calculer un coût fixe de 20 euro plus un coût variable de 35 euro/h. Pour une réparation de 0.75 heures ça donne donc un coût de 20 + 35*0.75 = 46.25 euro HTVA.

  • Dans le fichier test.py , ajoutez des tests pour tester cette nouvelle classe et son utilisation dans une facture. Par exemple, vérifiez que la ligne correspondant à une réparation soit affiché comme:

    Facture PC Store - 22 novembre
    ===================================================================================
    | Description                              |  prix HTVA |        TVA |  prix TVAC |
    ===================================================================================
    | ...                                                                             |
    | Réparation (0.75 heures)                 |      46.25 |       9.71 |      55.96 |
    ===================================================================================
    | T O T A L                                |    1020.86 |     214.38 |    1235.24 |
    ===================================================================================
    

2.3   Les classes ArticlePiece et Piece

Créez une nouvelle classe ArticlePiece qui hérite de Article et qui représente l'achat pas d'un seul article mais d'un nombre donné d'une pièce donnée. (Par exemple, 3 souris Bluetooth à 15.99 EUR par pièce.)

Implémentez d'abord une nouvelle classe Piece qui représente la pièce dont on veut facturer plusieurs exemplaires. Elle comporte les données suivantes:

- une description (string), p.ex. 'souris bluetooth';
- un prix unitaire (float), p.ex. 15.99 Euro;

et, optionnellement

- un poids unitaire en kg (float), p.ex. 0,154 kg;
- un indicateur booléen indiquant si la pièce est fragile, p.ex. un disque dur est fragile mais pas une souris;
- un indicateur booléen indiquant si la pièce est à taux de TVA réduit, p.ex. les livres bénéficient de TVA réduite.
  • Ajoutez une méthode d'initialisation permettant d'initialiser toutes ces données. Cette méthode d'initialisation doit aussi être utilisable avec seulement les deux paramètres obligatoires (description et prix) pour les pièces de poids négligeable, non fragiles et à taux de TVA normal (en assignant des valeurs par défaut pour les autres paramètres dans ce cas).
  • Ajoutez des méthodes accèsseurs (description() , prix() , poids() , fragile() , tva_reduit()) pour toutes ces données.
  • Ajoutez une méthode magique __eq__ afin que deux pièces sont considérées égales ( == ) si elles ont la même description et le même prix (les autres données sont ignorées pour la comparaison).

Ensuite implémentez la classe ArticlePiece qui hérite de Article

  • Ajoutez une méthode d'initialisation prenant le nombre et la pièce en paramètres.
  • Ajoutez des méthodes accèsseurs pour ces deux attributs.
  • Re-définissez la méthode description() pour fournir un texte reprenant la description de la pièce, le nombre souhaité de cette pièce et son prix unitaire, par exemple: 3 * souris bluetooth @ 15.99 .
  • Re-définissez la méthode prix() pour faire le produit du prix unitaire de la pièce par le nombre de pièces souhaité.
  • Re-définissez la méthode taux_tva() pour appliquer un taux de 6% aux pièces à taux de TVA réduit, tout en gardant le taux de TVA original pour d'autres pièces.

Finalement, dans le fichier test.py , ajoutez des tests pour tester ces nouvelles classes et leur utilisation dans une facture. Par exemple, vérifiez que les lignes correspondant aux articles pièces soient affichés comme:

Facture PC Store - 22 novembre
===================================================================================
| Description                              |  prix HTVA |        TVA |  prix TVAC |
===================================================================================
| ...                                                                             |
| 3 * souris bluetooth @ 15.99             |      47.97 |      10.07 |      58.04 |
| 2 * Java in a Nutshell @ 24.00           |      48.00 |       2.88 |      50.88 |
| ...                                                                             |
===================================================================================
| T O T A L                                |    1306.77 |     267.22 |    1573.99 |
===================================================================================

2.4   Numérotation des factures

Modifiez la classe Facture pour que chaque nouvelle facture reçoive un numéro séquentiel unique, qui apparait dans l'en-tête de la facture.

2.5   Compter le nombre de pièces

Dans la classe Facture, ajoutez une méthode def nombre(self,pce) qui retourne le nombre d'exemplaires d'une Piece pce dans la facture, en totalisant sur tous les articles qui concernent cette pièce. (Vous pouvez utiliser le fait que le comparateur ``==`` a été redéfinie dans la classe ``Piece`` (via la méthode magique ``__eq__`` que vous avez ajoutée).)

2.6   Bordereau de livraison

Dans la classe Facture, ajoutez une méthode print_livraison() qui imprime un bordereau de livraison comme

Livraison - Facture No 1 : PC store 22 octobre
===================================================================================
| Description                              |  poids/pce |     nombre |      poids |
===================================================================================
| disque dur 350 GB (!)                    |    0.355kg |          1 |    0.355kg |
| souris bluetooth                         |    0.176kg |          3 |    0.528kg |
| adaptateur DVI - VGA                     |    0.000kg |          5 |    0.000kg |
| Java in a Nutshell                       |    0.321kg |          2 |    0.642kg |
| souris bluetooth                         |    0.176kg |          5 |    0.880kg |
===================================================================================
| 5 articles                               |            |         16 |    2.405kg |
===================================================================================
 (!) *** livraison fragile ***

Ce bordereau:

  • imprime une en-tête avec la description de la facture;
  • imprime toutes les pièces dans la facture avec, pour chacune, sa description, son poids unitaire, le nombre facturé et le poids correspondant;
  • ajoute une marque (!) dans la description des pièces fragiles;
  • totalise et imprime à la fin le nombre d'articles, le nombre de pièces et le poids total;
  • imprime un message supplémentaire (!) *** livraison fragile *** si (et seulement si) la livraison contient une ou plusieurs pièces fragiles.

Remarquez que les détails imprimés dans ce bordereau de livraison ne concernent que les articles de type ArticlePiece; les autres articles sont ignorés. Pour faciliter le formatage du texte, vous pouvez utiliser la méthode format, déjà utilisée à plusieurs endroits dans la classe Facture. Si vous ne la connaissez pas, n'hésitez pas à chercher en-ligne comment cette méthode format fonctionne exactement. Pour implémenter la méthode print_livraison() , réutiliser un maximum de méthodes déjà existantes de la classe Facture .

Finalement, modifiez le fichier test.py pour tester votre nouvelle méthode. En particulier, vérifiez qu'un bordereau de livraison soit affiché comme:

Livraison - Facture No 1 : PC Store - 22 novembre
===================================================================================
| Description                              |  poids/pce |     nombre |      poids |
===================================================================================
| disque dur 350 GB @ 49.99 (!)            |    0.355kg |          1 |    0.355kg |
| souris bluetooth @ 15.99                 |    0.176kg |          3 |    0.528kg |
| adaptateur DVI - VGA @ 12.00             |    0.000kg |          5 |    0.000kg |
| Java in a Nutshell @ 24.00               |    0.321kg |          2 |    0.642kg |
| souris bluetooth @ 15.99                 |    0.176kg |          5 |    0.880kg |
===================================================================================
| 5 articles                               |            |         16 |    2.405kg |
===================================================================================
 (!) *** livraison fragile ***

3   Diagramme de classes

Le diagramme de classes suivant résume les différentes classes et méthodes à implémenter lors de cette mission :

/syllabus/info1-exercises/assets/class_diagram_mission9.png

4   Remise de votre solution

Pour cette mission, vous devez soumettre toutes les classes de votre programme dans un seul fichier mission9.py, vos classes tests dans un fichier test.py, ainsi que votre fichier README.txt qui décrit comment on peut tester votre code.

Votre fichier mission9.py doit contenir les classes Facture, Article, ArticleReparation, ArticlePiece et Piece.

Votre fichier test.py doit contenir des tests pour chacune des classes et étappes de cette mission, ainsi qu'une série d'instructions à la fin pour lancer tous les tests automatiquement lors de l'exécution du fichier.

L'exécution de votre programme mission9.py doit imprimer une facture et un bon de livraison comme illustré plus haut dans ce document.


        
        

5   Challenge

Il est possible d'ajouter de multiples variantes d'article à ce programme. Par exemple:

  • étendre ArticlePiece en ArticlePieceGros qui applique une dégression sur les prix en fonction du nombre commandé;
  • ajouter une extension d'Article qui fait référence à une configuration de PC et calcule le prix correspondant (taille mémoire, CPU, écran, capacité disque, etc);
  • étendre ArticleReparation en ArticleReparationUrgente avec des tarifs plus élevés;
  • ajouter une extension d'Article pour des frais de déplacement;
  • ...

On peut également ajouter des calculs supplémentaires sur les factures, par exemple un bilan des frais de main d'oeuvre. Un peu plus difficile, modifier la méthode printLivraison() de la classe Facture pour n'imprimer qu'une seule ligne par pièce qui cumule les articles correspondants, comme dans la méthode nombre() .

Questions complémentaires

Questions complémentaires

1   Variables d'instance

Quelqu'un a programmé une classe Compte représentant un compte bancaire avec 2 attributs privés __titulaire (représentant le titulaire du compte) et __solde (représentant le montant sur le compte, initialement zéro) et 1 attribut publique représentant la banque du compte.

class Compte :

    def __init__(self, banque, titulaire, solde = 0) :
        self.banque = banque
        self.__titulaire = titulaire
        self.__solde = solde

    def banque(self) :
        return self.banque

    def titulaire(self):
        return self.__titulaire

    def solde(self):
        return self.__solde

    def __str__(self) :
        return "Banque: " + self.banque() \
           + " Compte: " + self.titulaire() \
           + " Solde: " + str(self.solde())

a = Compte("ShittyBank","Kim")
print(a)

Malheureusement, quand on exécute l'instruction print(a), une erreur se produit:

Traceback (most recent call last):
  > print(a)
  > print(self.banque())
  > TypeError: 'str' object is not callable

Quel est le problème? Pouvez-vous corriger le code?

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

2   Variable de classe