Comment je suis devenu un biffin du numérique grâce à Emmabuntüs

biffin (nom masculin) : 1. Chiffonnier, 2. Militaire de l’infanterie

Bonjour,

Il y a deux semaines, j’ai eu l’heureuse surprise de découvrir dans ma boite à courriels, une missive de Patrick d’Emmabuntüs me demandant si j’étais disposé à participer aux tests de la prochaine version de cette distribution solidaire permettant le reconditionnement d’ordinosaures abandonnés. Ces derniers sont ensuite proposés à des associations œuvrant dans le domaine de la solidarité internationale telles que :

Vous pensez bien que je n’ai pas hésité longtemps avant de lui répondre JAWOHL!  Me voilà donc devenu testeur et le moins qu’on puisse dire, c’est que je ne regrette pas ma décision. Comme c’est tout nouveau tout beau, j’y consacre plusieurs heures par jour ce qui explique que le dernier article de mon blogue date d’il y a deux semaines. Je n’ai pas de clone pour me seconder et il faut bien que je dorme un peu!

emmabuntus_fond_ecran_accueil_4

Pourquoi cela me plaît?

  • Parce que dans une ancienne vie, j’ai fait pas mal de contrôle qualité et d’amélioration continue. Or, dans la fonction de testeur, je retrouve le même état d’esprit, c’est-à dire se mettre, autant que faire se peut, dans la peau du futur utilisateur pour juger si tel défaut va le faire sortir de ses gonds ou bien s’il ne va même pas le remarquer.
  • En outre, l’idée d’utiliser plusieurs mois avant sa diffusion officielle, une version que presque personne ne possède sur son ordinateur, me procure de la joie.
  • Enfin, je voudrais rajouter que c’est pour moi l’occasion de découvrir de nouvelles fonctionnalités et de me coucher moins bête le soir, ce qui m’aide à trouver le sommeil. Quelques exemples à l’appui de mes dires :

J’ai toujours pensé que le swap était un genre musical inventé par les Forbans, un groupe mythique qui a sévi durant les années 80 et qui, croyez-le ou non, tourne encore! Eh bien pas du tout! Le swap est une espèce de déversoir qui se vide dans la mémoire de masse pour soulager la RAM lorsque le taux d’occupation de cette dernière atteint un seuil critique. Et ça, ce sont les tests qui me l’ont appris! Swap! swap! swap… Swap babedouwa!

J’ai également appris à utiliser ./configure, make et make install pour installer un logiciel qui n’est pas dans les dépôts officiels de Debian.

Pour un autodidacte de mon espèce, cette fonction de testeur, quoique modeste, est une incomparable source d’enrichissement personnel et je voudrais encore une fois remercier chaleureusement Patrick d’Emmabuntüs pour m’accompagner quotidiennement dans cette tâche. Lorsque je suis bloqué, il me prodigue juste les quelques conseils nécessaires pour continuer mon chemin et il me laisse me débrouiller par moi-même pour trouver la solution. je trouve que c’est une excellente démarche.

Bon week-end les pingouins!

pingouin.png

On recrute! Formation dispensée en interne

Bonjour à toutes et à tous,

Je m’efforce de rédiger un article par semaine ce qui, croyez-le ou non, n’est pas toujours une mince affaire… Mais je suis récompensé par le fait que l’audience du site se porte bien. Les visites sont régulières et en augmentation constante. Continuer à lire … « On recrute! Formation dispensée en interne »

À la découverte de l’informatique dans les nuages avec Seafile

Bonjour,

Quand j’étais petit, je me souviens que la télévision en noir et blanc ne diffusait que trois chaînes : TF1, Antenne 2 et FR3. Dans le temps, y’avait pas Linternet et c’était pas plus mal comme ça. On manquait de rien. On était heureux comme tout.

On partait jamais en vacances. On passait nos étés à battre le blé au fléau avant de le vanner mais on manquait de rien, on était vrai heureux. À Noël, quelle joie de découvrir dans mon sabot une orange que je partageais avec mes douze frères et soeurs. Le soir du réveillon, on écoutait Tino Rossi sur un vieux mange-disques mais pas trop longtemps pour pas user les piles. À minuit, on allait à la messe de minuit avec Jacquou le croquant, notre voisin qui avait été amputé des deux jambes après avoir sauté sur une mine en Indochine. C’était le bon temps.

