JSON en CSV · oefening
De waardetypen behouden
read_csv_rows weet nu dat elke rij vijf cellen heeft. De functie geeft "0", "7.25" en "false" nog steeds als strings terug. Die strings rechtstreeks naar JSON schrijven zou geldige JSON met de verkeerde betekenis opleveren.
Omzetten hoort bij de overgang
Het uitvoerschema bepaalt elk Python-type voordat de JSON-serializer het ziet:
{
"sku": "GM-204",
"name": "Dice, Set of 6",
"quantity": 0,
"unit_price": 7.25,
"in_stock": False,
}
json zet die dictionary later vanzelf om naar JSON. Het belangrijke werk is eerst zorgen dat deze dictionary de waarheid weergeeft.
Verwijder voor sku en name witruimte eromheen en wijs een leeg resultaat af. Eis voor quantity tekst met decimale cijfers voordat je int aanroept. Daarmee houd je waarden zoals "4.5" en "many" buiten. Wijs vervolgens een negatief resultaat af.
Voor unit_price verwerkt float gewone decimale notaties, maar accepteert die ook bijzondere waarden zoals nan en inf. Dat zijn geen eindige prijzen en het schema sluit ze uit. math.isfinite(price) dicht dat gat.
Een boolean is geen niet-lege tekst
Dit is fout:
in_stock = bool(row["in_stock"])
Het is de moeite waard om dat te zien misgaan in plaats van mij op mijn woord te geloven:
Zowel "true" als "false" is True, omdat bool bij een string vraagt “zit er iets in?” en beide vier of vijf tekens bevatten. Alleen de lege string is False.
Vergelijk in plaats daarvan met de twee toegestane schrijfwijzen:
if row["in_stock"] == "true":
in_stock = True
elif row["in_stock"] == "false":
in_stock = False
else:
raise ValueError("in_stock must be true or false")
De strikte regel voor kleine letters is bewust gekozen. Stilletjes vijf schrijfwijzen accepteren maakt fouten bij de aanlevering moeilijker te ontdekken.
Nu jij
Implementeer parse_row(row, row_number) en read_catalog_csv(path).
parse_row moet een nieuwe dictionary teruggeven met precies de vijf schemasleutels en de afgesproken typen. De functie mag de onbewerkte rij niet wijzigen. Vermeld row_number in elke fout over een rijwaarde.
read_catalog_csv hoort read_csv_rows aan te roepen, elke rij op volgorde om te zetten en de itemlijst terug te geven. Geef logische CSV-rijnummers mee die bij 2 beginnen.
Maak een tijdelijke kopie van catalog.csv, voeg een vierde product toe met andere waarden dan de bestaande drie en roep read_catalog_csv aan met het pad van die kopie. Controleer of de omgezette uitvoer je nieuwe rij volgt. Houd de oorspronkelijke catalog.csv met drie rijen ongewijzigd voor het inleveren. Een converter die alleen de rijen verwerkt waarnaast hij is geschreven, is nog geen converter.
Waarom is bool(row["in_stock"]) de verkeerde manier om "false" te lezen?
Waarom controleer je math.isfinite(price) nadat je float hebt aangeroepen?
Opdracht
Implementeer parse_row(row, row_number) en read_catalog_csv(path).
Geef exacte itemdictionaries terug met sku en name als strings, quantity als integer, unit_price als eindige float en in_stock als echte boolean. Wijs lege tekst, ongeldige of negatieve getallen, niet-eindige prijzen en booleantekst anders dan precies true of false in kleine letters af.