6D: Conception, débogage et beignets

Cette leçon a quelques suggestions sur des façons de faciliter la conception et le débogage de vos programmes. Le plus d’expérience vous aurez avec la programmation, le meilleur vous deviendrez à éviter et corriger des erreurs, mais ici, nous allons essayer de vous donner quelques conseils généraux et utiles. Nous allons vous expliquer les techniques suivantes:

  • la conception un morceau à la fois
  • résolution de certains exemples à la main
  • la planification de code avant sa création
  • l’écriture du code
  • tester les exemples que vous avez résolu à la main
  • tester des exemples supplémentaires, y compris des cas "limites" et aléatoires

Cette formule magique ne résoudra pas tout automatiquement, mais pourra vous faire économiser de maux de tête et réduira le nombre de problèmes dont vous devrez vous préoccupez plus tard.

Lorsque vous rencontrez un problème, des stratégies pour vous aider à déboguer sont d'utiliser l'aide de diagnostic par impression d'instructions d'impression (nous ferons cela plus tard dans la leçon), en utilisant le visualiseur, la lecture de votre code avec soin, et la création de bons tests. Si vous exécutez Python à la maison, vous pouvez utiliser des outils de point d'arrêt et pas à pas pour obtenir un meilleur aperçu de ce qui se passe mal.

Un algorithme désigne une série d'instructions. Bien qu'un programme informatique a besoin d'être écrit dans une langue spécifique comme Python ou JavaScript pour fonctionner, le mot algorithme signifie, la liste, étape par étape, des instructions qui peuvent être écrites en langue naturelle ou exprimées dans un diagramme. Par exemple, une recette de beignets est un algorithme, où "mesure 3 tasses de farine" est une étape, et «laisser lever la pâte pendant 2 heures" est une autre étape. Nous allons développer un algorithme simple dans cette leçon. Ensuite, nous allons mettre en œuvre l'algorithme, ce qui signifie de le convertir en un programme informatique de travail.

Le problème: Calculatrice de beignets

Tim Horton, une chaîne de magasins de café au Canada, vend des beignes «timbits», qui sont de savoureux beignets sphériques:

Photo: looking_and_learning, flickr

Vous devez organiser plusieurs fêtes dans les prochaines semaines, et vous allez commander un nombre de beignets différent pour chaque fête. Donc, vous voulez faire un programme pour calculer le prix d'un nombre arbitraire de beignets, afin de planifier votre budget. À votre succursale locale, les prix sont les suivants:

Number Price
1 0.20 $
10 (boîte de petite taille) 1.99 $
20 (boîte de taille moyenne) 3.39 $
40 (boîte de grande taille) 6.19 $

Construire une partie à la fois

Au final, vous souhaitez écrire un programme où l'entrée est P, le nombre de personnes à la fête, et la sortie est le coût pour nourrir ce nombre de personnes, taxes comprises. Au plus haut niveau, il ya trois composantes de ce programme:

  1. calculez, pour P personnes, quel est le nombre T de beignets que vous devrez acheter?
  2. calculez le prix pour d’achat pour exactement T beignets «timbits»
  3. calculez les taxes et le coût total.

Cependant, vous pouvez travailler sur ces trois parties une à la fois. En fait, nous vous recommandons de créer une partie à la fois, avec les essais et la complétion de chaque partie, avant de passer à la partie suivante, car plus votre programme est long, plus il est difficile de trouver et de corriger chaque bogue. Il est plus facile de développer et de tester les trois parties séparément, avant de les combiner en un seul programme. Pour le reste de cette leçon, nous allons nous concentrer sur l'étape 2: calculer le prix d'achat pour exactement T beignets «timbits».

Résoudre quelques exemples à la main

Afin d'être en mesure de dire à l'ordinateur de faire quelque chose, vous devez être en mesure de le faire vous-même. Nous devons travailler à travers un exemple nous-mêmes: quel est le prix pour acheter exactement 45 beignets «timbits»? En regardant la liste des formats, on peut acheter une grande boîte (40), qui coûtera 6,19 $. Cela laisse 45 – 40 = 5 timbits plus que nous besoin d'acheter individuellement, ce qui a un coût supplémentaire de 5 * 0,20 $ = 1,00 $. Le coût total sera 6,19 $ + 1,00 $ = 7,19 $.

Planifier votre code avant de commencer à l'écrire

Que faire si nous voulions acheter 4 ou 456 timbits au lieu de 45? En général, nous devrions acheter autant de grandes boîtes que possible, puis prendre une boîte moyenne et / ou une petite boîte, si nécessaire, et, finalement, les «timbits» individuels pour obtenir le total voulu.

Est-ce vraiment algorithme optimal? Oui! Vous pouvez voir que l'achat deux boîtes de taille moyenne (2 * 3,39 $ = 6,78 $) est une mauvaise idée car nous pouvons obtenir 2 * 20 = 40 dans une boîte de beignes, à un prix plus avantageux. Des comparaisons similaires de l' achat individuel / petit et petit / moyen peuvent être utilisées pour trouver l'algorithme donnant le prix le moins cher d'acheter un nombre exact de beignets. Si les prix ou la taille étaient différents, nous devrions être plus prudents.