Les téléphones n’étaient pas portatifs mais on manquait de rien, on était heureux comme tout. À la télé, tous les morveux regardaient Le Village dans les nuages. C’était une série avec des extrathérèses réfugiés dans le hameau du Glaude et du Bombé. C’était poilant! Qu’est-ce qu’on était heureux de manquer de rien!

Aujourd’hui, à cause du réchauffement climatique, le ciel est aussi bleu qu’un monochrome d’Yves Klein et il n’y a plus de village dans les nuages. Cela dit, l’esprit de ce lieu singulier n’a pas complètement disparu puisque de nos jours, il n’est pas rare de stocker ses données personnelles dans un nuage. On appelle ça l’informatique en nuage ou cloud computing en anglais. D’aucuns prétendent qu’il s’agit d’informatique dématérialisée mais c’est une illusion! Les données sont, de toute façon stockées quelques part, que ce soit sur un strato-cumulus, au fond d’une mine, dans le cul d’une vache ou bien dans un Raspberry pi!

Tiens justement, pour mes dernières vacances en France, j’ai eu la bonne idée d’emporter mon Raspberry pi. Il se trouve que j’ai également acheté le magazine Linux inside consacré à ce drôle de petit ordinateur. Au passage, je suis moyennement satisfait de mon acquisition. Je trouve que les tutoriaux sont parfois d’une précision toute relative (en termes de pédagogie). À 12,90€, je m’attendais quand-même à quelque chose de plus consistant. Notez qu’il est fort possible que ce soit aussi mon cerveau qui soit d’une précision toute relative.

rasp_guide

Bref, je suis tombé sur un tuto qui explique comment transformer son « Rasp » en nuage avec Owncloud. Je me suis lancé dans l’aventure et après moult déboires, j’ai réussi à créer mon propre nuage sur mon propre serveur. Cerise sur le gâteau, les données étaient stockées non pas sur la carte micro-SD du Raspberry mais déportées sur une clé USB de 31 GO. La grande classe!

Sauf que le nuage owncloud, je le trouvais bien lourd à l’usage. Le téléversement de mes documents prenaient des plombes, à tel point que je n’ai même pas osé essayer avec des images. J’avais grand peur de faire fondre mon rasp! Était-ce la faute d’Owncloud ou du Raspberry? Je ne saurai jamais le fin mot de l’histoire puisque tout a planté après quelques jours d’utilisation. Je me suis retrouvé devant une page blanche et d’une certaine manière, j’étais soulagé. Pour celles et ceux que ça intéresse quand-même, voici le tutoriel que j’ai suivi pour installer owncloud :

https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-owncloud-on-ubuntu-16-04

Installation de Seafile

Je me suis donc mis en quête de solutions alternatives et j’ai jeté mon dévolu sur Seafile, un cloud certes un peu plus modeste en termes de capacités mais qui me comble de joie. C’est ici que ça se passe :

https://www.seafile.com/en/download/

Il faut scroller vers le bas et cliquer sur Server for Raspberry Pi. Après avoir téléchargé et décompressé seafile-server_6.1.1_stable_pi.tar.gz, placez-vous dans le dossier seafile-server-6.1.1 et entrez la commande suivante :

./setup-seafile

Laissez-vous guider. L’installation est très facile.

Ensuite, pour démarrer le serveur Seafile, il faut entrer cette commande :

seafile.sh start

Il faut également démarrer la partie hub qui permet les connexions :

seahub.sh start

N’ayant nullement envie d’entrer ces deux commandes à chaque connexion, je les ai paramétrées dans l’onglet Applications au démarrage d’Ubuntu Mate (le système d’exploitation de mon raspberry) afin qu’elles se lancent automatiquement à l’ouverture de session. Attention toutefois de ne pas lancer la commande Seahub en même temps que la commande Seafile! Ça ne fonctionnera pas. Il faut la lancer avec un léger temps de retard. Pour ma part, j’ai choisi soixante secondes.

Donc, pour résumer, ça nous donne ceci :

Système > Préférences > Personnel >Applications au démarrage

  • Démarrage de Seafile à l’ouverture de session :
/home/ordinosor/seafile-server-6.1.1/seafile.sh start
  • Démarrage de Seahub 60 secondes après l’ouverture de session :
