% Programmation avec Python (chapitre 5) % Dimitri Merejkowsky
\center \huge Suite de l’atelier précédent
Travail de la dernière fois.
Les problèmes que j’ai vus:
\center \huge naming
L’un des problèmes les plus compliqué de l’informatique
get_freq
-> get_frequencies
nom_fich
-> filename
list_frag
-> fragments
# le pluriel nous dit que c’est une listeliste_mot
-> words
Essayez de rester cohérents!
# Avant
for fragment in list_frag:
fragment_min = fragment.lower()
frag_clean = clean(fragment_min)
liste_mot.append(frag_clean)
# Après
for fragment in fragments:
fragment = fragment.lower()
fragment = clean(fragment)
words.append(fragment)
On peut ré-utiliser le même nom plusieurs fois!
\center \huge Style
\vfill
def foo(a, b):
a = 42
bar(a, spam=False)
def bar(a, spam=True):
...
=
pour les affectationsQuestion de convention. Voir PEP8.
\center \huge Repartons du début
\normalsize (un genre de corrigé)
Vous pourrez voir la suite des changements sur github:
https://github.com/E2L/cours-python/tree/master/sources/topwords/
En programmation, il y a très rarement une seule bonne réponse !
Ceci n’est qu’une solution possible, et une technique possible pour arriver à cette solution ...
Dans la liste se trouvent des mots mal découpés:
peutétre
lhumanité
Il faut revoir pas mal de code! (comme souvent après la découverte d’un bug).
On va essayer d'être plus méthodique.
On a:
L’univers est, peut-être, « infini! »
On veut:
["l", "univers", "est", "peut-être", '«', "infini", '»']
On s’occupera d’enlever la ponctuation plus tard.
contents = "L'unives est, peut-être, infini!"
fragments = split_fragments(contents)
print(fragments)
def split_fragments(contents):
res = list()
for fragment in contents.split():
if "’" in fragment:
(before, after) = fragment.split("’")
res.append(before)
res.append(after)
else:
res.append(fragment)
return res
On a:
L'unives est, peut-être, « infini! »
On veut:
['l', 'unives', 'est', 'peut-être', 'infini']
contents = "L'univers est, peut-être, « infini! »"
words = split_words(contents)
print(words)
On peut reprendre le code vu ensemble, avec quelques modifications:
def split_words(text):
fragments = split_fragments(text)
res = list()
for fragment in fragments:
fragment = fragment.lower()
fragment = clean_fragment(fragment)
if fragment: # le fragment peut-être vide ici
res.append(fragment)
return res
Juste une petite modification:
def clean_fragment(fragment):
result = ""
for c in fragment:
# autorise les tirets et apostrophes à l'intérieur
# des mots
if c.isalpha() or c in ["-", "'"]:
result += c
return result
On a:
["pomme", "poire", "banane", "poire", "banane", "banane"]`
On veut:
{"pomme": 1, "poire": 2, "banane": 3}
\vfill
Note: par encore d’ordre ici!
words = [
"pomme", "poire", "banane",
"poire", "banane", "banane"
]
frequencies = get_frequencies(words)
print(frequencies)
def get_frequencies(words):
res = dict()
for word in words:
# Si le mot est déjà là, on incrémente
# son compteur:
if word in res:
res[word] += 1
else:
# Sinon on crée une nouvelle clé
# avec la valeur 1
res[word] = 1
return res
On a:
{'pomme': 1, 'poire': 2, 'banane': 3}
On veut:
[
(3, 'banane'),
(2, 'poire'),
(1 'pomme'),
]
frequencies = {'pomme': 1, 'poire': 2, 'banane': 3}
scores = get_scores(frequencies)
print(scores)
def get_scores(frequencies):
res = list()
for word, count in frequencies.items():
res.append((count, word))
res.sort(reverse=True)
return res
On a :
scores = [
(20, "banane"),
(19, "poire"),
...
]
On veut:
20 banane
19 poire
scores = [
(20, "banane"),
(19, "poire"),
...
]
print_scores(scores)
def print_scores(scores):
for count, word in scores:
print(count, word)
def main():
filename = "ruffin.txt"
file = open(filename)
contents = file.read()
words = split_words(contents)
frequencies = get_frequencies(words)
scores = get_scores(frequencies)
top_words = scores[:20] # le top 20
print_scores(top_words)
main()
C’est bien si le nom du fichier est lu depuis la ligne de commande:
import sys
def main():
if len(sys.argv) < 2:
sys.exit("not enough arguments")
filename = sys.argv[1]
...
\center \huge Compléments - tris
>>> nombres = [2, 3, 1, 5]
>>> nombres.sort()
>>> nombres
[1, 2, 3, 5]
Notez que la liste est modifiée sur place.
>>> mots = ["abeille", "faucon", "chat"]
>>> mots.sort()
>>> mots
['abeille', 'chat', 'faucon']
Pour chaque “liste-élément” on compare le premier élément. S’il y a égalité, on regarde le deuxième élément, etc:
>>> composite = [["chat", 1], ["abeille", 2], ["chat", 3]]
>>> composite.sort()
>>> composite
[['abeille', 2], ['chat', 1], ['chat', 3]]
L’ordre alphabétique est l’ordre lexicographique pour les chaînes de caractères :)
Tous les éléments de la liste doivent être comparables deux à deux:
\vfill
>>> mauvaise_liste = ["un", 2]
>>> mauvaise_liste.sort()
TypeError
Exemple: trier les mots par leur taille avec l’argument key
\vfill
def taille(mot):
return len(mot)
mots = ["chat", "abeille", "faucon"]
mots.sort(key=taille)
>>> mots
["chat", "faucon", "abeille"]
Sert définir une fonction sans utiliser def
>>> retourne_42 = lambda: 42 # pas d'argument
>>> retourne_42()
42
>>> ajoute_deux = lambda x: x + 2 # un seul argument
>>> ajoute_deux(3)
5
>>> multiplie = lambda x, y: x* y # deux arguments
>>> multiplie(2, 3)
6
Note: le corps de la fonction doit tenir en une seule ligne
>>> mots = ["chat", "abeille", "faucon"]
>>> mots.sort(key=lambda x: len(x))
>>> mots
["chat", "faucon", "abeille"]
Si on a besoin de l’ordre initial après coup:
b = a.copy()
b.sort()
# ou:
b = sorted(a)
\center \huge Compléments - fichiers
file = open("toto.txt", "r") # 'r' comme 'read'
contenu = file.read()
file.close()
Note: le fichier toto.txt
doit exister!
On peut écrire tout le contenu d’un coup:
contenu = "du texte à sauvegarder"
file = open("article.txt", "w") # 'w' comme 'write'
file.write(contenu)
file.close()
article.txt
sera écrasé s’il existe déjà.close()
file = open("article.txt", "w") # 'w' comme 'write'
# ... beacoup de code ici
# ... < une erreur
file.close()
S’il y a une erreur entre open()
et close()
, le fichier ne sera pas fermé!
with open("toto.txt", "w") as file:
file.write("du texte")
Quand on sort du bloc with
on a la garantie que file.close()
sera appelé,
même si on sort du bloc à cause d’une erreur.
Il n’y a maintenant plus aucune raison d’appeler .close()
“à la main”,
donc ne le faites pas et utilisez with
.
Très courant:
with open("toto.txt", "r") as file:
lignes = file.readlines()
# faire quelque chose avec la liste de lignes
with open("toto.txt", "w") as file:
file.writelines(lignes)
Pensez à fermer le premier fichier avant d’ouvrir le second. (ça marche même s’ils ont le même nom)
\center \huge Atelier 2
Garder une liste de scores persistent dans le jeu du pendu
https://github.com/E2L/cours-python/tree/master/sources/hangman