Se lecture 6
Notera skillnaden mellan data i minnet och data som finns kvar efter programmet.
Öppna Harvard vecka 6 ↗Lektion 6 · Cirka 45 min genomgång
Variabler försvinner när ett program avslutas. Filer gör det möjligt att lagra data beständigt, läsa in den i en senare körning och utbyta strukturerad information med andra program.
with använder en context manager. Filen stängs när blocket lämnas, även om ett undantag uppstår inne i blocket.
with open("names.txt", "a", encoding="utf-8") as file:
file.write("Ada\n")Före genomgången
Den här kursen hoppar över Harvardavsnitt 5 om unit tests. Därför följer lektion 06 direkt efter lektion 04. Numret behålls så att filmer, notebook och Harvarduppgifter fortfarande är lätta att hitta.
Notera skillnaden mellan data i minnet och data som finns kvar efter programmet.
Öppna Harvard vecka 6 ↗Skapa lektion_06 i kursmappen och öppna hela mappen i VS Code.
Skapa names.txt och students.csv. Filerna ska ligga i samma arbetsmapp som programmen.
Den nedladdningsbara notebooken innehåller lärarens ursprungliga exempel. Guiden kompletterar dem med bland annat encoding="utf-8", newline="" för CSV och dagens exakta Harvardkrav.
Dagens karta
Vi börjar med vanliga textfiler, går vidare till strukturerade CSV-filer och avslutar med binära bildfiler.
5 min
7 min
6 min
7 min
8 min
7 min
5 min
Varför filer?
I/O betyder input/output. Filinput innebär att programmet läser data från en fil. Filoutput innebär att programmet skriver eller skapar en fil.
En list, ett dict och andra objekt finns normalt bara medan processen körs. När processen avslutas försvinner objekten ur dess minne.
En fil lagras utanför programmets arbetsminne. Ett senare program kan öppna samma fil och tolka innehållet på nytt.
Filer kan skrivas över, raderas, bli korrupta eller vara otillgängliga. Ett program måste därför välja rätt filläge och hantera rimliga felvägar.
Öppna en resurs
open returnerar ett filobjektEtt filobjekt representerar en öppen förbindelse till en fil. Det håller reda på bland annat filläge, teckenkodning och aktuell position.
file = open(
"names.txt",
"r",
encoding="utf-8",
)
print(file.read())
file.close()str eller ett path-like objekt som pekar ut resursen."utf-8" för text."r"read · standardläge · filen måste finnas"w"write · skapar fil eller raderar befintligt innehåll"a"append · skapar fil eller lägger till sist"x"exclusive create · misslyckas om filen redan finns"b"binary · kombineras exempelvis som "rb" och ger bytes"w" tömmer en befintlig fil omedelbartÖppna därför inte en värdefull fil i write-läge bara för att undersöka den. Använd "r" när programmet endast ska läsa.
open("data/names.txt") letar relativt den katalog där processen startades, inte nödvändigtvis katalogen där Pythonfilen ligger. VS Codes öppna mapp och terminalens aktuella katalog påverkar därför resultatet.
Context manager
with stänger filen även när blocket lämnas genom ett felEn context manager hanterar start och avslutning av en resurs. För ett filobjekt innebär det att filen öppnas före blocket och stängs när blocket lämnas.
close kan glömmasfile = open("names.txt", "a", encoding="utf-8")
file.write("Ada\n")
file.close()Om en operation mellan open och close skapar ett undantag kanske sista raden aldrig nås.
with avgränsar livstidenwith open("names.txt", "a", encoding="utf-8") as file:
file.write("Ada\n")Efter det indragna blocket är filen stängd. Namnet file kan fortfarande finnas, men objektet får inte längre läsas eller skrivas.
as file är en vanlig lokal bindningNamnet file är inte ett reserverat ord. Det refererar till filobjektet inne i koden och kan ersättas med ett tydligare namn som csvfile.
Sekventiell text
str och innehåller även radbrytningarI textläge avkodar Python filens bytes till tecken. Parametern encoding="utf-8" gör valet uttryckligt och ger samma avkodning på olika datorer.
with open("names.txt", encoding="utf-8") as file:
for line in file:
name = line.rstrip("\n")
print(f"Hej, {name}!")Hej, Ada!Hej, Grace!Filobjektet är itererbart. Varje varv ger nästa rad som en str. Modellen behöver inte läsa hela filen till minnet på en gång.
Textens radbrytning ingår normalt sist i raden. rstrip("\n") tar bara bort radbrytningstecknet. rstrip() utan argument tar bort alla avslutande whitespace-tecken, även betydelsefulla blanksteg.
read()Returnerar återstående text som en enda str. Praktiskt för små filer, men stora filer kan ta mycket minne.
readlines()Returnerar en list av rader. Radbrytningarna behålls normalt i elementen.
name = input("Namn: ")
with open("names.txt", "a", encoding="utf-8") as file:
file.write(f"{name}\n")write lägger inte till en radbrytning automatisktUtan \n hamnar nästa namn direkt efter det föregående. Alternativet print(name, file=file) använder däremot print-funktionens vanliga radslut.
Rader och fält
CSV betyder comma-separated values. En rad representerar normalt en post och fälten representerar kolumner. Formatet tillåter att ett fält med kommatecken omges av citattecken.
name,home
Harry,"Number Four, Privet Drive"
Ron,The Burrowsplit(",") är skörtEn vanlig str.split känner inte till CSV-regler. Den delar även vid kommatecknet inne i den citerade adressen och skapar tre delar i stället för två.
Standardmodulen csv tolkar avgränsare, citattecken och andra CSV-detaljer. Vi ska använda formatets parser, inte återskapa den.
csv.readerimport csv
with open("students.csv", newline="", encoding="utf-8") as file:
reader = csv.reader(file)
for row in reader:
print(row)Varje rad blir en list av str-värden. row[0] betyder första kolumnen.
csv.DictReaderimport csv
with open("students.csv", newline="", encoding="utf-8") as file:
reader = csv.DictReader(file)
for row in reader:
print(row["name"])Första raden används som nycklar. Varje följande rad blir ett dict, så koden kan använda kolumnnamn.
strcsv.reader omvandlar inte automatiskt "42" till int. Programmet måste själv omvandla fält när datamodellen kräver det.
newline=""Dokumentationen rekommenderar detta så att csv-modulen själv får hantera radslut korrekt på olika operativsystem.
Bearbeta och skriv strukturerat
key talar om vilket värde sorted ska jämföraEtt dict har flera värden. När en list av sådana poster ska sorteras behöver sorted en funktion som hämtar sorteringsvärdet ur varje post.
def get_name(student):
return student["name"]
for student in sorted(students, key=get_name):
print(student["name"])sorted anropar get_name en gång per post och använder returvärdet vid jämförelsen.
for student in sorted(
students,
key=lambda student: student["name"],
):
print(student["name"])Syntaxen är lambda parameter: uttryck. Uttryckets värde returneras automatiskt. Använd formen för en kort, lokal funktion.
key får funktionen — inte resultatet av ett för tidigt anropSkriv key=get_name, inte key=get_name(). sorted ansvarar för att anropa funktionen med varje element.
import csv
fields = ["name", "home"]
with open(
"students.csv",
"w",
newline="",
encoding="utf-8",
) as file:
writer = csv.DictWriter(file, fieldnames=fields)
writer.writeheader()
writer.writerow({
"name": "Ron",
"home": "The Burrow",
})DictWriter behöver ett schemafieldnames anger kolumnernas namn och ordning. writeheader() skriver rubrikraden. writerow tar ett dict och placerar värdena i rätt kolumner.
Välj "w" när filen ska byggas på nytt och "a" när nya poster verkligen ska läggas sist. I append-läge måste programmet undvika att skriva rubriken på nytt vid varje körning.
Inte bara text
Bilder, ljud och många dokument är binära format. I binärt läge arbetar Python med bytes, inte str. Ofta använder vi ett specialiserat package som känner till formatets struktur.
PIL importerasPillow är distributionens namn på PyPI. Den moderna koden importerar fortfarande genom namnrymden PIL. Installera i kursens aktiva miljö med python -m pip install Pillow.
Image.open avkodar ett bildformat till ett bildobjekt. ImageOps.fit returnerar en ny bild som både skalats och beskurits till önskad storlek. Returvärdet måste sparas.
from PIL import Image, ImageOps
with Image.open("photo.jpg") as photo:
fitted = ImageOps.fit(photo, (600, 600))
fitted.save("square.jpg")ImageOps.fit ändrar inte originalobjektet på platsImageOps.fit(photo, size) returnerar den bearbetade bilden. Om returvärdet ignoreras fortsätter variabeln photo att referera till den ursprungliga bilden.
Problem Set 6
Harvards aktuella uppgiftssidor är kravspecifikationen. Testa alltid normala fall, gränser, felaktigt antal argument, fel filtyp och saknad fil.
Ta exakt ett kommandoradsargument som slutar på .py. Räkna rader som inte är tomma och inte börjar med # efter valfritt inledande whitespace. En docstring räknas som kod. Avsluta kontrollerat vid fel antal argument, fel filtyp eller saknad fil.
Ta exakt ett CSV-filnamn som argument, läs tabellen med csv och visa den med tredjepaketet tabulate och formatet "grid". Validera argument, ändelsen .csv och att filen finns.
Ta en inputfil och en outputfil som två kommandoradsargument. Läs name,house med DictReader, dela "last, first" och skriv first,last,house med DictWriter och en rubrikrad.
Ta input- och outputbild som två argument. Tillåt .jpg, .jpeg och .png utan hänsyn till skiftläge, kräv samma extension, använd ImageOps.fit till tröjans storlek, klistra in tröjan med dess transparensmask och spara resultatet.
I några äldre filer används interaktiv input där uppgiften kräver sys.argv, en CSV-rubrik saknas och returvärdet från ImageOps.fit ignoreras. Utgå från den aktuella uppgiftstexten och använd skisserna endast för diskussion och felsökning.
Fördjupa och repetera
Börja med kursguiden. Använd sedan originaldokumentationen när du behöver exakta argument, returvärden eller undantag.
✓ skilja data i minnet från beständig data i en fil
✓ välja rätt filläge och förklara risken med "w"
✓ använda with, UTF-8 och säkra relativa sökvägar
✓ läsa och skriva text utan felaktiga radbrytningar
✓ läsa CSV som list eller dict
✓ förklara lambda och key vid sortering
✓ skriva CSV med rubrik och bearbeta en binär bild med Pillow