sh -c "sleep 60; /home/ordinosor/seafile-server-6.1.1/seahub.sh start"

L’interface graphique de Seafile

Si tout s’est déroulé comme prévu, vous allez arriver sur une page qui vous invitera à vous connecter et à profiter pleinement des fonctionnalités de votre cumulo-nimbus. Le téléversement des documents est très rapide (grâce au glisser-déposer), le téléchargement aussi.

 

 

Ce diaporama nécessite JavaScript.

Petit bémol toutefois par rapport à owncloud, il n’y a pas d’extensions telles qu’un agenda ou un répertoire d’adresses téléphoniques mais En dehors de ça, je suis tout à fait satisfait de mon nouveau cumulo-nimbus!

seafile_2
C’est moi…

J’ai basculé ma messagerie sur Mail.Lilo.org

Étant un adepte convaincu de la distribution solidaire Emmabuntüs que j’ai installée sur Volgor mon fidèle ordinateur de bureau, je connaissais déjà le métamoteur de recherche Lilo. Du reste, je lui avais même consacré un article pour en dire tout le bien que j’en pensais. Je rappelle que grâce à lui, les recherches effectuées par les internautes sont comptabilisées en gouttes d’eau puis converties en argent avant d’être reversé à des projets sociaux et environnementaux. En ce qui me concerne, j’ai choisi de reverser mes gouttes d’eau au projet Emmabuntüs. Continuer à lire … « J’ai basculé ma messagerie sur Mail.Lilo.org »

Python: Variables et espaces de noms

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

Introduction

Dans le chapitre précédent, nous avons pu constater que grâce à la programmation orientée objet, deux développeurs, Briface et Jobriel, pouvaient coder un module chacun de leur côté et que ces deux modules pouvaient être « assemblés » in fine pour donner naissance au programme de notre choix.

Même si ces deux modules renfermaient un objet ou une variable dont le nom était identique, il n’y avait pas de risques que le programme se comporte de manière erratique puisque chaque objet évoluait dans son propre espace de noms. C’est la raison pour laquelle  une commande telle que self.random_choice.random_choice ne levait pas d’exception. 

La notion d’espace de noms dans le langage Python

La notion d’espace de noms est très importante dans le langage Python. Lorsque nous définissons une fonction avec des variables à l’intérieur, ces dernières ne peuvent vivre que dans l’espace de noms de cette fonction. Dès que celle-ci a exécuté sa dernière ligne d’instruction, les variables qui y séjournent deviennent hors de portée. Voici un exemple :

#!/usr/bin/env python3
# -*- coding: utf8 -*-

def first_names():
    lady_1 = "Gabiche"
    print(lady_1)

first_names() #appel de fonction

Résultat : Gabiche.

La fonction affiche bien la valeur contenue dans la variable définie localement.

Maintenant, nous allons modifier la dernière ligne du programme. Au lieu d’appeler la fonction, nous allons tenter de faire un print() de la variable lady_1.

#!/usr/bin/env python3
# -*- coding: utf8 -*-

def first_names():
    lady_1 = "Gabiche"
    print(lady_1)

print(lady_1)

Traceback (most recent call last):
File « /home/ordinosor/1_exemple.py », line 8, in
print(lady_1)
NameError: name ‘lady_1’ is not defined

Godverdomme! Keskispasse? Eh bien, nous avons tout simplement essayé d’afficher la valeur d’une variable qui est hors de portée puisqu’elle est définie à l’intérieur de la fonction.

À présent, nous allons essayer de faire le contraire. Nous allons définir une variable lady_2  dite globale c’est-à-dire à l’extérieur de toute fonction, et dans la fonction first_names, nous allons tenter de faire un print(lady_2).

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    print(lady_2)

first_names() #Appel de fonction

Résultat : Amandale.

Là, dans cet exemple, lady_2 n’est pas définie à l’intérieur de la fonction, et pourtant le programme ne plante pas! Warum?

En fait, Python va d’abord chercher dans l’espace local une variable portant le nom de lady_2. S’il ne la trouve pas, alors il va poursuivre sa recherche à l’extérieur de la fonction, c’est-à-dire dans l’espace global où il existe bien une variable définie avec le nom lady_2. Par conséquent, la fonction print() peut récupérer la valeur de cette variable dite globale.

