Presentationer Slide 1/1

Kap 4.4

Miniuppgift: filbaserat program

Bygg en receptsamling som sparar data mellan programmets körningar.

Mål

Du kombinerar tidigare kunskaper

  • funktioner och tydlig programstruktur
  • menyer, villkor och loopar
  • skrivning och läsning av textfiler
  • try/except vid filfel
  • testning av flera programflöden

Uppgiften

Receptsamling

Användaren ska kunna:

  1. lägga till ett recept med namn och ingredienser
  2. visa alla sparade recept
  3. avsluta programmet

Recepten ska finnas kvar nästa gång programmet startas.

Planera först

Vilka delar behöver programmet?

visa_meny()
lägga_till_recept()
visa_recept()
main()
  • En funktion för varje tydlig uppgift.
  • main() kopplar samman funktionerna.

Lagring

Bestäm ett enkelt filformat

Pannkakor|mjölk,ägg,mjöl
Tomatsoppa|tomater,lök,vatten
  • | skiljer receptnamnet från ingredienserna.
  • Komma skiljer ingredienserna från varandra.
  • Ett recept sparas per rad.

Konstant

Filnamnet används på flera platser

RECEPTFIL = "recept.txt"

Namnet skrivs med stora bokstäver eftersom värdet är tänkt att vara konstant.

Både skrivfunktionen och läsfunktionen använder samma filnamn.

Meny

Visa användarens alternativ

def visa_meny():
    print("\nMeny:")
    print("1. Lägg till recept")
    print("2. Visa recept")
    print("3. Avsluta")

Funktionen ansvarar bara för att skriva ut menyn.

Mallkod

Bygg programflödet först

def main():
    while True:
        visa_meny()
        val = input("Välj ett alternativ: ")

        if val == "1":
            pass
        elif val == "2":
            pass
        elif val == "3":
            break
        else:
            print("Ogiltigt val!")

pass

Tillfälliga platshållare

if val == "1":
    pass  # Funktionen skrivs senare.

pass gör ingenting.

Det används här för att kodblocket inte ska vara tomt medan programmet byggs.

När funktionen är färdig ersätts pass med funktionsanropet.

Spara recept

Läs in användarens data

def lägga_till_recept():
    namn = input("Vad heter receptet? ")
    ingredienser = input(
        "Ange ingredienser (komma-separerade): "
    )
    meddelande = f"{namn}|{ingredienser}\n"

meddelande får samma format som en rad i filen.

Append

Lägg receptet sist i filen

try:
    with open(RECEPTFIL, "a") as fil:
        fil.write(meddelande)
    print("Recept sparat.")
except Exception as e:
    print(f"Något gick fel: {e}")

"a" behåller tidigare recept och lägger till en ny rad.

Efter skrivning

Så förändras filen

Före:
Pannkakor|mjölk,ägg,mjöl
Efter:
Pannkakor|mjölk,ägg,mjöl
Tomatsoppa|tomater,lök,vatten

Läsa recept

Läs alla rader

def visa_recept():
    try:
        with open(RECEPTFIL, "r") as fil:
            rader = fil.readlines()
    except FileNotFoundError:
        print("Filen med recept finns inte ännu.")
        return

readlines() returnerar en lista med filens rader.

Tom fil

Kontrollera innan loopen

if not rader:
    print("Inga recept hittades.")
    return

En tom lista är falsk i ett villkor.

return avslutar funktionen när det inte finns något att visa.

Tolka raden

Dela upp receptets delar

for rad in rader:
    namn, ingredienser = rad.strip().split("|")
  1. strip() tar bort radbrytningen.
  2. split("|") delar texten i två delar.
  3. Delarna sparas i namn och ingredienser.

Ingredienser

Dela en gång till

print(f"\nRecept: {namn}")
print("Ingredienser:")

for ingrediens in ingredienser.split(","):
    print(f"- {ingrediens.strip()}")

split(",") skapar en lista med ingredienser.

Exempel

Från filrad till utskrift

Pannkakor|mjölk,ägg,mjöl
Recept: Pannkakor
Ingredienser:
- mjölk
- ägg
- mjöl

Färdig meny

Ersätt pass med funktionsanrop

if val == "1":
    lägga_till_recept()
elif val == "2":
    visa_recept()
elif val == "3":
    print("Programmet avslutas.")
    break
else:
    print("Ogiltigt val, försök igen.")

Programstart

Starta main()

if __name__ == "__main__":
    main()

Villkoret är sant när filen körs direkt.

Då startas huvudprogrammet.

Om filen importeras som en modul startar inte menyn automatiskt.

Programflöde

Så hänger delarna ihop

main()

Visar menyn och läser användarens val.

lägga_till_recept()

Skriver en ny rad med "a".

visa_recept()

Läser, delar upp och visar alla rader.

Testa

Viktiga testfall

  1. Lägg till ett recept i en tom fil.
  2. Lägg till flera recept.
  3. Visa recepten och kontrollera formateringen.
  4. Visa recept när filen saknas.
  5. Starta programmet igen och kontrollera att recepten finns kvar.
  6. Skriv ett ogiltigt menyval.

Sammanfattning

Miniuppgiften kombinerar...

  • en meny med loop och villkor
  • funktioner med tydliga ansvar
  • "a" för att spara utan att radera
  • readlines() för att läsa filens rader
  • split() för att tolka sparad text
  • try/except för förväntade filfel