PROJET AUTOBLOG


Planet-Libre

source: Planet-Libre

⇐ retour index

Benoît Boudaud : Python: Les dictionnaires

samedi 11 mars 2017 à 05:46

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.

J’habite en Allemagne et l’idiome guttural de ce pays n’est pas ma langue maternelle. Par conséquent, lorsqu’un mot me manque, je consulte un dictionnaire. Je me rends directement à l’emplacement précis du mot français, par exemple Ambulance, et ce mot français est comme une clé qui me donne accès à la valeur correspondante dans la langue de Rammstein :

Ambulance : Krankenwagen

Figurez-vous qu’il existe exactement le même procédé en Python et c’est bien plus pratique qu’une liste. Les dictionnaires sont la solution idéale pour réaliser un test d’appartenance et en extraire une valeur.

dico
Ne jamais laver un dictionnaire à 60°!

Limitation des listes

Le problème des listes, c’est qu’il s’agit d’une séquence d’objets indicés, c’est-à dire que pour avoir accès à un élément précis, il faut connaitre son indice :

mots_fr = ["Ambulance", "Hôpital","Infirmière"]
mots_allemands = ["Krankenwagen", "Krankenhaus","Krankenschwester"]

Par exemple, je sais que l’indice d’Infirmière est le nombre entier 2. Je consulte la liste allemande. Que trouve-t-on à l’indice 2? Krankenschwester.

Pas très pratique tout ça! En plus, est-ce que je suis sûr que les traductions sont rangées dans le bon ordre. Est-ce que le mot allemand qui est à l’indice 1 (Krankenhaus) correspond bien au mot français au même indice (Hôpital)? Si ça se trouve, c’est tout dans le désordre!

Pour éviter ce genre de désagréments, on pourrait alors imaginer une liste de listes contenant des paires mot_allemand – mot_français:

dictionnaire = [["Ambulance", "Krankenwagen"], ["Hôpital", "Krankenhaus"],["Infirmière", "Krankenschwester"], [(...), (...)]]

Et pour trouver la traduction, on pourrait utiliser ce code:

dictionnaire =[["Ambulance", "Krankenwagen"], ["Hôpital", "Krankenhaus"],["Infirmière", "Krankenschwester"]]
for i, element in enumerate (dictionnaire):
    if "Hôpital" in dictionnaire[i]:
        print(dictionnaire[i][1])

Résultat: « Krankenhaus »

« Ça marche, Ordinosor! On l’a, notre dictionnaire français-allemand ».

Ne t’emballe pas, jeune fou! je te rappelle que les listes sont des séquences. Cela signifie que pour faire un test d’appartenance, elles sont parcourues de l’indice 0 jusqu’à l’indice de l’élément recherché. En clair, si tu cherches la traduction de zygomatique qui se trouve à la fin du dictionnaire, il va falloir que tu tournes toutes les pages une par une et que tu lises tous les mots un par un! Tu n’as pas le choix, ton dictionnaire est une liste.

Tu sais quoi? On va se donner rendez-vous en 2025. Tu m’apporteras ta traduction. Allez vas-y, tourne les pages!

Bon… en attendant, entrons dans le vif du sujet.

Définition et déclaration d’un dictionnaire

Définition

Un dictionnaire est un ensemble dont les éléments sont des paires clé-valeur . Au niveau syntaxique, un dictionnaire est contenu entre deux accolades. Les éléments sont séparés par des virgules tandis que les paires clé-valeur sont séparées par deux points. Voici ce que ça donne:

nom_du_dictionnaire = {clé : valeur, clé : valeur, clé : valeur, (…) : (…)}

Un dictionnaire est modifiable et les valeurs peuvent être n’importe quel objet (immuable ou modifiable, il n’y a aucune restriction) mais les clés doivent absolument être des objets immuables (string, nombre entier, nombre décimal, tuple). Si la clé est un tuple, celui-ci ne doit contenir que des éléments immuables. Par exemple, ce genre de clé ([0, 1], [2, 3]) qui est un tuple contenant des listes modifiables va lever une exception (erreur):

TypeError: unhashable type: ‘list’