Maintenant, définissons deux variables portant le même nom mais ne stockant pas la même valeur… Une variable globale lady_2 et une variable locale lady_2 dans la fonction. Reprenons le code précédent:

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    lady_2 = "Mandy-Bulle"
    print(lady_2)

first_names() #Appel de fonction

Résultat : Mandy-Bulle.

Python a d’abord effectué une recherche en local, dans l’espace de noms de la fonction. Il a réussi à trouver une variable nommé lady_2. Donc, la recherche s’est immédiatement interrompue et la fonction print() a récupéré la valeur contenue dans cette variable locale, à savoir Mandy-Bulle.

Le mot-clé global

Il n’est pas possible de modifier la valeur de la variable globale lady_2 à l’intérieur de la fonction… A moins de lui affecter au préalable le mot-clé global mais cette technique est parfaitement déconseillée car dans un gros programme, si quelqu’un modifie la valeur stockée dans la variable, il y a un gros risque que ce changement impacte sans le vouloir d’autres parties du programme. Gros risque de bugs en perspective!

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    global lady_2
    lady_2 = "Mandy-Bulle"

print(lady_2) #Variable globale

Résultat : Mandy-Bulle.

Amandale a disparu du programme…

Et avec la méthode append() ?

Créons une liste ladies_list et essayons voir…

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list.append("Mandy-Bulle")

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Résultat : [« Amandale », « Gabiche », « Mandy-Bulle »].

Nous avons réussi à modifier la liste malgré le fait que la méthode append() soit présente à l’intérieur de la fonction. Pourquoi donc? Parce que nous avons fait appel à une méthode qui appartient à l’objet ladies_list. En agissant ainsi, aucune barrière d’espace de noms ne peut nous empêcher de mener à bien notre modification.

Mais il est impossible de modifier la variable globale ladies_list en lui affectant une nouvelle valeur à l’intérieur de la fonction.

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list = ["Mandy-Bulle", "Dominille"]
    print(ladies_list)

first_names() #Appel de fonction
print(ladies_list) #Variable globale

[« Mandy-Bulle », « Dominille »] : Résutat qui correspond au print() de la variable locale ladies_list dans la fonction first_names (à la ligne n° 10).

[« Amandale », « Gabiche »] : Résultat qui correspond au print() de la variable globale ladies_list (à la ligne n° 11). Nous n’avons pas réussi à modifier cette dernière.

Avec le slicing

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list[1:1] = ["Mandy-Bulle"]

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Résultat : [« Amandale », « Mandy-Bulle », « Gabiche »]

Avec la technique du slicing, le résultat est positif car en fait, sans le savoir, nous utilisons la méthode constructeur de la classe slice. Elle agit directement sur l’objet et là encore, aucune barrière d’espace de noms ne peut nous empêcher de mener à bien notre modification. C’est comme si nous avions écrit ce code (ligne n° 7) :

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list[slice(1,1)] = ["Mandy-Bulle"]

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Attributs d’instance et attributs de classe

Il existe également une hiérarchie entre les espaces de noms des instances et des classes.

  • Les instances et les classes peuvent utiliser les variables définies au niveau global mais elles ne peuvent pas les modifier.

Dans le code ci-dessous, nous avons trois types de variables :

  • Une variable globale
  • Un attribut de classe
  • Un attribut d’instance
#!/usr/bin/env python3
# -*- coding: utf8 -*-

man_1 = "Dentifritz_1" #Variable globale

class FirstName :
    """Test avec des prénoms"""

    man_1 = "Dentifritz_2" #Attribut de classe

    def first_name(self):
        """test des variables"""

        man_1 = "Sébanislas"
        self.man_1 = "Barnabulle"

#===== MAIN ===================================================================

if __name__ == '__main__':

    test = FirstName()
    test.first_name()
    print(man_1) #Variable globale
    print(FirstName.man_1) #Attribut(ou variable) de classe
    print(test.man_1) #Attribut (ou variable) d'instance

Ligne n° 23 : Dentifritz_1

Ligne n° 24 : Dentifritz_2

Ligne n° 25 : Barnabulle

Je vous invite à modifier ce code et à faire autant de tests que nécessaire pour bien comprendre le concept d’espaces de noms et la hiérarchie qui les gouverne.

