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.

python-05.md 9.5 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. % Programmation avec Python (chapitre 5)
  2. % Dimitri Merejkowsky
  3. #
  4. \center \huge Suite de l'atelier précédent
  5. # Rappel
  6. Travail de la dernière fois.
  7. Les problèmes que j'ai vus:
  8. * noms
  9. * méthodologie
  10. #
  11. \center \huge naming
  12. # Quelques principes
  13. L'un des problèmes les plus compliqué de l'informatique
  14. * Tout en anglais (sorry)
  15. * Pas d'abréviation
  16. * Pas de redondance
  17. # Exemples
  18. * `get_freq` -> `get_frequencies`
  19. * `nom_fich` -> `filename`
  20. * `list_frag` -> `fragments` # le pluriel nous dit que c'est une liste
  21. * `liste_mot` -> `words`
  22. Essayez de rester cohérents!
  23. # Exemples (2)
  24. ```python
  25. # Avant
  26. for fragment in list_frag:
  27. fragment_min = fragment.lower()
  28. frag_clean = clean(fragment_min)
  29. liste_mot.append(frag_clean)
  30. ```
  31. ```python
  32. # Après
  33. for fragment in fragments:
  34. fragment = fragment.lower()
  35. fragment = clean(fragment)
  36. words.append(fragment)
  37. ```
  38. On peut ré-utiliser le même nom plusieurs fois!
  39. #
  40. \center \huge Style
  41. # Espaces - exemple
  42. \vfill
  43. ```python
  44. def foo(a, b):
  45. a = 42
  46. bar(a, spam=False)
  47. def bar(a, spam=True):
  48. ...
  49. ```
  50. # Espaces - règles
  51. * Deux lignes entre chaque fonction
  52. * Des espaces autour des `=` pour les affectations
  53. * Pas d'espace quand c'est un argument nommé
  54. * Exactement un espace après chaque virgule
  55. Question de convention. Voir PEP8.
  56. #
  57. \center \huge Repartons du début
  58. \normalsize (un genre de corrigé)
  59. # Revoir les changements chez vous
  60. Vous pourrez voir la suite des changements sur github:
  61. https://github.com/E2L/cours-python/tree/master/sources/topwords/
  62. # Note importante
  63. En programmation, il y a très rarement une seule
  64. bonne réponse !
  65. Ceci n'est qu'une solution possible, et une *technique possible*
  66. pour arriver à cette solution ...
  67. # Découper les mots
  68. Dans la liste se trouvent des mots mal découpés:
  69. * `peutétre`
  70. * `lhumanité`
  71. Il faut revoir pas mal de code! (comme souvent après la découverte
  72. d'un bug).
  73. On va essayer d'être plus méthodique.
  74. # Tester chaque fonction une par une
  75. * Spécification
  76. * Test
  77. * Implémentation
  78. # Découpage en fragments - spécification
  79. On a:
  80. > L'univers est, peut-être, « infini! »
  81. On veut:
  82. ```python
  83. ["l", "univers", "est", "peut-être", '«', "infini", '»']
  84. ```
  85. On s'occupera d'enlever la ponctuation plus tard.
  86. # Découpage en fragments - test
  87. ```python
  88. contents = "L'unives est, peut-être, infini!"
  89. fragments = split_fragments(contents)
  90. print(fragments)
  91. ```
  92. # Découpage en fragments - implémentation
  93. ```python
  94. def split_fragments(contents):
  95. res = list()
  96. for fragment in contents.split():
  97. if "’" in fragment:
  98. (before, after) = fragment.split("’")
  99. res.append(before)
  100. res.append(after)
  101. else:
  102. res.append(fragment)
  103. return res
  104. ```
  105. # Découpage en mots - spécification
  106. On a:
  107. ```
  108. L'unives est, peut-être, « infini! »
  109. ```
  110. On veut:
  111. ```
  112. ['l', 'unives', 'est', 'peut-être', 'infini']
  113. ```
  114. # Découpage en mots - test
  115. ```python
  116. contents = "L'univers est, peut-être, « infini! »"
  117. words = split_words(contents)
  118. print(words)
  119. ```
  120. # Découpage en mots - implémentation
  121. On peut reprendre le code vu ensemble,
  122. avec quelques modifications:
  123. ```python
  124. def split_words(text):
  125. fragments = split_fragments(text)
  126. res = list()
  127. for fragment in fragments:
  128. fragment = fragment.lower()
  129. fragment = clean_fragment(fragment)
  130. if fragment: # le fragment peut-être vide ici
  131. res.append(fragment)
  132. return res
  133. ```
  134. # clean_fragment()
  135. Juste une petite modification:
  136. ```python
  137. def clean_fragment(fragment):
  138. result = ""
  139. for c in fragment:
  140. # autorise les tirets et apostrophes à l'intérieur
  141. # des mots
  142. if c.isalpha() or c in ["-", "'"]:
  143. result += c
  144. return result
  145. ```
  146. # Calcul des fréquences - spécification
  147. On a:
  148. ```python
  149. ["pomme", "poire", "banane", "poire", "banane", "banane"]`
  150. ```
  151. On veut:
  152. ```python
  153. {"pomme": 1, "poire": 2, "banane": 3}
  154. ```
  155. \vfill
  156. Note: par encore d'ordre ici!
  157. # Calcul des fréquences - test
  158. ```python
  159. words = [
  160. "pomme", "poire", "banane",
  161. "poire", "banane", "banane"
  162. ]
  163. frequencies = get_frequencies(words)
  164. print(frequencies)
  165. ```
  166. # Calcul des fréquences - implémentation
  167. ```python
  168. def get_frequencies(words):
  169. res = dict()
  170. for word in words:
  171. # Si le mot est déjà là, on incrémente
  172. # son compteur:
  173. if word in res:
  174. res[word] += 1
  175. else:
  176. # Sinon on crée une nouvelle clé
  177. # avec la valeur 1
  178. res[word] = 1
  179. return res
  180. ```
  181. # Tri - spécification
  182. On a:
  183. ```python
  184. {'pomme': 1, 'poire': 2, 'banane': 3}
  185. ```
  186. On veut:
  187. ```python
  188. [
  189. (3, 'banane'),
  190. (2, 'poire'),
  191. (1 'pomme'),
  192. ]
  193. ```
  194. # Tri - test
  195. ```python
  196. frequencies = {'pomme': 1, 'poire': 2, 'banane': 3}
  197. scores = get_scores(frequencies)
  198. print(scores)
  199. ```
  200. # Tri - implémentation
  201. ```python
  202. def get_scores(frequencies):
  203. res = list()
  204. for word, count in frequencies.items():
  205. res.append((count, word))
  206. res.sort(reverse=True)
  207. return res
  208. ```
  209. # Affichage des résultats
  210. On a :
  211. ```python
  212. scores = [
  213. (20, "banane"),
  214. (19, "poire"),
  215. ...
  216. ]
  217. ```
  218. On veut:
  219. ```
  220. 20 banane
  221. 19 poire
  222. ```
  223. # Affichage des résultats - test
  224. ```python
  225. scores = [
  226. (20, "banane"),
  227. (19, "poire"),
  228. ...
  229. ]
  230. print_scores(scores)
  231. ```
  232. # Affichage des résultats - implémentation
  233. ```python
  234. def print_scores(scores):
  235. for count, word in scores:
  236. print(count, word)
  237. ```
  238. # Assemblons les morceaux
  239. ```python
  240. def main():
  241. filename = "ruffin.txt"
  242. file = open(filename)
  243. contents = file.read()
  244. words = split_words(contents)
  245. frequencies = get_frequencies(words)
  246. scores = get_scores(frequencies)
  247. top_words = scores[:20] # le top 20
  248. print_scores(top_words)
  249. main()
  250. ```
  251. # Touches finales
  252. C'est bien si le nom du fichier est lu depuis la ligne de commande:
  253. ```python
  254. import sys
  255. def main():
  256. if len(sys.argv) < 2:
  257. sys.exit("not enough arguments")
  258. filename = sys.argv[1]
  259. ...
  260. ```
  261. #
  262. \center \huge Compléments - tris
  263. # sort() - ordre naturel
  264. ```python
  265. >>> nombres = [2, 3, 1, 5]
  266. >>> nombres.sort()
  267. >>> nombres
  268. [1, 2, 3, 5]
  269. ```
  270. Notez que la liste est modifiée *sur place*.
  271. # sort() - ordre alphabétique
  272. ```python
  273. >>> mots = ["abeille", "faucon", "chat"]
  274. >>> mots.sort()
  275. >>> mots
  276. ['abeille', 'chat', 'faucon']
  277. ```
  278. # sort() - ordre lexicographique
  279. Pour chaque "liste-élément" on compare le premier élément.
  280. S'il y a égalité, on regarde le deuxième élément, etc:
  281. ```python
  282. >>> composite = [["chat", 1], ["abeille", 2], ["chat", 3]]
  283. >>> composite.sort()
  284. >>> composite
  285. [['abeille', 2], ['chat', 1], ['chat', 3]]
  286. ```
  287. L'ordre alphabétique est l'ordre lexicographique pour les chaînes de caractères :)
  288. # Attention!
  289. Tous les éléments de la liste doivent être comparables deux à deux:
  290. \vfill
  291. ```python
  292. >>> mauvaise_liste = ["un", 2]
  293. >>> mauvaise_liste.sort()
  294. TypeError
  295. ```
  296. # Comparer autrement
  297. Exemple: trier les mots par leur taille avec l'argument `key`
  298. \vfill
  299. ```python
  300. def taille(mot):
  301. return len(mot)
  302. mots = ["chat", "abeille", "faucon"]
  303. mots.sort(key=taille)
  304. >>> mots
  305. ["chat", "faucon", "abeille"]
  306. ```
  307. # Lambda
  308. Sert définir une fonction sans utiliser `def`
  309. ```python
  310. >>> retourne_42 = lambda: 42 # pas d'argument
  311. >>> retourne_42()
  312. 42
  313. >>> ajoute_deux = lambda x: x + 2 # un seul argument
  314. >>> ajoute_deux(3)
  315. 5
  316. >>> multiplie = lambda x, y: x* y # deux arguments
  317. >>> multiplie(2, 3)
  318. 6
  319. ```
  320. Note: le corps de la fonction doit tenir en une seule ligne
  321. # Utilisation avec sort
  322. ```python
  323. >>> mots = ["chat", "abeille", "faucon"]
  324. >>> mots.sort(key=lambda x: len(x))
  325. >>> mots
  326. ["chat", "faucon", "abeille"]
  327. ```
  328. # sorted()
  329. Si on a besoin de l'ordre initial après coup:
  330. ```python
  331. b = a.copy()
  332. b.sort()
  333. # ou:
  334. b = sorted(a)
  335. ```
  336. #
  337. \center \huge Compléments - fichiers
  338. # Rappel: lire
  339. ```python
  340. file = open("toto.txt", "r") # 'r' comme 'read'
  341. contenu = file.read()
  342. file.close()
  343. ```
  344. Note: le fichier `toto.txt` doit exister!
  345. # Écrire
  346. On peut écrire tout le contenu d'un coup:
  347. ```python
  348. contenu = "du texte à sauvegarder"
  349. file = open("article.txt", "w") # 'w' comme 'write'
  350. file.write(contenu)
  351. file.close()
  352. ```
  353. * Le fichier `article.txt` sera écrasé s'il existe déjà.
  354. * N'oubliez surtout pas d'appeler `close()`
  355. # Que faire en cas d'erreur ?
  356. ```python
  357. file = open("article.txt", "w") # 'w' comme 'write'
  358. # ... beacoup de code ici
  359. # ... < une erreur
  360. file.close()
  361. ```
  362. S'il y a une erreur entre `open()` et `close()`, le fichier ne sera pas fermé!
  363. # Le mot-clé with
  364. ```python
  365. with open("toto.txt", "w") as file:
  366. file.write("du texte")
  367. ```
  368. Quand on sort du bloc `with` on a la garantie que `file.close()` sera appelé,
  369. *même* si on sort du bloc à cause d'une erreur.
  370. # Convention
  371. Il n'y a maintenant plus aucune raison d'appeler `.close()` "à la main",
  372. donc ne le faites pas et utilisez `with`.
  373. # Lire et écrire des lignes
  374. Très courant:
  375. ```python
  376. with open("toto.txt", "r") as file:
  377. lignes = file.readlines()
  378. # faire quelque chose avec la liste de lignes
  379. with open("toto.txt", "w") as file:
  380. file.writelines(lignes)
  381. ```
  382. Pensez à fermer le premier fichier avant d'ouvrir le second.
  383. (ça marche même s'ils ont le même nom)
  384. #
  385. \center \huge Atelier 2
  386. # Problème à résoudre
  387. Garder une liste de scores persistent dans
  388. le jeu du pendu
  389. # Point de départ
  390. https://github.com/E2L/cours-python/tree/master/sources/hangman
  391. * Version modifiée du pendu (grâce aux suggestions de certains
  392. d'entre vous)
  393. * Préparation d'un squelette isolé
  394. # Pour la prochaine fois
  395. * Essayez d'implémenter la gestion des scores multi joueurs
  396. dans `hangman.py` en partant de `scores.py`.
  397. * Envoyez moi vos solutions par e-mail :)