Nous avons dit que vous devez planifier votre code avant de commencer à l'écrire. Vous pouvez:

  • donner une courte description, étape par étape, de l’algorithme en français au lieu d’en Python.
  • utiliser un diagramme ou organigramme pour montrer les étapes
  • se concentrer sur les idées principales au lieu des détails, pour l’instant.

Dans notre exemple, nous allons donner une description en français. Nous n’allons pas de vous montrer un organigramme pour ce programme particulier, car il représenterait tout simplement un enchaînement de l'étape 1 à l'étape 2 et ainsi de suite de manière linéaire. Les programmes avec boucle(s), comme nous le verrons plus tard, profite davantage de diagrammes.

Algorithme pour calculer le prix de n'importe quel nombre de beignets

  1. obtenir le nombre d’entrée de beignets
  2. garder l'information du coût total, en commençant à zéro
  3. acheter autant de grandes boîtes que possible
    1. calculer le nombre de beignets encore nécessaires
    2. mettre à jour le prix total
    3. acheter une boîte moyenne si vous le pouvez et répétez les étapes A et B.
    4. acheter une petite boîte si vous le pouvez et répétez les étapes A et B.
    5. acheter des beignets individuels et répétez l’étape B.
    6. fournir, en sortie le coût total

Nous appelons ceci une description pseudocode de l'algorithme, car il s'agit d'une série de l'étape-par-étape des instructions, mais pas dans un langage de programmation réel.

Ecrire le code

Réitérant le premier conseil, construire une partie à la fois, vous pouvez également penser à écrire un morceau de code distinct pour chaque étape de 1 à 7. En outre, ici, voici une chose à laquelle nous devons penser pour toutes les étapes: quelles variables allons-nous utiliser? Quels vont être leurs noms, types et valeurs initiales?

Nous allons utiliser timbitsRestant pour représenter le nombre de beignets que nous avons encore à acheter, et nous allons utiliser prixTotal pour représenter le coût total à jour. Nous n'avons pas besoin de dire les types à l'avance, mais nous pouvons planifier pour nous-mêmes que timbitsRestant sera un int, alors que prixTotal sera une variable de type float qui contient le coût total en dollars. (Donc, un cent est 0,01). Nous aurons besoin de certaines variables temporaires supplémentaires à chaque étape, que nous allons traiter seulement lorsque cela est nécessaire.

Les étapes 1 et 2 peuvent être écrites avec en une seule ligne de code:

timbitsRestant = int(input())        # étape 1: obtenir l'entrée
prixTotal = 0                        # étape 2: initialiser le coût total
Pour l'étape 3, nous avons besoin pour calculer le nombre maximal de grandes boîtes que l'on peut acheter. Comment exactement pouvons-nous faire cela? Puisqu’une grande boîte contient 40 timbits, le nombre grandeBoites devrait être le quotient entier de timbitsRestant divisé par 40. En tenant compte de la division, le coût, et en soustrayant, nous avons le fragment de code suivant:

# étape 3: acheter autant de grandes boîtes comme vous pouvez 
grandeBoites = timbitsRestant / 40 
# mettre à jour le prix total : 
prixTotal = prixTotal + grandeBoites * 6,19         
# calculer le nombre de timbits encore nécessaires : 
timbitsRestant = timbitsRestant - 40 * grandeBoites
En fait, il s'avère que nous avons déjà fait une erreur. La meilleure façon de repérer des erreurs est de tester votre code tôt et souvent! Soyons optimiste et disons que nous avons testé le code partiellement à ce stade. Nous allons juste ajouter quelques déclarations d'impression pour observer son comportement actuel. (Au lieu d'utiliser des instructions d'impression, vous pouvez également utiliser le visualiseur pour vérifier chaque étape.)

Exemple
Tester le code jusqu'à présent sur l'entrée 45, à l'aide des instructions d'impression (print) pour aider le débogage.

Cela ne fonctionne pas comme nous voulons! Quel est le problème? Où est la première ligne où ce que nous attendons est différent de ce qui s'est passé? Essayez de le localiser avant d'ouvrir le prochain paragraphe. Rappelez-vous, nous avons résolu cet exemple à la main plus tôt.

Cliquez ici pour lire l'explication
Le coupable est la ligne grandeBoites = timbitsRestant / 40, puisque grandeBoites sort que 1.125, alors que nous voulions que ce soit égal à 1. Vous ne pouvez pas acheter une fraction d'une boîte. Une solution de contournement possible, que vous verrez dans la leçon 7A, est d'utiliser // pour la division entière au lieu de / qui ne la division décimale. Une autre solution, basée sur ce que nous avons vu dans la leçon 4, est de convertir timbitsRestant / 40 en un int qui permet de supprimer la partie fractionnaire. Nous allons utiliser cette approche à la place: la ligne devient grandeBoites = int(timbitsRestant / 40).