#Python : classes et méthodes (partie 2) – mise en pratique

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

Nous allons confier à deux programmeurs en herbe, Briface et Jobriel, le soin de rédiger le code d’une petite application à caractère pédagogique. Elle consiste à faire apparaître des formes générées aléatoirement.

Jobriel va rédiger le code nécessaire à la création de l’environnement graphique, c’est-à-dire les widgets tandis que Briface, de son côté, va rédiger le module permettant de faire apparaître de manière aléatoire, des formes qui sont soit des triangles, soit des cercles, soit des carrés. La couleur de ces formes est également définie de manière aléatoire.

Au final, voici ce que nos deux gugusses doivent produire :

Le code de Jobriel

Commençons par le code de notre ami Jobriel :


#!/usr/bin/env python3
# -*- coding: utf8 -*-

from tkinter import*
import choice

class MainProg :
    """Création de l'environnement graphique de l'application"""

    def __init__(self, main_window, h = 300, w = 300, color = 'white'):
        """Méthode constructeur"""

        self.main_window = main_window
        self.h = h
        self.w = w
        self.color = color

    def widgets(self):
        """Création des widgets"""

        self.main_frame = Frame(self.main_window, height=self.h,\
                      width=self.w, bg=self.color)
        self.main_frame.pack()

        self.canevas = Canvas(self.main_frame, height=400, width=self.w,\
                   bg=self.color)
        self.canevas.pack(side=TOP)

        self.frame_1 = Frame(self.main_frame, height=100, width=self.w,\
                   bg=self.color)
        self.frame_1.pack(side=BOTTOM)

        self.random_choice = choice.RandomObjects(self.canevas)

        self.button = Button(self.frame_1, height=1, width=5, text='Afficher',\
                  relief='ridge', bd=3, bg='navy', fg='white',\
                  font=('Times', 14, 'bold'), padx=20,\
                  command = self.random_choice.random_choice)
        self.button.pack(padx=20, pady=10)

#===== MAIN ===================================================================

if __name__ == '__main__':

    main_window = Tk()
    main_window.title('Une forme au hasard')

    main_page = MainProg(main_window, 500, 500)
    main_page.widgets()

    main_window.mainloop()

ligne n° 4 : importation du module tkinter.
ligne n° 5 : importation du module choice qui va nous permettre de faire apparaître de manière aléatoire, différentes formes telles que des carrés, des ronds, des triangles. Les couleurs de ces formes sont également définies de manière aléatoire. Pour les deux formes d’importation, je vous renvoie au chapitre sur les modules. Personnellement, je préfère la forme d’importation ci-dessous car il n’y a pas de risques de conflits entre des variables portant le même nom. En outre, elle permet de raccourcir le nom du module. tkinter devient tk :

import tkinter as tk 

Pour de plus amples renseignements sur la bibliothèque tkinter, je vous invite à consulter cette documentation en français.

Ligne n° 43 : Nous trouvons une condition introduisant du code qui va s’exécuter uniquement si le programme est lancé de manière indépendante et non pas comme un module. Ici, c’est le cas. Par conséquent, cette partie du code s’exécute.

Ligne n° 45 : Création de l’objet main_window (fenêtre principale) par instanciation de la classe Tk() issue du module tkinter. Si j’avais écrit ceci à la ligne n° 4 : import tkinter as tk, alors la ligne n° 45 aurait été : main_window = tk.Tk().

Ligne n° 46 : application de la méthode title() sur l’objet main_window. Elle donne un titre à la fenêtre.

À ce stade, si on exécute le programme, voici ce qu’on obtient :

main_window

Ligne n° 48 : Création de l’objet main_page par instanciation de la classe MainProg(). Nous lui passons trois arguments qui sont main_window (la fenêtre mère), 500 (la hauteur de l’application) et 500 (la largeur). Nous choisissons de ne pas lui passer de paramètre de couleur. Ce sera donc la couleur par défaut qui va s’appliquer.
Ligne n° 49 : Application de la méthode widgets() sur l’objet main_page.

Ligne n° 51 : Application de la méthode mainloop() sur l’objet main_window ce qui a pour effet de déclencher le réceptionnaire d’événements et de permettre l’exécution du programme.

