Extra material om Python
Innehåll
Här hittar du trevliga Python-konstruktioner som inte nödvändigtvis finns i andra programmeringsspråk.
Läsa från textfil
Det finns många olika sätt att läsa data från en fil i Python. Vilket sätt som är “bäst” beror på kontexten.
I lektion 2 används följande som “standardsätt” att läsa och bearbeta rader från en fil:
|
|
Loopa genom öppen fil
Vi kan också använda en for
-loop direkt på en öppen textfil:
|
|
Det pythonska sättet
Ett mer pythonskt sätt är att använda kontexthanterare i Python (context manager):
|
|
Konstruktionen bygger på att objektet (den öppna filen i detta fall)
implementerar metoderna __enter__()
och __exit__()
. Dessa metoder anropas
när vi går in i with
-blocket (__enter__()
), samt när vi lämnar
with
-blocket (__exit__()
).
Med hjälp av denna konstruktion kan den öppna filen stänga sig själv när vi går ut ur kontexten. Koden blir också mer lättläst och det blir tydligt var filen används.
Villkor på en rad
|
|
kan skrivas som
|
|
Mer generellt:
|
|
I första exemplet motsvaras <uttryck A>
av värdet 10
, inte z = 10
.
dict.get() och dict.setdefault()
Det är vanligt att man behöver undersöka om en nyckel finns eller inte finns i
ett dictionary innan man antingen hämtar dess värde eller uppdaterar dess värde.
Om nyckeln k
inte finns i dictionaryt d
får man ett key error om man
försöker hämta dess värde; d[k]
-> KeyError
. För att undvika detta kan man
använda en villkorssats för att undersöka detta först:
|
|
Eftersom detta är så vanligt förekommande fall har man i Python lagt till
metoderna .get()
och .setdefault()
. Använder vi dessa metoder kan vi
både skriva mindre kod och göra den mer lättläst:
|
|
Se dict.get() och dict.setdefault().
Skriva ut en lista som innehåller egendefinerade klasser
TLDR; list.__str__()
använder värdenas __repr__()
-metod, inte deras
__str__()
-metod. Implementera __repr__()
för styra vad som syns. Om du redan
har implementerat __str__()
kan du låta __repr__()
returnera
self.__str__()
. Mer nyanserad förklaring nedan.
Säg att vi definerar följande klass:
|
|
Vi skapar 5 instanser och lägger dem i listan l
, men när vi gör print(l)
så får vi något i stil med nedanstående, varför?
[<__main__.MyClass object at 0x1108786a0>, <__main__.MyClass object at 0x1107ac310>,
<__main__.MyClass object at 0x1107acd60>, <__main__.MyClass object at 0x1107ac0d0>,
<__main__.MyClass object at 0x1107ac1c0>]
list.__str__()
Det som händer ovan är att Python använder den __str__()
som är definierad i
list
och det den gör är att använda sina värdens __repr__()
-metoder för att
visa dem.
För att print(l)
ska fungera för en lista med instanser av en egendefinierad
klass behöver vi alltså se till att vår klass implementerar __repr__()
. Om
vi redan har en __str__()
som vi använder för att göra fina utskrifter av vår
klass (se nedan), så kan vi låta __repr__()
returnera self.__str__()
.
Om vi inte har en __str__()
än, kan vi definera __repr__()
, eller så kan
vi se till att vi både implementerar __str__()
och __repr__()
. Se nedan
för skillnaden i användning av dessa.
Skillnaden mellan __repr__()
och __str__()
Metoderna __repr__()
och __str__()
finns dokumenterade i beskrivningen av Pythons datamodell.
Tanken är att __repr__()
används när vi felsöker vår kod, “debuggar” den,
medan __str__()
används när vi t.ex. vi vill visa objektet för en användare.
__str__()
används av Python vid print()
, str()
eller när vi formaterar en
sträng med .format()
eller använder en formaterad sträng; f"Värde: {value}"
.
__repr__()
används av funktionen repr()
(Notera att det finns en funktion
för att använda __repr__()
, dvs vi anropar inte __repr__()
explicit utanför
klassen)
Användningområden är är tydligt om vi t.ex. tittar på skillnaden mellan
__str__()
och __repr__()
för den inbyggda datatypen str
(Ja, de finns
även för str
, alla objekt behandlas lika!):
|
|
Vi ser att här att repr(s)
returnerar en sträng som om vi skriver ut den vi
faktiskt ser radbrytstecknet (vi skriver "\\"
för att få ut ett \
med
print()
).
Till sist är det värt att notera att pythontolken kommer använda
försöka använda __repr__()
om en klass inte implementerar __str__()
, men
inte tvärt om.
Sidansvarig: Johan Falkenjack
Senast uppdaterad: 2021-08-18