Les étapes 4 et 5 sont similaires à l'étape 3. Puisque vous allez acheter au plus un boîte moyenne et au plus une petite boîte, on peut utiliser une instruction if:

if timbitsRestant >= 20: # étape 4, peut-on acheter une boîte moyenne?
  prixTotal = prixTotal + 3.39 
  timbitsRestant = timbitsRestant - 20 
if timbitsRestant >= 10: # étape 5, peut-on acheter une petite boîte?  
  prixTotal = prixTotal + 1.99  
  timbitsRestant = timbitsRestant - 20
Pour finir, nous avons besoin de payer 20 cents pour chacun des derniers timbits nécessaires et de sortir la réponse.

prixTotal = prixTotal + timbitsRestant * 20 # étape 6 
print(prixTotal)                            # étape 7

Testez les exemples que vous avez résolus à la main

Voici l'ensemble du programme. La première chose que nous allons faire est de tester pour voir si cela fonctionne sur l'entrée 45 que nous avons résolue à la main.

Exemple
Quel est le prix de 45 timbits?
Vous pouvez entrer des données pour le programme dans la boîte ci-dessous.

Il doit y avoir une erreur (un bogue), puisque nous payons plus de 100 dollars pour seulement 45 timbits! Votre travail final est de trouver et d'éliminer ce bogue, et un autre bogue caché dans le code. Il sera testé dans la section suivante.

Juste pour que vous le sachiez, il y a une drôle de chose qui se produit avec des prix de Tim Horton, qui n'est pas un bogue: il peut être moins cher d'acheter exactement T+1 timbits que d'acheter exactementtimbits. Par exemple, l'achat d'exactement 19 timbits coûte 3,79 $, mais l'achat d'exactement 20 timbits ne coûte que $ 3,39. Peu importe, nous nous en tiendrons au problème de l'achat timbits exactement T aussi bon marché que possible, pour laquelle l'algorithme expliqué précédemment est correct. Donc, votre programme devrait vraiment sortir 3,79 lorsque l'entrée est de 19.

Testez d'autres exemples

Sur Computer Science Circles, nous essayons de faire tests automatisés intelligents de votre code afin de veiller à ce que vous ayez résolu le problème correctement. Mais dans un cadre de programmation réelle, c'est à vous de tester votre propre code en profondeur. Voici quelques lignes directrices utiles pour les tests.

  • Vous pouvez vérifier que chaque ligne de code de votre programme fonctionne correctement. Dans le problème Timbits, utiliser l'entrée 10 va vérifier si nous sommes correctement la manipulation de petites boîtes. De même, les entrées 20 et 40 vont vérifier que les boîtes moyennes et grandes sont manipulées correctement. Enfin, vous devez vérifier que nous nous occupons de timbits individuels correctement (par exemple, avec l'entrée 1).
    • Ceci peut aider à vérifier que des valeurs telles que 3,39 $ et 1,99 $ ont été correctement tapées.
  • N'oubliez pas de vérifier les cas extrêmes qui poussent votre programme vers ses limites. Par exemple, l'entrée minimum possible de ce programme est de 0, puisque vous ne pouvez pas avoir une valeur de timbits négative. Notre programme n'a pas d'entrée maximum, mais vous pourriez vouloir essayer des valeurs telles que 39 et 41 qui sont près de la limite qui vaut la peine d'acheter une grande boîte.
    • Cela peut aider à vérifier que vous n'avez pas accidentellement tapé > lorsque vous auriez dû taper >=.
  • Dans certains cas, vous pouvez vérifier automatiquement chaque entrée, ou vérifier un grand nombre de données aléatoires pour voir si votre programme fonctionne correctement. Nous utilisons souvent des entrées aléatoires dans les tests internes de CS Circles. Utilisez import random  au début de votre programme, puis random.randint(10, 100) va générer un nombre aléatoire compris entre 10 et 100.

Pouvez-vous trouver à la fois des bugs et passer tous les tests? Tentez le coup!

Certains calculs introduire des erreurs très faibles en Python:
Exemple : Erreur d'arrondi
Il est surprenant que le code ci-dessus ne donne pas exactement 0.35! Elle est liée à la manière dont Python stocke les numéros. Ne vous inquiétez pas à propos de ces petites erreurs : le correcteur n'en tient pas compte. Nous en dirons plus dans leçon 7B.

Exercice de code : Timbits
Corrigez les erreurs et passez tous les tests!
Vous pouvez entrer des données pour le programme dans la boîte ci-dessous.

Avez vous faim maintenant? Vous êtes prêt à continuer à la leçon suivante!

Alors que 10 timbits fait une boîte, 8 timbits font une timbyte. Photo: thisisbrianfisher, flickr