Ligne n° 7 : On remonte tout en haut! Définition d’une classe fondamentale baptisée MainProg
Ligne n° 10 : Méthode constructeur qui prend quatre paramètres:

  • self qui correspond à la référence de l’instance, c’est-à-dire l’objet main_page que nous avons instancié à la ligne n° 48. je rappelle qu’une méthode d’instance prend toujours au moins cet argument et que par convention, il est nommé self.
  • main_window qui correspond à la fenêtre principale et dont nous avons besoin pour instancier les widgets enfants.
  • h, w et color sont des paramètres qui possèdent une valeur par défaut. Si nous décidons de les ignorer, ce seront donc ces valeurs qui vont s’appliquer. C’est ce que nous avons fait avec color. Nous avons ignoré ce paramètre. Pour ce qui est des autres valeurs par défaut (h=300, w=300), nous avons choisi de les remplacer par 500 (voir ligne n° 48). Si nous décidons de ne pas respecter l’ordre de déclaration, il faut alors préciser le paramètre. Par exemple :

main_page = MainProg(main_window, color = ‘blue’, w=260, h=600)

Ligne n° 11 : Docstring

Lignes n° 13 à 16 : Création des attributs d’instance
Ligne n° 18 : Méthode widgets (création de tous les widgets de l’application)
Lignes n° 21 et 22 : Création de l’objet self.main_frame par instanciation de la classe Frame. Cette dernière créé un cadre que l’on peut remplir avec d’autres widgets. Nous pouvons lui passer plusieurs arguments. Notez bien la largeur (width) et la hauteur (height). Normalement, vous devez être capables de retrouver leurs valeurs. Notez également la barre oblique (antislash) qui permet d’écrire une instruction sur plusieurs lignes. La fondation Python préconise de ne pas dépasser 79 caractères par ligne, ce qui est assez strict. Dans la mesure du possible, il faut respecter cette convention.

Ligne n° 23 : Application de la méthode pack(). Cette dernière place le widget. Elle peut prendre des paramètres tels que TOP, BOTTOM, LEFT ou RIGHT qui poussent le widget dans la direction donnée.

À ce stade, si nous exécutons le programme, voici ce que nous obtenons. J’ai volontairement et provisoirement coloré en rouge, le fond du widget :

main_frame

Lignes n° 25 et 26 : Création de l’objet self.canevas par instanciation de la classe Canvas. C’est ce widget qui va nous permettre de placer les formes aléatoires grâce à différentes méthodes qui lui sont liées.
Ligne n° 27 : Méthode de placement pack(). Cette fois-ci, elle prend un paramètre (side=TOP) pour pousser le widget vers le haut.
Lignes n° 29 à 31: Nous créons un nouvel objet de type Frame que nous plaçons tout en bas de sa fenêtre parente (side=BOTTOM). Dans ce widget, nous placerons le bouton Afficher.

Ligne n° 33: Création de l’objet random_choice par instanciation de la classe RandomObjects du module importé choice. Nous lui passons un paramètre qui est self.canevas. Donc, cela nous donne:

self.random_choice = choice.RandomObjects(self.canevas)

Je rappelle que l’utilisation du point en Python signifie l’appartenance. Ainsi, la classe RandomObjects appartient au module choice.

Lignes n° 35 à 38: Création du bouton afficher par instanciation de la classe Button. Celle-ci prend plusieurs paramètres qui sont :

  • La hauteur
  • La largeur
  • Le texte à afficher
  • Le relief de la bordure
  • L’épaisseur de la bordure
  • La couleur de fond
  • La couleur du texte
  • La police et la fonte de caractères
  • L’espacement horizontal du texte à l’intérieur du widget
  • La commande que le bouton déclenche.

Pour ce dernier paramètre, nous appliquons la méthode random_choice issue du module importé choice, sur l’objet que nous avons créé (random_choice). Cela nous donne :

command=self.random_choice.random_choice

Alors là, vous allez me dire : « Mais Ordinosor! Tu bé, tu bé-bé, tu bégayes? »

Absolument pas! Il n’y a aucun risque de collision ou de confusion puisque ces deux noms identiques n’évoluent pas dans les mêmes espaces.

Notez bien que la commande déclenche une méthode lorsque nous cliquons sur le bouton. Il ne faut donc pas mettre les parenthèses () à la fin de la commande car cela aurait pour effet de shunter le bouton et d’activer la méthode dès le lancement du programme! Donc, il ne faut pas écrire :

