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 :

Conseils Programmation Orientée Objet


Sujet :

Python

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2013
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Août 2013
    Messages : 25
    Points : 10
    Points
    10
    Par défaut Conseils Programmation Orientée Objet
    Bonjour,
    Je souhaite créer une interface pour gérer une petite base de donnée.
    Je ne connais pas bien la programmation en général et encore moins celle orientée objet.
    J'aimerai donc avoir l'avis de spécialiste pour me guider et me remettre dans le droit chemin,
    pour optimiser le code et qu'il soit correctement "orienté objet"
    Merci

    J'ai commencé à écrire ceci :

    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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
     
    import sqlite3
    import tkinter as tk
    from tkinter import ttk
    import locale
     
     
    locale.setlocale(locale.LC_TIME, '')
     
     
    idselect = 0
     
    SIZED = "1300x600"
    color = 'grey40'
     
     
    class Window(tk.Toplevel):
        def __init__(self, parent):
            super().__init__(parent)
     
            self.geometry(SIZED)
            self.title('Consignes en cours')
            self.iconbitmap("Images/flower.ico")
            self.configure(bg=color)
            self.columnconfigure(1, weight=1)
            self.rowconfigure(5, weight=1)
     
            def vidertreeview():
                for i in tree.get_children():
                    tree.delete(i)
     
            def razed():
                effacer_champs()
                cbb_rech.delete(0, tk.END)
                affiche()
     
            # afficher bdd
            def affiche():
                conn = sqlite3.connect("ConsigneDB.db")
                cur = conn.cursor()
                select = cur.execute("select * from TConsignes")
                vidertreeview()
     
                for row in select:
                    tree.insert("", tk.END, value=row)
     
                conn.close()
     
            def effacer_champs():
                e_date.config(text="")
                e_soff.config(text="")
                e_objet.config(text="")
                e_objet2.config(text="")
                e_type.config(text="")
                e_consigne.config(text="")
                e_vu.config(text="")
                e_prevu.config(text="")
                e_cloture.config(text="")
     
            def supprimer():
                idsel = tree.item(tree.selection())['values'][0]
                conn = sqlite3.connect("ConsigneDB.db")
                cur = conn.cursor()
                delete = cur.execute("delete from TConsignes where id = {}".format(idsel))
                conn.commit()
                conn.close()
                tree.delete(tree.selection())
     
            def trier():
                vidertreeview()
                conn = sqlite3.connect("ConsigneDB.db")
                cur = conn.cursor()
                select = cur.execute("select * from TConsignes order by Soff desc")
                conn.commit()
                for row in select:
                    tree.insert("", tk.END, value=row)
     
                conn.close()
     
            def recherche(event):
                vidertreeview()
                servrech = cbb_rech.get()
                conn = sqlite3.connect("ConsigneDB.db")
                cur = conn.cursor()
                select = cur.execute("select * from TConsignes where Objet = (?)", (servrech,))
                conn.commit()
                for row in select:
                    tree.insert("", tk.END, values=row)
                conn.close()
     
            def treevisu(event):
                # gestion des entry,  ?? Faire boucle ??
                e_date.config(text=tree.item(tree.selection())['values'][1])
                e_soff.config(text=tree.item(tree.selection())['values'][2])
                e_objet.config(text=tree.item(tree.selection())['values'][3])
                e_objet2.config(text=tree.item(tree.selection())['values'][4])
                e_type.config(text=tree.item(tree.selection())['values'][5])
                e_consigne.config(text=tree.item(tree.selection())['values'][6])
                e_vu.config(text=tree.item(tree.selection())['values'][7])
                e_prevu.config(text=tree.item(tree.selection())['values'][8])
                e_cloture.config(text=tree.item(tree.selection())['values'][9])
     
            # ---------------------------------------------------------------------- gestion frame
            f_rech = tk.Frame(self, padx=5, bg=color)
            f_rech.grid(row=1, column=0, columnspan=4, padx=0, pady=0, sticky="ew")
     
            ftree = tk.Frame(self, bg=color)
            ftree.grid(row=2, column=0, columnspan=4, padx=0, pady=0, sticky="ew")
     
            f_bouton = tk.Frame(self, padx=5, bg=color)
            f_bouton.grid(row=3, column=0, columnspan=4, padx=0, pady=0, sticky="ew")
     
            f_entry = tk.Frame(self, padx=10, bg=color)
            f_entry.grid(row=4, column=0, columnspan=4, padx=0, pady=0, sticky="ew")
            # ---------------------------------------------------------------------- Construction Titre
            lbl_titre = tk.Label(self, text="-----   Consignes   -----",
                                 bg="grey40",
                                 fg="black",
                                 font=("calibri", 40, "bold"))
            lbl_titre.grid(row=0, column=0, columnspan=6, padx=0, pady=0, sticky="ew")
            # ---------------------------------------------------------------------- Construction Label Info
            lbl_date = tk.Label(f_entry, text="Date : ", bg=color, width=20)
            lbl_date.grid(row=0, padx=5, pady=5)
            e_date = tk.Label(f_entry, bg=color, width=20)
            e_date.grid(row=0, column=1, padx=5, pady=5)
     
            lbl_soff = tk.Label(f_entry, text="Soff : ", bg=color, width=20)
            lbl_soff.grid(row=1, column=0, padx=5, pady=5)
            e_soff = tk.Label(f_entry, bg=color, width=20)
            e_soff.grid(row=1, column=1, padx=5, pady=5)
     
            lbl_objet = tk.Label(f_entry, text="Objet : ", bg=color, width=20)
            lbl_objet.grid(row=2, padx=5, pady=5)
            e_objet = tk.Label(f_entry, bg=color, width=20)
            e_objet.grid(row=2, column=1, padx=5, pady=5)
     
            lbl_objet2 = tk.Label(f_entry, text="Objet2 : ", bg=color, width=20)
            lbl_objet2.grid(row=3, padx=5, pady=5)
            e_objet2 = tk.Label(f_entry, bg=color, width=20)
            e_objet2.grid(row=3, column=1, padx=5, pady=5)
     
            lbl_type = tk.Label(f_entry, text="Type : ", bg=color, width=20)
            lbl_type.grid(row=4, padx=5, pady=5)
            e_type = tk.Label(f_entry, bg=color, width=20)
            e_type.grid(row=4, column=1, padx=5, pady=5)
     
            lbl_consigne = tk.Label(f_entry, text="Consigne : ", bg=color, width=20)
            lbl_consigne.grid(row=0, column=4, padx=5, pady=5)
            e_consigne = tk.Label(f_entry, bg=color, width=20)
            e_consigne.grid(row=0, column=5, padx=5, pady=5)
     
            lbl_vu = tk.Label(f_entry, text="Vu : ", bg=color, width=20)
            lbl_vu.grid(row=1, column=4, padx=5, pady=5)
            e_vu = tk.Label(f_entry, bg=color, width=20)
            e_vu.grid(row=1, column=5, padx=5, pady=5)
     
            lbl_prevu = tk.Label(f_entry, text="Prevu : ", bg=color, width=20)
            lbl_prevu.grid(row=2, column=4, padx=5, pady=5)
            e_prevu = tk.Label(f_entry, bg=color, width=20)
            e_prevu.grid(row=2, column=5, padx=5, pady=5)
     
            lbl_cloture = tk.Label(f_entry, text="Cloture : ", bg=color, width=20)
            lbl_cloture.grid(row=3, column=4, padx=5, pady=5)
            e_cloture = tk.Label(f_entry, bg=color, width=20)
            e_cloture.grid(row=3, column=5, padx=5, pady=5)
     
            # -------------------------------------------------------------------------- place treeview
            treescroll = ttk.Scrollbar(ftree)
            treescroll.grid(row=0, column=1, sticky="ns")
     
            style = ttk.Style()
            style.theme_use('clam')
            style.configure("mystyle.Treeview.Heading", font=('Calibri', 16, 'bold'))  # Modify the font of the headings
            style.configure("mystyle.Treeview", rowheight=50, font=('Calibri', 12))
     
            tree = ttk.Treeview(ftree, style="mystyle.Treeview", yscrollcommand=treescroll.set, columns=
            ("N°",
             "Date",
             "Soff",
             "Objet",
             "Objet2",
             "Type",
             "Consigne",
             "Vu",
             "Prevu",
             "Cloture"),
              height=8)
     
            tree.column("#0", width=5, minwidth=1)
            tree.heading("#0", text="", anchor="w")
            tree.column("N°", width=30, minwidth=10, stretch=True)
            tree.heading("N°", text="N°", anchor="w")
            tree.column("Date", width=100, minwidth=100, stretch=False)
            tree.heading("Date", text="Date", anchor="w")
            tree.column("Soff", width=100, minwidth=100, stretch=False)
            tree.heading("Soff", text="Soff", anchor="w", command=trier)
            tree.column("Objet", width=100, minwidth=50, stretch=False)
            tree.heading("Objet", text="Objet", anchor="w")
            tree.column("Objet2", width=100, minwidth=50, stretch=False)
            tree.heading("Objet2", text="Objet2", anchor="w")
            tree.column("Type", width=100, minwidth=50, stretch=False)
            tree.heading("Type", text="Type", anchor="w")
            tree.column("Consigne", width=400, minwidth=50, stretch=False)
            tree.heading("Consigne", text="Consigne", anchor="w")
            tree.column("Vu", width=100, minwidth=50, stretch=False)
            tree.heading("Vu", text="Vu", anchor="w")
            tree.column("Prevu", width=100, minwidth=50, stretch=False)
            tree.heading("Prevu", text="Prevu", anchor="w")
            tree.column("Cloture", width=100, minwidth=50, stretch=True)
            tree.heading("Cloture", text="Cloture", anchor="w")
     
            tree.bind("<<TreeviewSelect>>", treevisu)
            tree.grid(row=0, column=0, padx=5, pady=5, sticky="ew")
            affiche()
            # Config scrollbar
            treescroll.config(command=tree.yview)
            # ----------------------------------------------------------------- creation des boutons
     
            b_supprimer = tk.Button(f_bouton, text="Supprimer", padx=20, command=supprimer)
            b_supprimer.grid(row=0, column=1, padx=5)
            b_trier = tk.Button(f_bouton, text="Trier par Nom", padx=20, command=trier)
            b_trier.grid(row=0, column=2, padx=5)
            b_raz = tk.Button(f_bouton, text="RAZ", padx=20, command=razed)
            b_raz.grid(row=0, column=3, padx=5)
     
            # ----------------------------------------------------------------- Recherche par critere
            choixservice = []
     
            def creationservice():
                conn = sqlite3.connect("ConsigneDB.db")
                cur = conn.cursor()
                select = cur.execute("SELECT  Service FROM TServices ORDER BY Service")
                for name in select:
                    choixservice.append(name[0])
                conn.close()
     
            creationservice()
            l_recherche = tk.Label(f_rech, text="Recherche par Service :", padx=10)
            l_recherche.grid(row=0, column=1, padx=5, pady=5)
            cbb_rech = ttk.Combobox(f_rech, values=choixservice)
            cbb_rech.bind("<<ComboboxSelected>>", recherche)
            cbb_rech.grid(row=0, column=2, padx=5, pady=5)

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 273
    Points : 36 757
    Points
    36 757
    Par défaut
    Salut,

    Pour faire de la programmation orientée objets il faut d'abord définir les objets qui vont mériter d'être construits en tant que "class". Ce qui est un travail de conception bien en amont de la programmation.

    Fonctionnellement, la POO n'apporte rien: le code fera aussi bien le boulot avec que sans.

    La POO n'a rien à voir avec Python (et vous avez des rubriques ad hoc pour apprendre à concevoir orienté objets). Ce qui est spécifique à Python, c'est comment on crée un objet (avec "class") et comment on hérite de... et c'est décrit dans tous les bons tutos.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 677
    Points : 30 965
    Points
    30 965
    Billets dans le blog
    1
    Par défaut
    Salut
    Citation Envoyé par cegehi Voir le message
    J'aimerai donc avoir l'avis de spécialiste pour me guider et me remettre dans le droit chemin, pour optimiser le code et qu'il soit correctement "orienté objet"
    Comme dit wiztricks, la POO n'est qu'une façon de programmer. Si par exemple tu veux claculer la circonférence et la surface d'un cercle, tu pourras parfaitement créer une fonction à laquelle tu passes le rayon et elle te renvoie le calcul de la circonférence, et une autre à laquelle tu passes aussi le rayon et elle te renvoie la surface.
    Comme tu remarques que le rayon est utilisé plusieurs fois (et risque de l'être encore si tu veux une autre fonction qui calcule autre chose pour ton cercle), tu peux alors créer un objet "cercle" qui contient un attribut "rayon" et deux méthodes "surface()" et "circonference()" - Le travail est alors plus complexe mais en retour tu obtiens un truc plus facilement utilisable.

    Donc l'objet n'est pas un but en lui-même, seulement un outil. Si le code est correctement conçu il en ira de même pour l'objet...

    Or en programmation dite "complexe" (quand on fait intervenir de l'IHM associée à de la bdd) on a alors l'habitude de bien séparer les choses. Ce qui a trait à l'IHM ne fait alors que de l'IHM. Et ce qui a trait à la bdd ne fait alors que la bdd (méthode "MVC" => Modèle, Vue, Contrôleur). Le Modèle c'est tout ce qui est stockage des données (ici bdd). La Vue c'est tout ce qui est saisie/affichage et le Contrôleur c'est tout ce qui a trait au calculs des valeurs connues pour produire des résultats. Ainsi cela permet de ne pas rester prisonnier d'une technologie (les bdd évoluent, les IHM aussi).
    Si on applique ce principe à ton code, alors on verra apparaitre deux objets. Le premier dédié à la bdd (connexion) et l'autre dédié à l'affichage. Ainsi ta méthode affiche() pourra recevoir en paramètre l'identifiant de la bdd ce qui lui évitera de devoir gérer la connexion. Là ça donnera quelque chose de plus indépendant donc plus facilement maintenable/évolutif....
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  4. #4
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2013
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Août 2013
    Messages : 25
    Points : 10
    Points
    10
    Par défaut
    @ wiztricks

    Merci pour votre réponse, même si ce n'est pas celle que j’espérais.
    J'ai bien compris ce que vous m'expliquez.
    L'utilisation du "self" n'est pas claire pour moi, malgré ce que j'ai pu lire ça et là.
    J'aurai donc souhaité à partir de ce que j'ai pu faire,voir et essayer de comprendre ce que cela aurait donné, afin de m'en inspirer pour la suite.

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 273
    Points : 36 757
    Points
    36 757
    Par défaut
    Citation Envoyé par cegehi Voir le message
    J'aurai donc souhaité à partir de ce que j'ai pu faire,voir et essayer de comprendre ce que cela aurait donné, afin de m'en inspirer pour la suite.
    J'avais bien compris.
    Cependant, vous avez de bons tutos à disposition avec des exemples et des exercices corrigés.

    Le problème avec la compréhension de quelque chose est qu'il y a toujours plusieurs solutions et des arbitrages à faire selon des critères non-techniques. Ce qui exclut de recopier le truc qui marche sans comprendre pourquoi ça marche ni pourquoi on a écrit ça comme çà plutôt qu'autrement.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  6. #6
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2013
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Août 2013
    Messages : 25
    Points : 10
    Points
    10
    Par défaut
    @ Sve@r
    Merci,
    Votre réponse correspond plus à ce que j’espérai.
    Je n'ai pas encore acquit cette façon de réfléchir.
    Il n'y a rien d'évident pour moi de définir comme "propriété" de l'objet cercle, le diamètre et la circonférence. Alors que quand je l'écris en ce moment cela parait évident.
    Circonférence et diamètre sont pour moi ( ou plutôt était, maintenant) le résultat de calcul à partir des propriétés du cerce.
    Mais je pense avoir intégré le concept. Dans le cas du cercle ça va mais pour le cas de l'affichage j'ai plus de mal.
    J'avais bien vu en "codant" qu'il fallait que je sépare l'interface de la gestion de la bdd mais ce n'est pas si simple pour moi.
    J'ai souvent l'impression de faire des usines à gaz alors que je sait qu'il y a bien mieux à faire.
    Si ce n'est pas trop abusé pourriez vous me donner les grandes lignes de ce que pourrait donner la méthode affiche

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 677
    Points : 30 965
    Points
    30 965
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par cegehi Voir le message
    L'utilisation du "self" n'est pas claire pour moi, malgré ce que j'ai pu lire ça et là.
    Le "self" correspond à l'instance de l'objet vue depuis l'intérieur de l'objet
    Imagine un objet "cercle" avec un attribut "rayon". Si tu crées deux variables de type "cercle"...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    vA=cercle(5)
    vB=cercle(10)
    ... comment faire pour que la valeur "5" soit associée à vA et la valeur "10" à vB ? Il faut que d'une manière ou d'une autre, l'objet "cercle "connaisse vA ou vB - Cela se fait au travers du premier paramètre de toutes les méthodes de l'objet qui récupèrent l'instance qui a créé ledit objet - Et on nomme ce paramètre "self" par convention.
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class cercle:
    	def __init__(self, rayon):
    		self.rayon=rayon

    Citation Envoyé par cegehi Voir le message
    Si ce n'est pas trop abusé pourriez vous me donner les grandes lignes de ce que pourrait donner la méthode affiche
    Hum... un truc de ce style
    Code python : 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
    class cBdd:
    	def __init__(self, nomBdd):
    		self.nomBdd=nomBdd
     
    	def connect(self):
    		self.conn=sqlite3.connect(self.nomBdd)
     
    	def select(self, req):
    		cur=self.conn.cursor()
    		res=cur.execute(req)
    		cur.close()
    		return res
    	# select()
    # class cBdd
     
    class Window(tk.Toplevel):
    	def __init__(self, parent):
    		super().__init__(parent)
    		...
     
    	def affich(self, bdd)
    		self.viderTreeView()
    		for row in bdd.select(" (la requête) "):
    			tee.insert("", tk.END, value=row)
    	# affich()
     
    bdd=cBdd("ConsigneDB.db")
    bdd.connect()
     
    w=Window(...)
    w.affich(bdd)
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  8. #8
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2013
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Vienne (Poitou Charente)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Août 2013
    Messages : 25
    Points : 10
    Points
    10
    Par défaut
    @sve@r
    Merci pour l'attention que vous m'avez accordé.
    Cela répond clairement à ma demande initiale
    Je vais travailler pour essayer de structurer mon code dans ce sens.
    Ce n'est peut être pas très utile pour un petit programme mais cela sera certainement indispensable pour des projets plus important.

  9. #9
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 661
    Points : 5 224
    Points
    5 224
    Par défaut
    Ma maitrise de python est loin d'égaler celle de Sve@r ou wiztricks mais je souhaiterai intervenir sur cette phrase qui concerne la POO.

    Citation Envoyé par cegehi Voir le message
    @ Sve@r
    Il n'y a rien d'évident pour moi de définir comme "propriété" de l'objet cercle, le diamètre et la circonférence. Alors que quand je l'écris en ce moment cela parait évident.
    Circonférence et diamètre sont pour moi ( ou plutôt était, maintenant) le résultat de calcul à partir des propriétés du cerce.
    Je conçois que ce n'est pas évident mais en fait les deux versions sont acceptables selon la façon dont on voit les choses.
    On peux considérer que circonférence et diamètre sont des calculs effectués à partir du rayon et donc n'avoir qu'une propriété rayon et deux méthodes pour faires les deux calculs.
    Mais on peux également considérer que circonférence et diamètre sont des propriétés dans la mesure où leurs appels renverra toujours le même résultat.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Cercle1:
        def __init__(self, rayon):
            self.rayon = rayon
     
        def diametre(self):
            return self.rayon * 2
     
    class Cercle2:
        def __init__(self, rayon):
            self.rayon = rayon
            self.diametre = rayon * 2

    Personnellement, je choisirai la second option, voire une autre version plus à mon gout (reste à voir si Sve@r et wiztricks approuvent).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Cercle3:
        def __init__(self, rayon):
            self.__rayon = rayon
            self.__diametre = rayon * 2
     
        @property
        def rayon(self):
            return self.__rayon
     
        @property
        def diametre(self):
            return self.__diametre

  10. #10
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 677
    Points : 30 965
    Points
    30 965
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par popo Voir le message
    Personnellement, je choisirai la second option.
    Ca dépend de pas mal de facteurs (a-t-on besoin du diamètre quand on a le rayon? ce diamètre est-il facilement calculable ou vaut-il mieux consommer un peu de mémoire ?). Ces facteurs sont bien entendu applicables d'autres concepts plus complexes. A chaque problème on verra ces questions revenir sous une forme ou une autre.

    Mais si on part dans l'idée "calcul", on peut alors cacher le diamètre derrière une fonction sans le montrer...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Cercle:
        diametre=property(lambda self: self.rayon * 2)
        def __init__(self, rayon):
            self.rayon = rayon
     
    xxx=Cercle(5)
    print(xxx.diametre)          # pas de parenthèses, on l'utilise comme un attribut !!!
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 661
    Points : 5 224
    Points
    5 224
    Par défaut
    Cette façon de faire ne me plait pas trop parce que je ne peux pas réutiliser le diamètre ailleurs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Cercle4:
        diametre = property(lambda self: self.rayon * 2)
        perimetre = property(lambda self: diametre * pi) #diametre est inconnu
        def __init__(self, rayon):
            self.__rayon = rayon

  12. #12
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 677
    Points : 30 965
    Points
    30 965
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par popo Voir le message
    perimetre = property(lambda self: diametre * pi) #diametre est inconnu
    perimetre = property(lambda self: self.diametre * pi) #et voilà !!!
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 273
    Points : 36 757
    Points
    36 757
    Par défaut
    Salut,

    Citation Envoyé par popo Voir le message
    Mais on peux également considérer que circonférence et diamètre sont des propriétés dans la mesure où leurs appels renverra toujours le même résultat.
    Avec Python on a juste des attributs et pas vraiment de différence entre propriété et méthodes (puisqu'une propriétés peut être associée à une méthode...).

    Après concernant le Cercle, la question de base est de savoir si on veut pouvoir changer le rayon du cercle et d'arbitrer entre une mouture mutable (mise à jour du diamètre) ou non mutable (on crée un nouveau cercle avec son diamètre). Et si on ne répond pas à cette question on va créer un truc entre les deux qui pourra poser problèmes.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  14. #14
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 661
    Points : 5 224
    Points
    5 224
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    perimetre = property(lambda self: self.diametre * pi) #et voilà !!!
    Oui, c'est logique en fait.


    Citation Envoyé par wiztricks Voir le message
    Salut,

    Avec Python on a juste des attributs et pas vraiment de différence entre propriété et méthodes (puisqu'une propriétés peut être associée à une méthode...).

    Après concernant le Cercle, la question de base est de savoir si on veut pouvoir changer le rayon du cercle et d'arbitrer entre une mouture mutable (mise à jour du diamètre) ou non mutable (on crée un nouveau cercle avec son diamètre). Et si on ne répond pas à cette question on va créer un truc entre les deux qui pourra poser problèmes.

    - W
    Il y a tout de même une différence syntaxique entre l'appel d'une méthode qui nécessite des parenthèses et l'appel d'une propriété qui n'en a pas besoin.

    Mais bon, c'est vrai qu'étant plus habitué à langage où tout est objet (sans la possibilité de déclarer une procédure ailleurs que dans une classe) et tout est fortement typé, j'ai tendance à appliquer des dogmes sans vraiment savoir s'il sont adaptés à python.

    Par exemple :
    En règle générale, les méthodes représentent des actions et les propriétés représentent des données.
    Les propriétés sont conçues pour être utilisées comme des champs, ce qui signifie que les propriétés ne doivent pas être complexes en termes de calcul ni produire des effets secondaires comme influer sur une autre donnée (le remplissage d'un cache interne n'étant généralement pas considéré comme un effet secondaire observable et constitue une exception à cette règle).

    Et comme une propriété est plus simple à utiliser qu'une méthode, s'il n'y a pas besoin de paramètre complémentaire, je vais avoir tendance à déclarer une propriété si elle n'est pas contraire à l'une des règles suivante :
    - L'opération va prendre du temps à s'exécuter
    - L'opération est une conversion
    - L'opération retourne un résultat différent à chaque appel
    - L'opération à un effet secondaire notable
    - L'opération retourne une copie d'un état interne
    - L'opération retourne un tableau

    Du coup, est-ce qu'il faut que je modifie ou adapte ces dogmes pour python ?

    Edit : Désolé, je me rends compte que j'ai complètement fait dévier le sujet.

  15. #15
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 677
    Points : 30 965
    Points
    30 965
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par popo Voir le message
    Il y a tout de même une différence syntaxique entre l'appel d'une méthode qui nécessite des parenthèses et l'appel d'une propriété qui n'en a pas besoin.
    Même plus. perimetre est une méthode cachée. Ce qui peut parfois surprendre...

    Citation Envoyé par popo Voir le message
    En règle générale, les méthodes représentent des actions et les propriétés représentent des données.
    Les propriétés sont conçues pour être utilisées comme des champs, ce qui signifie que les propriétés ne doivent pas être complexes en termes de calcul ni produire des effets secondaires comme influer sur une autre donnée (le remplissage d'un cache interne n'étant généralement pas considéré comme un effet secondaire observable et constitue une exception à cette règle).
    Oui, jusque là c'est cohérent

    Citation Envoyé par popo Voir le message
    Et comme une propriété est plus simple à utiliser qu'une méthode, s'il n'y a pas besoin de paramètre complémentaire, je vais avoir tendance à déclarer une propriété si elle n'est pas contraire à l'une des règles suivante :
    - L'opération va prendre du temps à s'exécuter
    - L'opération est une conversion
    - L'opération retourne un résultat différent à chaque appel
    - L'opération à un effet secondaire notable
    - L'opération retourne une copie d'un état interne
    - L'opération retourne un tableau
    Euh là je ne comprends pas. Si l'opération retourne un résultat différent à chaque appel, ça ne peut pas être une propriété... (si j'ai bien compris le "pas contraire" = double négation = "correspondant à"... )

    Citation Envoyé par popo Voir le message
    Du coup, est-ce qu'il faut que je modifie ou adapte ces dogmes pour python ?
    Euh non. Python n'est pas un langage zarbi où tout marche à l'envers. Si tu as des principes qui te garantissent un résultat efficace et le plus optimum possible, ces principes resteront valables avec Python.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  16. #16
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 661
    Points : 5 224
    Points
    5 224
    Par défaut
    Effectivement, j'aurais du me relire avant d'envoyer.
    Le "pas contraire" déforme complètement le sens de la phrase.

    Ce que je voulais dire c'est que si un membre entre dans l'un des cas qui suivent, ce membre sera une méthode et pas propriété.
    Donc, il fallait comprendre que si l'opération renvoie un résultat différent à chaque appel, cette opération sera une méthode.

    Après pour le côté zarbi, ça dépend.
    Lorsqu'on vient de C# ou de Java, il y a quelques concepts python qui surprennent. Je pense notamment :
    - aux interfaces qui deviennent des classes avec des méthodes abstraites (devoir hériter de ABC aussi est déroutant)
    - aux propriétés qu'on peut créer à la volée depuis l'extérieur d'un objet. C'est encore plus fourbe quand tu mets des getter /setter sur une propriété xxx avec @property et @xxx.setter où dans les méthodes associées tu modifie un membre privé self.__xxx. Et depuis l'extérieur tu peux écrire dans monobjet.__xxx ça va te créer à la volée une propriété publique __xxx sur ton objet en plus de ton membre privé de même nom. c'est très perturbant de constater qu'on peut rajouter un membre depuis l'extérieur. C'est contraire au principe d'encapsulation qui est la base de la POO.
    - à certaines syntaxes dites "simplifiée" notamment celle pour remplir un tableau et où la boucle for est derrière au lieu d'être devant, et parfois agrémentée d'une condition encore placée derrière: w = [x for x,y in z if y>100].
    - à l'unpacking que tu m'as expliqué sur un autre post.

  17. #17
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 677
    Points : 30 965
    Points
    30 965
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par popo Voir le message
    Ce que je voulais dire c'est que si un membre entre dans l'un des cas qui suivent, ce membre sera une méthode et pas propriété.
    Donc, il fallait comprendre que si l'opération renvoie un résultat différent à chaque appel, cette opération sera une méthode.
    Ok ça roule.

    Citation Envoyé par popo Voir le message
    Je pense notamment :
    - aux propriétés qu'on peut créer à la volée depuis l'extérieur d'un objet. C'est encore plus fourbe quand tu mets des getter /setter sur une propriété xxx avec @property et @xxx.setter où dans les méthodes associées tu modifie un membre privé self.__xxx. Et depuis l'extérieur tu peux écrire dans monobjet.__xxx ça va te créer à la volée une propriété publique __xxx sur ton objet en plus de ton membre privé de même nom. c'est très perturbant de constater qu'on peut rajouter un membre depuis l'extérieur. C'est contraire au principe d'encapsulation qui est la base de la POO.
    Ah ben ça on peut l'empêcher
    Il suffit de créer et remplir l'attribut statique "__slots__" en lui mettant les attributs que ton objet aura le droit de posséder. Tout autre attribut sera interdit...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    >>> class personne:
    ...	__slots__=("nom", "prenom")
    ...	def __init__(self, nom, prenom):
    ...		self.nom=nom
    ...		self.prenom=prenom
     
    >>> p=personne("LeRoi", "Arthur")
    >>> p.age=800
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'personne' object has no attribute 'age'


    Citation Envoyé par popo Voir le message
    - à certaines syntaxes dites "simplifiée" notamment celle pour remplir un tableau et où la boucle for est derrière au lieu d'être devant, et parfois agrémentée d'une condition encore placée derrière: w = [x for x,y in z if y>100].
    - à l'unpacking que tu m'as expliqué sur un autre post.
    Moui. Mais ces syntaxes simplifiées ne remettent pas en cause tes dogmes... L'unpacking offre justement toute une gamme de nouvelles possibilités mais tu n'es pas obligé de les utiliser. Et sinon w = [x for x,y in z if y>100] s'écrit de façon classique...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    w=list()
    for (x, y) in z:
    	if y > 100: w.append(x)
    ... et là on voit un append() très gros consommateur de ressources. A mon avis la première écriture est plus rapide. J'essaierai de faire un timeit entre les deux d'ici demain soir (là suis claqué) pour voir si mon hypothèse est correcte...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  18. #18
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 661
    Points : 5 224
    Points
    5 224
    Par défaut
    __slots__ ?
    J'en ai parcouru des tutoriels sur les classes en python notamment pour voir comment se traduisent les notions de virtual vs abstract, ou encore protected, private, internal que je ne retrouvait pas dans les tutoriels pour débutants. Et je n'ai rien vu de tel.

    Cela devrait être plus mis en avant.
    Même si c'est dommage que ça doit passer par ce qui ressemble à une rustine.

    En ce qui concerne l'unpacking et la syntaxe simplifiée, je n'ai pas dis que c'était contraire à mes dogmes. Je soulignais simplement que ces sucres syntaxes sont perturbant lorsqu'on est habitué à un autre langage.

  19. #19
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 273
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 273
    Points : 36 757
    Points
    36 757
    Par défaut
    Citation Envoyé par popo Voir le message
    Lorsqu'on vient de C# ou de Java, il y a quelques concepts python qui surprennent
    On ne fait pas de la POO avec Python comme on le fait avec Java/C++.... Et tout devient un peu plus facile lorsqu'on abandonne (un peu) ce qu'on a appris pour essayer de comprendre la façon Python de...

    Si vous avez du temps, cherchez des videos faites à l'occasion des PyCon: les conférences Python où les équipes de développement et quelques un de ceux qui codent avec Python présentent leurs façons de voir les choses.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  20. #20
    Expert confirmé
    Avatar de popo
    Homme Profil pro
    Analyste programmeur Delphi / C#
    Inscrit en
    Mars 2005
    Messages
    2 661
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste programmeur Delphi / C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 2 661
    Points : 5 224
    Points
    5 224
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    On ne fait pas de la POO avec Python comme on le fait avec Java/C++.... Et tout devient un peu plus facile lorsqu'on abandonne (un peu) ce qu'on a appris pour essayer de comprendre la façon Python de...
    Je commence à en prendre conscience mais les vieux réflexes ont la peau dure.

    Citation Envoyé par wiztricks Voir le message
    Si vous avez du temps, cherchez des videos faites à l'occasion des PyCon: les conférences Python où les équipes de développement et quelques un de ceux qui codent avec Python présentent leurs façons de voir les choses.
    Quand j'ai lu ça, je m'attendais à des types parlant dans un anglais avec leur accent américain où tu dois réécouter 10 fois pour comprendre ce qu'il dit.
    J'ai été ravi de constater qu'il y avait la transcription (certes toujours en anglais). Mais c'est d'une grande aide.
    Je regarderai à l'occasion.

    En attendant, je vais me noter de rajouter systématiquement des __slots__ à mes classes surtout que je vois que ça fait consommer moins de RAM.

Discussions similaires

  1. Réponses: 2
    Dernier message: 11/04/2015, 13h59
  2. Programation Orientée Objet POO
    Par helmis dans le forum Débuter
    Réponses: 11
    Dernier message: 02/05/2008, 17h53
  3. [VB6]programation orientée objet
    Par meriemeness dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 16/03/2006, 08h42
  4. [DEBUTANT] Conseil sur la programmation orienté objet
    Par etiennegaloup dans le forum Langage
    Réponses: 7
    Dernier message: 27/05/2005, 12h59
  5. [SGBDOO] Base de données orientée objet
    Par Jaona dans le forum Décisions SGBD
    Réponses: 19
    Dernier message: 14/04/2003, 11h07

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