0%

Dataclasses en waardeobjecten · eindproject

Eindproject: Project: modelleer resultaatregistraties en configuratie

Het hele betoog van dit hoofdstuk past in één zin: laat Python de code schrijven die al door je attributenlijst wordt bepaald en blijf zelf de code schrijven die een beslissing uitdrukt.

Het project is een klein resultatensysteem waarin elke keuze uit het hoofdstuk één keer voorkomt.

Wat je bouwt

QuizConfig    how a quiz runs         changeable, has defaults
Points        an amount               frozen value
Question      a question              frozen value, built several ways
ResultRecord  one finished result     frozen value
Gradebook     the collection          entity, changes as results arrive

Drie bevroren waarden, één veranderbare configuratie en één entiteit die bestaat om te groeien.

De beslissingen om bij stil te staan

Waarom ResultRecord bevroren is. Een afgerond resultaat is een gegeven over iets dat al is gebeurd. Niets hoort de score van vorige week te kunnen aanpassen, en bevriezen legt dat vast op een manier die commentaar niet kan.

Waarom Gradebook dat niet is. Het bestaat om resultaten te verzamelen. Bevriezen zou betekenen dat je bij elk resultaat de hele resultatenlijst opnieuw moet opbouwen. eq=False behoudt ook de entiteitsidentiteit: twee afzonderlijke resultatenlijsten worden niet hetzelfde object alleen omdat hun huidige registraties overeenkomen.

Waarom Gradebook een lijst bevat die per object wordt gemaakt. Les 4 en les 8 toonden dezelfde fout via verschillende routes: een veranderbare standaardwaarde en een veranderbaar klasseattribuut. Eén Gradebook per programma is het gebruikelijke geval, en precies daarom zou een gedeelde lijst tussen twee exemplaren lang onopgemerkt blijven.

Waarom is ResultRecord bevroren en Gradebook niet?

De methoden die geen boilerplate zijn

@dataclass schrijft de constructors, reprs en vergelijkingen. Wat overblijft is van jou en daar besteedt de beoordelaar de meeste aandacht aan:

  • Question.from_dict en Question.simple, twee extra ingangen;

  • Question.normalize, de hulpmethode die bij vragen hoort;

  • Question.is_correct en points_for, de regels die een vraag beheert;

  • ResultRecord.percentage en passed_under, gegevens over een resultaat;

  • Gradebook.record, best en average, die genormaliseerde percentages vergelijken zodat resultaten met verschillende totalen betekenisvol blijven.

Geen enkele ervan had kunnen worden gegenereerd, omdat elke methode een beslissing is die iemand heeft genomen.

Afronden

Tel de regels die je niet hoefde te schrijven. Lees daarna de regels die je wel schreef en controleer of elke regel iets zegt dat niet uit de lijst met attributen erboven had kunnen worden afgeleid.

Voeg twee resultaten met verschillende totalen toe, zoals 9/100 en 8/10, en druk het beste resultaat plus het gemiddelde percentage af. Die laatste uitvoering bewijst dat de resultatenlijst resultaten modelleert in plaats van alleen de gegeven voorbeelden te doorstaan.

Opdracht

Bouw de vijf klassen en gebruik het gegenereerde werk voor alles wat daardoor wordt afgedekt.

Points is een bevroren waarde met een positieve amount, waarbij plus(other) een nieuwe Points teruggeeft.

Question is een bevroren, gevalideerde waarde met een niet-lege prompt en answer, en points met standaardwaarde Points(1).

QuizConfig is een veranderbare dataclass: een verplichte niet-lege title, pass_mark met standaardwaarde 0.6 en een beperking tot boven 0 en maximaal 1, en tags die per configuratie als een nieuwe lege lijst begint.

ResultRecord is een bevroren waarde met een niet-lege learner, een niet-negatieve total en een score van 0 tot en met total, met percentage en een methode passed_under(config).

Gradebook is een veranderbare entiteit met een niet-lege title en één interne lijst _records. Gebruik eq=False. De klasse krijgt record(result), records() dat een veilige kopie teruggeeft, best() en average().

Maak de methoden af die in de startcode worden genoemd:

  • Question.from_dict(record) leest prompt, answer en een Points-waarde uit points; simple(prompt, answer) gebruikt Points(1). Beide zijn klassemethoden die via cls een object maken. Weiger een puntenargument dat geen Points is met TypeError.

  • Question.normalize(text) is een statische methode die witruimte aan de uiteinden verwijdert en tekst omzet naar kleine letters. Gebruik die aan beide kanten in is_correct. points_for geeft de gehele hoeveelheid terug voor een juist antwoord en anders 0.

  • QuizConfig.practice(title) en final_exam(title) zijn klassemethoden die respectievelijk slaaggrenzen van 0.5 en 0.8 kiezen; tags beginnen nog steeds leeg.

  • ResultRecord.percentage is de verhouding score / total, of 0.0 bij een totaal van nul. passed_under(config) rekent een resultaat precies op de slaaggrens van de configuratie ook als geslaagd.

  • Gradebook.record accepteert alleen ResultRecord-waarden en gooit anders TypeError op. best() vergelijkt percentages en geeft een hoogste resultaat terug, of None als er geen resultaten zijn. average() is het gemiddelde van de geregistreerde percentages, of 0.0 als er geen resultaten zijn.

Gebruik ValueError voor de hierboven beschreven ongeldige veldwaarden. Houd de geschiedenis van de resultatenlijst buiten constructorargumenten en de gegenereerde repr met init=False, repr=False, zoals in les 7. Geen enkele klasse drukt iets af.