command=self.random_choice.random_choice()

Ligne n° 39: La méthode pack() place le bouton dans sa fenêtre parente en réservant un espace vertical (pady=20) et horizontal (padx=20).

J’ai coloré provisoirement les différents widgets pour mieux les visualiser. Si nous exécutons le programme à ce stade, voici ce que nous obtenons:

  • En rouge, le widget self.main_frame
  • En blanc, le widget self.canevas
  • En jaune, le widget self.frame_1
  • En bleu, le widget self.button

button2

Merci pour ce travail, Jobriel! À présent, remettons tous les fonds des widgets en blanc Cliquons sur le bouton et voyons ce que notre ami Briface a codé…

Le code de Briface


#!/usr/bin/env python3
# -*- coding: utf8 -*-

from tkinter import*
import random

class RandomObjects :
    """Instancie aléatoirement les formes (triangles, cercles, carrés).
    Les couleurs de ces formes sont également définies de manière aléatoire"""

    def __init__(self, canevas):
        """Constructeur"""

        self.canevas = canevas

    def square(self):
        """Création du carré"""

        self.square_object = self.canevas.create_rectangle(200, 150, 300, 250,\
                             fill=self.random_color)

    def circle(self):
        """Création du cercle"""

        self.circle_object = self.canevas.create_oval(200, 150, 300, 250,\
                             fill=self.random_color)

    def triangle(self):
        """Création du triangle"""

        self.polygon = self.canevas.create_polygon(250, 150, 200, 250, 300,\
                       250,fill=self.random_color)

    def random_choice(self):
        """cf docstring class RandomObjects"""

        self.canevas.delete('all')
        self.random_color=random.choice(['green','red','yellow','blue','black'])
        random.choice([self.square, self.circle, self.triangle])()

Ligne n° 5 : importation du module random qui va nous permettre de faire des choix aléatoires.
Ligne n° 7: Création la classe RandomObjects.
Ligne n° 11: Méthode constructeur avec deux paramètres, la référence d’instance self et canevas.
Ligne n° 13: Déclaration d’une variable d’instance.
Ligne n° 16: Définition d’une méthode qui dessine un carré.
Ligne n° 19: Pour cela, nous utilisons la méthode create_rectangle qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage.
Ligne n° 22: Définition d’une méthode qui dessine un cercle plein.
Ligne n° 25: Pour cela, nous utilisons la méthode create_oval qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage.
Ligne n° 28: Définition d’une méthode qui dessine un triangle.
Ligne n° 31: Pour cela, nous utilisons la méthode create_polygon qui prend six coordonnés en arguments ainsi qu’une couleur de remplissage.

Pour de plus amples détails, je vous invite à consulter cette documentation en français.

Ligne n° 34: Définition de la méthode random_choice.
Ligne n° 37: Nous appliquons la méthode delete(‘all’) sur le widget self.canevas pour effacer une éventuelle forme avant que la suivante ne prenne sa place.
Ligne n° 38: Déclaration de la variable self.random_color. La valeur qui lui est affectée est une couleur choisie au hasard dans la liste passée en argument à la méthode random.choice.

Là encore, attention de ne pas confondre la méthode random_choice que nous avons nous-même définie et la méthode random.choice, c’est-à-dire la méthode choice du module importé random (ligne n° 5)!

Ligne n° 39: Cette fois-ci, random.choice choisit au hasard la méthode qui va matérialiser la forme. Pour que cette méthode exécute ses instructions, nous rajoutons tout à la fin, deux parenthèses. Sans ces deux parenthèses, rien ne se passerait:
random.choice([self.square, self.circle, self.triangle])()

Merci à toi , Briface, pour ce module qui exécute à la perfection la tâche qui lui a été impartie.

Ce diaporama nécessite JavaScript.

Python : classes et méthodes (partie 1), avec un peu de menuiserie en prime.

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

En programmation orientée objet (POO) et notamment dans le langage Python, tout est objet ! En fait, c’est un peu comme dans le monde réel… Nous sommes entourés d’objets de toutes sortes. Continuer à lire … « Python : classes et méthodes (partie 1), avec un peu de menuiserie en prime. »