Déclarer un dictionnaire

dictionnaire = {} # dictionnaire vide
capitales = {"France":"Paris", "Allemagne" : "Berlin"}

Dans cet exemple, « France » est une clé tandis que « Paris » est une valeur.

liste_capitales = [("France","Paris"), ("Allemagne","Berlin")]
capitales = dict(liste_capitales)
print(capitales)

Résultat : {‘Allemagne’: ‘Berlin’, ‘France’: ‘Paris’}

capitales = {"France":"Paris", "Allemagne" : "Berlin", "France" : "Marseille"}
print(capitales)

Résultat: {‘Allemagne’: ‘Berlin’, ‘France’: ‘Marseille’}

Ajouter un élément (paire clé-valeur)

Si je veux rajouter un élément, c’est très simple, je créé une nouvelle paire clé-valeur. La clé  est contenue entre des crochets et la valeur se trouve à la droite du signe d’affectation. La syntaxe est donc la suivante :

nom_du_dico[clé] = valeur

capitales['Islande'] = "Reykjavik"
print(capitales)

Résultat : {‘Allemagne’: ‘Berlin’, ‘Islande’: ‘Reykjavik’, ‘France’: ‘Paris’}

Diantre! Les éléments ne sont plus dans le même ordre? Comment se fait-ce?

Ça n’a aucune espèce d’importance. L’ordre est aléatoire car un dictionnaire n’est pas une séquence, c’est une implémentation de tables de hachage. Pour retrouver une valeur, nous avons seulement besoin de connaître sa clé.

Accéder à une valeur

Voici comment on accède à une valeur:

capitales = {'Allemagne': 'Berlin', 'Islande': 'Reykjavik', 'France': 'Paris'}
result = capitales["Allemagne"] #Je stocke le résultat dans une variable.
print(result)

Résultat : « Berlin »

C’est simple et instantané! Le programme n’a pas besoin de parcourir le dictionnaire du début à la fin. Grâce à la clé (« Allemagne »), Python est en mesure de se rendre directement à la « page » souhaitée pour trouver la valeur et renvoyer cette dernière. Que le dictionnaire contienne dix éléments ou cinq cent millions, la vitesse d’exécution sera de toute façon identique!

Et si j’utilise une clé qui n’est pas dans le dictionnaire, Python lève une exception (erreur):

result = capitales["Syldavie"]
print(result)

KeyError: ‘Syldavie’

La méthode get() comme test d’appartenance

Pour contourner cette exception et éviter d’avoir un message d’erreur qui stoppe le programme, il suffit d’utiliser la méthode get() en lui passant deux arguments : la clé et le résultat renvoyé au cas où la clé serait absente du dictionnaire. Reprenons le code précédent :

result = capitales.get("Syldavie", "Non répertorié.")
print(result)

Résultat : Non répertorié.

Tester l’appartenance avec l’instruction in

Il est possible de tester l’appartenance d’une clé à un dictionnaire grâce à la puissante instruction in.

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
if "Islande" in capitales:
    print(capitales["Islande"])

Résultat : Reykjavik

Je précise que l’instruction in ne teste que l’appartenance des clés et non pas l’appartenance des valeurs.

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
if "Reykjavik" in capitales:
    print("Test d'appartenance réussi")
else:
    print("Cette clé est absente du dictionnaire")

Résultat: Cette clé est absente du dictionnaire

Mettre à jour une valeur

Si on souhaite mettre à jour une valeur, c’est fort simple. Voici comment on procède:

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
capitales["France"] = "Marseille"
print(capitales)

Résultat: {‘France’: ‘Marseille’, ‘Allemagne’: ‘Berlin’, ‘Islande’: ‘Reykjavik’}

Utiliser un tuple comme clé

C’est tout à fait possible, à la condition que le tuple ne contienne que des objets immuables. Quant à la valeur, elle peut être constituée par n’importe quel objet donc une liste ne pose aucun problème.

Dès lors, on peut très bien imaginer un dictionnaire avec en guise de clés, des tuples contenant les noms de capitales et les noms de pays et en guise de valeurs, des listes contenant la latitude et la longitude.

