IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Problème d'appel d'une variable de classe [Python 3.X]


Sujet :

Python

  1. #1
    Membre du Club
    Homme Profil pro
    Sans activité
    Inscrit en
    Novembre 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Sans activité

    Informations forums :
    Inscription : Novembre 2014
    Messages : 23
    Points : 42
    Points
    42
    Par défaut Problème d'appel d'une variable de classe
    Bonjour,

    J'essaye de comprendre le fonctionnement de la POO en python; dans l'exemple suivant, le script est censé afficher la liste ordonnée des clients contenus dans le dictionnaire "client" et l'affichage doit se terminer par le nombre total de clients comptabilisés.
    Bien entendu, l'affichage se fait par l'intermédiaire des méthodes "repr" et "cptr" de ma classe Bank.

    J'arrive au résultat voulu mais j'ai le sentiment que mon code n'est pas optimisé : intégrer "client.values()" dans un tuple pour extraire la première entrée de mon dictionnaire afin de faire appel à ma méthode "cptr", ça marche mais je suis sur qu'il doit exister méthode plus efficace pour y parvenir.

    Une autre piste que j'ai explorée sans parvenir au résultat voulu était de lancer "cptr" depuis "repr".

    (Pour info : dans ce contexte, on considère que le code ne connait pas les clés du dictionnaire à l'avance; ils sont ici affichés afin d'illustrer mon propos).

    Merci pour vos avis...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    class Bank:
     
        compteur = 0
        def __init__(self, nom=" X Client X", bal=0):
            self._nom = nom
            self._balance = bal
            Bank.compteur += 1
     
     
        def __repr__(self):
            return "Nom client : {}  - solde : {}€".format(self._nom, self._balance)
     
     
        def cptr(self):
            print("Nombre de clients : {}".format(Bank.compteur))
     
     
    client = {}
     
    client["c1"] = Bank("c1", 100)
    client["c2"] = Bank("c2", 50)
    client["c3"] = Bank("c3", 10)
    client["c4"] = Bank("c4", 200)
     
    from operator import attrgetter as ag
    aa = sorted(client.values(), key=ag("_nom"))
    print()
    [print(i) for i in aa]
     
    aa = tuple(client.keys())
    bb = aa[0]
    client[bb].cptr()

  2. #2
    Membre éprouvé
    Homme Profil pro
    Aucune activité
    Inscrit en
    Novembre 2011
    Messages
    505
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Aucune activité

    Informations forums :
    Inscription : Novembre 2011
    Messages : 505
    Points : 926
    Points
    926
    Par défaut
    Citation Envoyé par Laudec Voir le message
    J'arrive au résultat voulu mais j'ai le sentiment que mon code n'est pas optimisé : intégrer "client.values()" dans un tuple pour extraire la première entrée de mon dictionnaire afin de faire appel à ma méthode "cptr", ça marche mais je suis sur qu'il doit exister méthode plus efficace pour y parvenir.
    Bonsoir,
    Et avec "@classmethod"?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        @classmethod
        def cptr(cls):
            print("Nombre de clients : {}".format(cls.compteur))
    Puis:
    Non?

    Clodion

    PS: perso, je remplacerais les lignes 26 à 33 par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    print(*[client[k] for k in sorted(client.keys())], sep="\n")
    Bank.cptr()

  3. #3
    Membre du Club
    Homme Profil pro
    Sans activité
    Inscrit en
    Novembre 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Sans activité

    Informations forums :
    Inscription : Novembre 2014
    Messages : 23
    Points : 42
    Points
    42
    Par défaut
    ben... si !
    Ca marche correctement, merci Clodion.

    Je vais regarder tout ça de plus près, je ne connais pas encore le concept de décorateur, une bonne opportunité pour apprendre.
    Merci pour le PS également, je vais commencer par décrypter ça; ça me semble déjà plus à ma portée.

  4. #4
    Membre éprouvé
    Homme Profil pro
    Aucune activité
    Inscrit en
    Novembre 2011
    Messages
    505
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Aucune activité

    Informations forums :
    Inscription : Novembre 2011
    Messages : 505
    Points : 926
    Points
    926
    Par défaut
    Citation Envoyé par Laudec Voir le message
    Je vais regarder tout ça de plus près, je ne connais pas encore le concept de décorateur, une bonne opportunité pour apprendre.
    Bonsoir,
    Oui!! Mais là c'est le plus aisé!!
    C'est juste pour déclarer que cette méthode se réfère à la classe plutôt qu'à l'instance (on met cls à la place de self pour ne pas confondre)! Et donc, cette méthode ne peut pas utiliser les variables des instances!!

    Clodion

  5. #5
    Membre du Club
    Homme Profil pro
    Sans activité
    Inscrit en
    Novembre 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Sans activité

    Informations forums :
    Inscription : Novembre 2014
    Messages : 23
    Points : 42
    Points
    42
    Par défaut
    Citation Envoyé par Clodion Voir le message
    Bonsoir,
    Oui!! Mais là c'est le plus aisé!!
    C'est juste pour déclarer que cette méthode se réfère à la classe plutôt qu'à l'instance (on met cls à la place de self pour ne pas confondre)! Et donc, cette méthode ne peut pas utiliser les variables des instances!!

    Clodion
    Pigé ! en tout cas pour ce cas de figure, l'explication est limpide.

    J'en profite pour te demander quelques compléments d'information sur cette ligne de code que tu proposes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print(*[client[k] for k in sorted(client.keys())], sep="\n")
    cette méthode n'est valable que pour faire un tri par le nom du client, n'est ce pas ?
    si, je dois, par la suite, afficher la liste de mes clients selon le solde de leur compte en banque, je suis obligé de passer par client.values()... ou bien je me trompe ?

    D'autre part, personnellement j'intègre ma fonction print dans ma liste en intention, comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    [print(client[k]) for k in sorted(client.keys())]
    les résultats sont identiques à l'affichage.

    Est ce que ta méthode est optimisée par rapport à la mienne ?

    Merci

  6. #6
    Membre régulier
    Homme Profil pro
    Amateur
    Inscrit en
    Juin 2015
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Amateur
    Secteur : Transports

    Informations forums :
    Inscription : Juin 2015
    Messages : 52
    Points : 94
    Points
    94
    Par défaut
    Salut,

    Je pense que ta classe n'est pas vraiment bien conçue. Le nom de la classe est Bank, hors tu crées des clients avec... Je te propose ce code qui est un exemple d'une classe banque à laquelle on peut ajouter des clients. L'exemple est bien entendu peu réaliste, mais c'est pour te montrer comment aborder la chose. Tout ce qui est compliqué (comme retourner la liste des clients triés par nom avec leur solde) est implémenté dans la classe. Le client (ton code utilisant cette classe) lui ne doit pas se tracasser de ces détails. Il se contente d'appeler les méthodes pour faire le sale boulot.

    On aurait bien entendu pu utiliser un OrderedDict pour garder les clients triés par nom. Mais le but ici est de montrer comment la classe peut cacher ces détails d'implémentation. D'ailleurs si demain on voulait utiliser cet OrderedDict, les méthodes resteraient les même, et le client ne verrait aucune différence (à part peut-être un gain en performance).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    class Bank:
        "Une banque contenant des clients et un compte en banque."
        def __init__(self, nom="Banque X"):
            self.nom = nom
            self.clients = {}
     
        def ajout_client(self, nom="X Client X", balance=0):
            "Ajoute un client portant un nom et avec une somme sur le compte."
            self.clients[nom] = balance
     
        def __str__(self):
            return "Banque: {} - nombre de clients : {}".format(self.nom, len(self.clients))
     
        def nbre_clients(self):
            "Retourne le nombre de clients dans cette banque."
            return len(self.clients)
     
        def list_clients_sorted(self):
            """Générateur qui retourne une chaînes de caractères contenant les noms 
            des clients et leur solde classée par nom de client.
     
            Exemple: "client X - 150 €", "..."
            """
            list_clients = sorted(self.clients.keys())
            for client in list_clients:
                yield "{0} - {1} €".format(client, self.clients[client])
     
     
    if __name__ == '__main__':
        banque = Bank("La banque qui assure")
        banque.ajout_client("c1", 100)
        banque.ajout_client("c2", 50)
        banque.ajout_client("c3", 10)
        banque.ajout_client("c4", 120)
     
        print("Informations sur la banque {}".format(banque))
        print("Voici la liste des clients de la banque '{}' triée par nom.\n".format(banque.nom))
        print("\n".join(banque.list_clients_sorted()))

  7. #7
    Membre éprouvé
    Homme Profil pro
    Aucune activité
    Inscrit en
    Novembre 2011
    Messages
    505
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Aucune activité

    Informations forums :
    Inscription : Novembre 2011
    Messages : 505
    Points : 926
    Points
    926
    Par défaut
    Citation Envoyé par Laudec Voir le message
    J'en profite pour te demander quelques compléments d'information sur cette ligne de code que tu proposes :
    cette méthode n'est valable que pour faire un tri par le nom du client, n'est ce pas ?
    Bonsoir,
    Oui, c'est exacte!

    Citation Envoyé par Laudec Voir le message
    si, je dois, par la suite, afficher la liste de mes clients selon le solde de leur compte en banque, je suis obligé de passer par client.values()
    Pas tout à fait! Enfin, si!
    Il faut obligatoirement passer par "client.values()" puisque c'est un dictionnaire et que c'est sur ces termes que sont stockées les Bank (et donc les "_balance")…

    Il est aussi possible d'ajouter une méthode renvoyant la valeur de "_balance".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        def val(self):
            return self._balance
    puis:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    lst = [v for v in client.values()] # pour la liste des Bank
    lst = sorted(lst, key=lambda x: x.val()) # val pour récupérer "_balance"
    print(*lst, sep="\n")
    ou bien:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    print(*sorted([v for v in client.values()], key=lambda x: x.val()), sep="\n")
    Et il doit bien exister d'autres manières de faire!!

    Citation Envoyé par Laudec Voir le message
    Est ce que ta méthode est optimisée par rapport à la mienne ?
    J'avoue ne pas trop savoir. Il faudrait tester.
    Instinctivement, je pencherais pour éviter des entrées/sorties dans les listes par intention… Mais bon, sans essayer…

    Clodion

    PS: je n'avais pas vu le message de Dan737: Mais tout à fait d'accord avec ses commentaires!

  8. #8
    Membre du Club
    Homme Profil pro
    Sans activité
    Inscrit en
    Novembre 2014
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Sans activité

    Informations forums :
    Inscription : Novembre 2014
    Messages : 23
    Points : 42
    Points
    42
    Par défaut
    Merci à tous les deux pour vos éclaircissements...

    Inutile de vous préciser que j'ai débuté en python très récemment et que ce petit exercice était censé faire le bilan de mes connaissances sur la POO; à la lecture de la proposition de Dan, j'ai le sentiment d'être complètement hors du coup, pourtant ma solution semblait cohérente par rapport aux ressources à ma disposition (et à mon niveau) pour apprendre ce langage (tuto et ebook sur internet).

    Du coup, selon vous, quelle est la méthode la plus efficace pour apprendre le python ? (sachant que je fais ça par passion uniquement et sans contrainte scolaire ou professionnelle)

  9. #9
    Membre éprouvé
    Homme Profil pro
    Aucune activité
    Inscrit en
    Novembre 2011
    Messages
    505
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Aucune activité

    Informations forums :
    Inscription : Novembre 2011
    Messages : 505
    Points : 926
    Points
    926
    Par défaut
    Citation Envoyé par Laudec Voir le message
    Du coup, selon vous, quelle est la méthode la plus efficace pour apprendre le python ? (sachant que je fais ça par passion uniquement et sans contrainte scolaire ou professionnelle)
    Bonjour,
    L'un (ou le) meilleur tutoriel est, à ma connaissance, celui de G.Swinenn, disponible gratuitement, en français, sur developpez.

    Clodion

  10. #10
    Membre régulier
    Homme Profil pro
    Amateur
    Inscrit en
    Juin 2015
    Messages
    52
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Amateur
    Secteur : Transports

    Informations forums :
    Inscription : Juin 2015
    Messages : 52
    Points : 94
    Points
    94
    Par défaut
    Tu n'es pas complètement à côté du sujet. Tu débutes, et tu fais des erreurs. Et c'est très bien de venir demander l'avis d'autres personnes pour pouvoir t'améliorer. Tu as la bonne attitude, il te manque juste un peu de pratique. C'est normal de ne pas tout faire parfaitement dès le début. Moi aussi j'ai fait des classes qui n'avaient ni queue ni tête à mes débuts. Et je continue à écrire des absurdités.

    Je vois une classe un peu comme un sac de variables avec des fonctions attachées qui peuvent manipuler ces variables. C'est un peu une manière de regrouper ensemble ce qui est cohérent.

    Pour prendre un simple exemple, on pourrait imaginer reproduire un jeu de carte. Une carte en elle-même contient des variables (la valeur de la carte et sa couleur). Pour les fonctions, je ne vois pour le moment d'utile qu'une fonction de comparaison qui permet de demander à une carte si sa valeur est plus grande ou plus petite qu'une autre carte. Et encore... Car la comparaison de deux cartes dépend du jeu auquel on joue. Donc tout bien réfléchi, je pense qu'il ne faut que deux variables: valeur et couleur. Vu qu'il n'y a pas de méthode, autant ne pas faire une classe, mais utiliser tout de suite un tuple, ou encore mieux un namedtuple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    from collections import namedtuple
     
    Carte = namedtuple('Carte', 'valeur, couleur')
    as_pique = Carte(valeur='As', couleur='Pique')
    Ensuite il y a le deck de cartes. Celui-ci doit avoir un conteneur pouvant contenir des instances de cartes. Disons que ce conteneur est une liste, car une liste est un objet mutable (on peut ajouter, enlever des éléments, ...) où l'ordre est maintenu (ben oui les cartes sont dans un ordre précis).

    Le deck pourrait avoir des méthodes comme créer nouveau jeu qui remplirait notre liste avec les 13 valeurs et 4 couleurs (52 cartes). Donc c'est le deck qui connait les valeurs et couleurs possibles des cartes. On pourrait avoir une méthode pour mélanger le deck, puis une méthode pour tirer une carte et une méthode pour comparer deux cartes.

    Le client de ce code ne doit pas se tracasser de savoir si en interne le deck est une liste de cartes, ou autre chose. Tout ce que le client doit voir, c'est qu'on peut créer un nouveau jeu de carte, le mélanger et demander des cartes. Il doit y avoir un comportement prévisible si le deck est vide alors qu'on demande une carte (probablement lancer une exception).

    Ce serait peut-être un bon exercice de crée un simple jeu de carte.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XL 2000] problème d'appel d'une variable
    Par Kelaydos dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 03/09/2012, 13h44
  2. Réponses: 2
    Dernier message: 24/03/2009, 09h09
  3. problème d'appel d'une fonction d'une autre classe
    Par kifouillou dans le forum Langage
    Réponses: 5
    Dernier message: 08/02/2007, 17h42
  4. Réponses: 2
    Dernier message: 11/09/2006, 12h22
  5. Problème d'appels d'une variable entre fonctions
    Par julien.nasser dans le forum MFC
    Réponses: 12
    Dernier message: 26/04/2006, 09h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo