You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 
 
 
 
 

8.3 KiB

% Programmation avec Python (chapitre 5) % Dimitri Merejkowsky

\center \huge Suite de l’atelier précédent

Rappel

Travail de la dernière fois.

Les problèmes que j’ai vu:

  • noms
  • méthodologie

\center \huge naming

Quelques principes

  • L’un des problèmes les plus compliqué de l’informatique

  • Tout en Anglais

  • Pas d’abbréviation

  • Pas de redondance

Exemples

  • get_freq -> get_frequencies
  • nom_fich -> filename
  • list_frag -> fragments # le pluriel nous dit que c’est une liste
  • liste_mot -> words

Essayez de rester cohérents!

Exemples (2)

# 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)
   liste_mot.append(fragment)

On peut ré-utiliser le même nom plusieurs fois!

\center \huge Style

Espaces

  • Deux lignes entre chaque fonction
  • Des espaces autour des = pour les affectations
  • Pas d’espace quand c’est un argument nommé

\center \huge Repartons du début

Découper les mots

Dans la liste se trouvent des mots mal découpés:

  • peutétre
  • lhumanité

Reprenons depuis le début

Tester chaque fonction une par une

  • Spécification
  • Test
  • Implémentation

Découpage en fragments - spécification

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.

Découpage en fragments - test

contents = "L'unives est, peut-être, infini!"
fragments = split_fragments(contents)
print(fragments)

Découpage en fragments - implémentation

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

Découpage en mots - spécification

On a:

L'unives est, peut-être, « infini! »

On veut:

['l', 'unives', 'est', 'peut-être', 'infini']

Découpage en mots - test

contents = "L'univers est, peut-être, « infini! »"
words = split_words(contents)
print(words)

Découpage en mots - implémentation

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

clean_fragment()

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

Calcul des fréquences - spécification

On a:

["pomme", "poire", "banane", "poire", "banane", "banane"]`

On veut:

{"pomme": 1, "poire": 2, "banane": 3}

\vfill

Note: par encore d’ordre ici!

Calcul des fréquences - test

words = [
   "pomme", "poire", "banane",
   "poire", "banane", "banane"
]
frequencies = get_frequencies(words)
print(frequencies)

Calcul des fréquences - implémentation

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

Tri - spécification

On a:

{'pomme': 1, 'poire': 2, 'banane': 3}

On veut:

[
   (3, 'banane'),
   (2, 'poire'),
   (1 'pomme'),
]

Tri - test

frequencies = {'pomme': 1, 'poire': 2, 'banane': 3}
scores = get_scores(frequencies)
print(scores)

Tri - implémentation

def get_scores(frequencies):
   res = list()
   for word, count in frequencies.items():
      res.append((count, word))
   res.sort(reverse=True)
   return res

Affichage des résultats

On a :

scores = [
   (20, "banane"),
   (19, "poire"),
   ...
]

On veut:

20 banane
19 poire

Affichage des résultats - test

scores = [
   (20, "banane"),
   (19, "poire"),
   ...
]
print_scores(scores)

Affichage des résultats - implémentation

def print_scores(scores):
   for count, word in scores:
      print(count, word)

Assemblons les morceaux

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()

Touches finales

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

sort() - ordre naturel

>>> nombres = [2, 3, 1, 5]
>>> nombres.sort()
>>> nombres
[1, 2, 3, 5]

Notez que la liste est modifiée sur place.

sort() - ordre alphabétique

>>> mots = ["abeille", "faucon", "chat"]
>>> mots.sort()
>>> mots
['abeille', 'chat', 'faucon']

sort() - ordre lexicographique

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 :)

Attention!

Tous les éléments de la liste doivent être comparables deux à deux:

\vfill

>>> mauvaise_liste = ["un", 2]
>>> mauvaise_liste.sort()
TypeError

Comparer autrement

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"]

Lambda

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

Utilisation avec sort

>>> mots = ["chat", "abeille", "faucon"]
>>> mots.sort(key=lambda x: len(x))
>>> mots
["chat", "faucon", "abeille"]

sorted()

b = a.copy()
b.sort()

# or
b = sorted(a)

\center \huge Compléments - fichiers

Rappel: lire

file = open("toto.txt", "r")   # 'r' comme 'read'
contenu = file.read()
file.close()

Note: le fichier toto.txt doit exister!

Écrire

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()
  • Le fichier article.txt sera écrasé s’il existe déjà.
  • N’oubliez surtout pas d’appeler close()

Que faire en cas d’erreur ?

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é!

Le mot-clé with

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.

Convention

Il n’y a maintenant plus aucune raison d’appeler .close() “à la main”, donc ne le faites pas ...

Lire et écrire des lignes

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)