coords = {("Paris","France"):["48° 51′ N", "2° 21′ E"], ("Berlin","Allemagne"): ["52° 31′ N", "13° 24′ O"]}
result = coords[("Paris", "France")]
print(result)

Résultat : [’48° 51′ N’, ‘2° 21′ E’]

code_dict
Visualisation du code avec Pythontutor

Supprimer un élément grâce à l’instruction del

Nous avons vu comment rajouter un élément dans un dictionnaire. C’est d’une simplicité enfantine. Pas besoin de faire appel à la méthode append().

Pour supprimer un élément, on utilise l’instruction del. En fait, on supprime la clé et par conséquent, la valeur qui lui est associée.

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
del capitales["Allemagne"]
print(capitales)

Résultat : {‘France’: ‘Paris’, ‘Islande’: ‘Reykjavik’}

Supprimer tout le dictionnaire grâce à l’instruction del

Notez bien que l’instruction del permet également de supprimer tout le dictionnaire. Il suffit pour cela, de ne pas lui passer de clé entre crochets.

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
del capitales
print(capitales)

NameError: name ‘capitales’ is not defined

Ce message d’erreur nous confirme que le dictionnaire n’existe plus.

Utiliser la fonction intégrée len()

On peut également utiliser la fonction intégrée len() pour connaître le nombre de paires clé-valeur contenues dans un dictionnaire.

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
print(len(capitales))

Résultat: 3

Aperçu de quelques méthodes associées aux dictionnaires

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
capitales.clear() # Vide le dictionnaire
print(capitales)

Résultat: {}

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
result = capitales.items()
print(result)

Résultat: dict_items([(‘Islande’, ‘Reykjavik’), (‘France’, ‘Paris’), (‘Allemagne’, ‘Berlin’)])

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
result = capitales.keys()
print(result)

Résultat: dict_keys([‘Islande’, ‘Allemagne’, ‘France’])

capitales = {"France":"Paris", "Allemagne" : "Berlin","Islande": "Reykjavik"}
result = capitales.values()
print(result)

Résultat: dict_values([‘Berlin’, ‘Reykjavik’, ‘Paris’])

Conclusion

Un dictionnaire est un ensemble non ordonné de paires clé-valeur. Chaque clé donne accès à la valeur qui lui est associée. Plus puissant qu’une liste, Un dictionnaire est idéal pour réaliser un test d’appartenance. En effet, comme il s’agit d’une implémentation de table de hachage et non pas d’une séquence, la vitesse d’exécution du test d’appartenance n’est pas liée au nombre d’éléments que le dictionnaire contient.

Il existe des compréhensions de dictionnaire qui feront l’objet d’un chapitre ultérieur.


Gravatar de Benoît Boudaud
Original post of Benoît Boudaud.Votez pour ce billet sur Planet Libre.

Articles similaires

PostBlue : Prosody : mise à jour automatique des modules communautaires

jeudi 9 mars 2017 à 11:40

Pour mettre à jour automatique les modules communautaires que j'utilise sur mon serveur de messagerie instantanée (XMPP) Prosody, j'ai écrit un service systemd ainsi qu'un timer le lançant toutes les nuits.

D'abord, il faut évidemment copier le dépôt des modules communautaires quelque part sur le serveur où tourne prosody (par exemple /usr/local/lib/prosody/modules).

sudo apt update
sudo apt install mercurial
sudo hg clone https://hg.prosody.im/prosody-modules/ /usr/local/lib/prosody/modules

Ensuite, éditer le fichier de configuration sudo -e /etc/prosody/prosody.cfg.lua et y ajouter le chemin vers ce répertoire.

-- These paths are searched in the order specified, and before the default path
plugin_paths = { "/usr/local/lib/prosody/modules" }

Sauvegarder, relancer prosody et vérifier que le chemin est bien pris en compte.

sudo service prosody restart
sudo prosodyctl about

Exemple :

Le répertoire de modules complémentaires étant correctement pris en compte, on peut maintenant créer un service dont la tâche sera de mettre à jour le répertoire cloné.

sudo -e /etc/systemd/system/prosody-up.service

Copier et sauvegarder :

[Service]
Type=oneshot
ExecStart=/usr/bin/hg pull --update --cwd /usr/local/lib/prosody/modules
ExecStartPost=/usr/sbin/service prosody restart

Ensuite un timer invoquant le service ci-dessus à intervalle régulier (toutes les nuits à 2h du matin).

sudo -e /etc/systemd/system/prosody-up.timer

Copier et sauvegarder :

[Unit]
Description=Prosody Modules Updater
After=network-online.target
Wants=network-online.target prosody.service

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Pour finir, il suffit de recharger les services de systemd (par mesure de sécurité), activer le timer et lancer le service.

sudo systemctl daemon-reload
sudo systemctl enable prosody-up.timer
sudo systemctl start prosody-up.service
sudo systemctl status prosody-up.service -l

Gravatar de PostBlue
Original post of PostBlue.Votez pour ce billet sur Planet Libre.

Jean-Baptiste Holcroft : Droit des femmes et traduction ?

jeudi 9 mars 2017 à 00:00

Quel rapport entre le logiciel libre et la journée du droit des femmes ? La qualité de la traduction et de l’internationalisation ! Ici on s’intéressera aux cas concrêts pour ouvrir son logiciel aux minorités, et les femmes sont trop peu présentes dans l’informatique.

En réalisant la mise à jour des applications YunoHost sur mon serveur ce matin, l’interface me demande « Êtes-vous sur de vouloir mettre à jour de tous les applications ? ».

Ici, en plus du petit détail d’accent circonflexe manquant (sûr : être certain, sur : être dessus), on remarque donc deux problèmes liés au genre.

Si l’anglais permet très souvent l’usage de mots neutres, le français tend a donner un genre beaucoup plus rapidement. En anglais, effectivement cela ne se remarque pas : « Are you sure you want update every %s 1 ? ».

On découvre via la phrase source un problème de plus, ici le développeur utilise la même phrase pour parler de choses différentes « %s » peut être un paquet ou une application comme on le voit dans le code du projet… Eh bien ici on donc un problème de traduction et un problème d’internationalisation ! D’ailleurs il y en a d’autres.

Pour le problème de traduction, le fait de sous-entendre que l’utilisateur est un homme peut être résolu très simplement avec la tournure « Voulez-vous vraiment ». Ce n’est pas plus complexe à comprendre et cela utilise moins de place dans les interfaces, tout en étant un peu plus accueillant et équitable.

Pour le second problème, écrire « toutes » rendra cette phrase juste quand on parle d’application, mais fausse quand on parle de paquet. D’ailleurs, rien ne permet d’affirmer que le mot Application ou Paquet sera à la même place dans la phrase pour toutes les langues.

Sur ce dernier point, deux éléments sont importants et intéressants, l’emplacement des mots dans la phrase et la grammaire.

Concernant l’emplacement des mots – la FSF donne un lien très intéressant concernant la traduction sur la page décrivant son projet prioritaire d’internationalisation, c’est un article du W3C y décrit les enjeux rudimentaires de l’internationalisation liés au positionnement des mots dans les phrases selon les langues. Pour aller plus loin, tout ce site concernant l'internationalisation est très intéressant (et traduit).

Concernant la grammaire, certaines langues changent d’orthographe de ses mots en fonction de leur rapport aux autres mots. C’est par exemple le cas des déclinaisons en allemand. Sceptiques ? Voici un exemple avec le site vitrine getfedora cette fois-ci en polonais. « Choisissez la liberté. Choisissez Fedora » est traduit « Wybierz wolność. Wybierz Fedorę. ». Wikimédia m’apprend aujourd’hui qu’il s’agit de « langues flexionnelles ». Donc le fait de dissocier l’objet de la phrase mène très probablement à une mauvaise traduction (le contexte manque et le temps pour fouiller dans le code afin de comprendre n'est souvent pas pris).

Et encore, je n’ai pas traité ici le fait que mettre à jour « une application » ou « plusieurs applications » devrait pouvoir être traduit différemment ! En français c’est simplement deux possibilités (singulier ou pluriel), mais dans d’autres langues, il y a plusieurs formulations possibles… Voir sur le sujet la documentation Gettext ou Android.

Conclusion : internationaliser un logiciel et le traduit est une activité nécessitant beaucoup d’attention pour les développeurs, en plus de l’utilisation d’outils dédiés tel que gettext, il y a des règles de développement qu’il faut respecter, faute de quoi on pense bien faire, mais on ne couvre que de façon très imparfaite les cas effectivement rencontrés par les traducteurs.

Gravatar de Jean-Baptiste Holcroft
Original post of Jean-Baptiste Holcroft.Votez pour ce billet sur Planet Libre.

Benoît Boudaud : #Primtux, une distribution Linux pour les élèves du primaire.

mercredi 8 mars 2017 à 08:56

Bonjour, il y a quelques jours, j’ai découvert Primtux, une distribution « développée (je cite) par une petite équipe de professeurs des écoles et de passionnés de l’informatique dans le milieu éducatif. »

Je trouve que c’est une belle initiative. Ludique et éducative à la fois, elle s’adresse aux élèves scolarisés dans l’enseignement primaire. Je l’ai testée en démo dans une machine virtuelle. Elle contient par exemple une version LibreOffice avec un design beaucoup plus coloré. Cette version offre par exemple la possibilité de coloriser les syllabes d’un mot. Au passage, il y a une magnifique faute d’orthographe avec l’onglet aggrandir (oui vous avez bien lu! Avec deux g). Les professeur des écoles ne l’ont pas remarquée. Bravo! À qui la faute? À la méthode globale ou à la méthode syllabique?

Il y a trois niveaux :

Les niveaux Super et Maxi bénéficient d’un accès internet restreint c’est-à dire qu’il est inutile de taper ebay.fr dans la barre de recherche. Vous obtiendrez un message vous signifiant que l’accès à ce site est interdit. Le moteur de recherche est Qwant Junior.

On trouve également une multitude de petits jeux éducatifs pour assimiler des notions de français, mathématiques, géométrie etc… Voici un aperçu dans la vidéo présente sur le site officiel.


Gravatar de Benoît Boudaud
Original post of Benoît Boudaud.Votez pour ce billet sur Planet Libre.

Thuban : Être averti des mises à jours de -current disponibles.

mardi 7 mars 2017 à 16:30

Grande nouvelle, j'ai atteint mon objectif : longueur de barbe > longueur de cheveux. De quoi faire un T-shirt "Achievement unlocked" si ça en intéresse certains...

Quoi? oO Tout le monde s'en fout ? :D

Bon, de quoi voulais-je parler? Ah oui, les mises à jour de -current.

OpenBSD -current permet de suivre les derniers développements effectués et d'avoir les toutes dernières versions des paquets.
Bien que ça ne soit pas obligatoire, il faut en général veiller à ce que les paquets et la base du système soient synchrones avant de procéder à la mise à jour.

L'outil snaps de fredg vérifie ces informations. Cela dit, ça suppose que l'on prenne le temps de lancer snaps régulièrement, ce que j'oublie.

Du coup, j'ai repris une partie du code de snaps pour le mettre dans un script nommé ocun - OpenBSD current update notifier. Ce dernier vérifie si votre miroir dispose d'un nouveau snapshot et vous l'indique.

Afin de garder les choses simples et permettre à chacun de faire comme bon lui semble, le script ne fait qu'indiquer en sortie s'il y a un nouveau snapshot. Libre à vous de relayer l'information par mail, par libnotify, flux rss ou que sais-je...

Par exemple, j'ai rajouté cette ligne dans mon fichier /etc/daily.local afin que la vérification soit quotidienne (ça fonctionnerait aussi dans un crontab) :

/usr/local/bin/ocun | mail -E -s "-current update avaiable" monmail@blabla.com

N'oubliez pas de lire la page permettant de suivre -current après chaque mise à jour : https://www.openbsd.org/faq/current.html.

Gravatar de Thuban
Original post of Thuban.Votez pour ce billet sur Planet Libre.