13. Programmeringspraxis
I tidigare kapitel har vi diskuterat hur du ska skriva kod så att Python förstår den. Nu byter vi fokus och ska fundera över hur du kan skriva kod så att både du och dina kollegor förstår den.
Antalet rader producerad kod säger inget om hur bra en utvecklare är. En riktigt bra utvecklare är bra på att följa standarder. Python Enhancement Proposals som oftast förkortas till PEP är en serie numrerade dokument med förslag kring hur Python ska förändras och användas. Några av dessa beskriver programmeringspraxis som alla Python-utvecklare bör hålla sig till och vi ska gå igenom en del sådana detaljer i det här kapitlet.
1. Vad är det vi vill uppnå?
Korrekthet
| Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away. - Antoine de Saint-Exupéry |
Vi vill förstås att vår programkod ska vara korrekt, men vad betyder det egentligen att koden är korrekt? För att kunna avgöra det måste vi veta vad koden är tänkt att göra. Finns det en specifikation, en beställning eller åtminstone ett vagt önskemål? Om vi ska kunna avgöra om programkoden är korrekt måste vi veta vad tanken var från början.
Ett sätt att göra det tydlig för alla inblandade är att formulera ett slags kontrakt som visar vad varje funktion ska göra. Det kan vi göra genom att lägga in en så kallad docstring som vi ska fördjupa oss mer i senare. Det är en strukturerad kommentar som talar om vad vi kan förvänta oss från funktionen. Sedan gäller det förstås att upprätthålla det här kontraktet även när funktionen ändras, alternativt att uppdatera även kontraktet. För att vi ska vara säkra på att kontraktet uppfylls genomför vi välplanerade och genomtänkta tester.
Läsbarhet
| You know you're brilliant, but maybe you'd like to understand what you did two weeks from now. - Linus Torvalds |
Programkod kommer att läsas fler gånger än vad den skrivs. När du skriver kod, tänk i första hand på att den ska läsas av andra människor, inte bara av Python-interpretatorn. På kort sikt är det förstås viktigast att Python förstår koden så att programmet kan köras, men på lite längre sikt är det viktigare att du och dina kollegor förstår koden. Ditt program kommer kanske att leva i många år och behöva revideras flera gånger. Du kanske själv kommer behöva återkomma och göra en ändring om några månader. Hjälp dig själv att förstå din egen kod genom att skriva läsbart!
En av de viktigaste principerna för att skapa läsbar kod är att hålla en konsekvent kodstil. Det finns många sätt att variera koden, som alla ger korrekt resultat, men genom att vara konsekventa gör vi koden mer läsbar. Vi ska fördjupa oss i några sådana konventioner om en stund.
Testbarhet
| If it's hard to document, it's probably wrong. If it's hard to test, it's almost certainly wrong. - Okänd upphovsman |
Testbarhet är ett mått på hur enkelt något är att testa. Det kan vara ett helt system, ett program eller en enskild funktion. Kodens struktur och vilka standarder du följer (eller inte följer) kan ha en avgörande betydelse för hur lätt det är att testa. Det är en bra regel att ha testning i åtanke redan när du skriver koden första gången. Om du jobbar systematiskt på det sättet kallas det för testdriven utveckling.
Modularitet är en egenskap hos programkodens struktur som kan vara avgörande för hur testbar koden är. Det är helt enkelt ett mått på i vilken grad något är uppdelat i självständiga delar. Programkoden delas ju naturligt upp i moduler och funktioner, men funktioner kan vara mer eller mindre beroende av varandra. Om din progamkod är mer modulär - alltså i högre grad uppdelad i självständiga funktioner som inte är beroende av varandra - så är den också lättare att testa. Då kan du testa varje funktion var för sig. Modularitet innebär också att varje del av programmet har ansvar för en specifik uppgift och att kommunikationen mellan delarna sker strikt och kontrollerat. Denna princip brukar kallas inkapsling eller på engelska separation of concerns.
2. Namnkonventioner
Om vi väljer namn på variabler och funktioner som tydligt beskriver vad de gör har vi tagit ett stort steg på vägen mot självdokumenterande kod. Några exempel på beskrivande funktionsnamn är has_been_read, contains_key och is_substring. På det här sättet minskar vi behovet av extra kommentarer och långrandig dokumentation. Men det gäller också att följa de namnkonventioner som finns i Python.
Namn ska formatteras enligt vissa riktlinjer. Det är viktigt att dessa riktlinjer följs. Annars blir svårt för andra att arbeta vidare med din kod. Python i sig bryr sig dock inte om dessa konventioner, utan de är bara till för oss människor.
En generell regel är att ny kod ska namnges på samma sätt som existerande kod, men om du börjar med en tom fil är det bäst att följa den normala Python-standarden.
CamelCase
CamelCase innebär att namn som består av flera ord skrivs ihop och att varje ord börjar med stor bokstav. Namnet kommer av att det ser ut som att texten liksom får pucklar, som en kamel. I en del andra språk kan första ordet ibland inledas med liten bokstav, men inte i Python. Här används CamelCase för namn på klasser och undantag. (Vi har inte tittat så mycket på det ännu, så var inte orolig för det.)
snake_case
Standarden snake_case innebär att ett namn som består av flera ord separeras med understreck och att alla ord enbart har små bokstäver. Namnet kommer av att variabler ser ut som långsmala ormar. I Python används snake_case för variabler, funktioner, metoder och moduler. Modulnamn bör dessutom endast vara ett ord, eller hopskrivet utan understreck.
CAPITAL_LETTERS
CAPITAL_LETTERS används för variabler vars värde ska vara konstant, alltså så kallade konstanter.
3. Kommentarer
Om din programkod inte är helt självförklarande bör du använda kommentarer för att beskriva syftet med och tanken bakom koden. Kommentarer ska alltid vara fullständiga meningar och stämma överens med koden som beskrivs. Tanken med kommentarerna är att de ska komplettera koden, så att de tillsammans gör programmet lätt att förstå. Använd inte kommentarer för att beskriva speciell syntax eller specifika operationer.
Det här är ett dåligt exempel på en kommentar:
x = 2 # Set x to 2Kommentaren är helt överflödig. Den säger exakt samma sak som själva koden. Förklara i stället varför du tilldelar x värdet 2:
x = 2 # Start with the lowest prime numberTyper av kommentarer
Kommentarer är markerade sektioner av koden som ignoreras av interpretatorn. Det kan förekomma två olika sorters kommentarer i Python.
# Detta är en enradskommentar.
"""
Detta är en sträng som kan fungera som blockkommentar.
Den kan täcka flera rader.
"""Python har egentligen inte blockkommentarer, alltså kommentarer som sträcker sig över flera rader, men Python har något annat som många språk saknar, nämligen långa strängar. Om du skriver en sådan sträng som om den vore en sats, då betyder det att Python ska evaluera strängen och sedan inte göra något med värdet. Det fungerar precis som om det vore en kommentar. På precis samma sätt kan man egentligen placera vilka uttryck som helst inuti en funktion:
def test():
values = [1000, 2500, 400]
42
print(values)
>>> test()
[1000, 2500, 400]Mittenraden ovan ber Python att räkna ut 42. Den räknar ut att detta är 42. Sedan fortsätter den med nästa rad.
Docstrings
Python dokumenterar funktioner (med mera) med hjälp av så kallade docstrings, vilket är strängar placerade direkt efter def-raden för en funktion, metod, modul eller klass. Detta kan se ut så här:
def divides(k, n):
""" Checks if k divides n """
return n % k == 0Standarden säger att man ska skriva dessa strängar som blocksträngar, med tredubbla citattecken, men de är faktiskt bara vanliga strängar. Det råkar bara vara så att när det första i en funktion är en sträng, antar Python att den är tänkt som dokumentation.
Docstrings ska kortfattat förklara vad funktionen gör. Docstrings får också några speciella egenskaper som vi inte kommer gå in på här. I den här kursen kommer vi successivt att införa krav på docstrings för alla funktioner från och med nu.
Docstrings ska som andra kommentarer vara skrivna i flytande text. För funktioner ska en docstring summera funktionens beteende, dokumentera dess argument, returvärde och sidoeffekter. Om det finns många argument kan dessa beskrivas med en rad per argument.
Docstring utgör en funktions kontrakt. En funktion som utför det och endast det som är specifierat i dess docstring kan anses vara korrekt.
Det finns ytterligare krav på docstrings enligt standarden, som inte behöver uppfyllas i denna kurs. Den fullständiga specifikationen för docstrings finns i PEP-257.
def sum(n):
"""
Returns the sum of all integers from 0 to n.
"""
res = 0
for i in range(n + 1):
res += i
return res4. Programkodens upplägg
Det finns även en del konventioner för programkodens allmänna upplägg.
Blankrader
Alla funktioner och klasser på toppnivå (alltså rader som inte är indenterade) ska omringas av två blankrader. Undantag kan göras för enradade funktioner. Inre funktioner, klasser och metoder omringas av en blankrad.
Blankrader kan användas inne i funktioner för att dela upp koden i logiska sektioner.
Radlängd
För att skriva lättlästa program brukar man begränsa längden som en rad får ha. PEP-8 specificerar att Python-kod maximalt ska vara 79 tecken lång för att behålla läsbarheten. Vidare ska kommentarer och docstrings enbart vara 72 tecken långa enligt specifikationen.
Att det just är 79 tecken som är bredden för koden har troligen sitt ursprung i att terminalfönster som standard har en bredd på 80 tecken (från den tid när hårdvaruterminaler hade exakt 80 tecken per rad) samt att markören använder ett tecken. Det finns dock fler anledningar till att ha en radbredd som enbart är 79 tecken i dagsläget. PEP-8 nämner som exempel att det gör det möjligt att ha flera filer öppna vid sidan av varandra.
För att få Emacs att hålla reda på radlängden åt en kan man lägga till följande kod i filen ~/.emacs (och skapa den om den inte finns):
(require 'whitespace)
(setq whitespace-style '(face empty tabs lines-tail trailing))
(setq whitespace-line-column 79)
(global-whitespace-mode t)Det kommer att lägga till en annan bakgrundsfärg på alla tecken efter det 79:e tecknet.
Mellanrum och onödiga tecken
Eftersom man strävar efter att skriva läsbar kod är det även värt att nämna något om mellanrum i koden och onödiga tecken. Det man kan tänka på med mellanrum i koden är att det inte finns någon regel som inbegriper alla fall. Som riktlinje kan man dock ha att man ska efterlika helt vanlig text. Till exempel, ha ett mellanslag efter ',' och separera gärna långa aritmetiska uttryck på lämpliga ställen. Titta på följande exempel:
x=fn(3*4+5/3*26-3,3+4%9-3*5)Jämför detta med följande version som använder mellanslag:
x = fn(3*4 + 5/3*26 - 3, 3 + 4%9 - 3*5)Vill man kan det hela delas upp på två rader enligt följande:
x = fn(3*4 + 5/3*26 - 3,
3 + 4%9 - 3*5)Notera här att det inte finns med ett '\' i slutet av första raden. Det är för att man är "inuti" en öppen parentes (i ett funktionsanrop). Satsen kan omöjligt ha tagit slut efter första raden eftersom man behöver hitta en högerparentes först, så Python antar att även nästa rad är med i satsen utan att man behöver ett '\'.
5. Enkelhet
Koden är inte en plats för att du ska briljera med dina kunskaper i ett språks konstigaste funktionaliteter. Enkel och tydlig kod är att föredra.
print("Uneven" if x%2 else "Even")
if x % 2 == 0:
print("Even")
else:
print("Uneven")Även om dessa två lösningar gör samma sak kan det nedre alternativet vara mer lättläst. Detta för att det använder en if-sats och inte använder att 0 tolkas som False i Python.
Detta är ett exempel som illustrerar principel KISS.
Sammanfattning
- Vi skriver programkod i första hand för människor, inte för maskiner.
- För att koden ska bli läsbar ska den ha beskrivande namn och följa språkets konventioner.
- För att koden ska bli testbar ska den vara modulär.
- Docstrings är en standard för att dokumentera vad en funktion gör.
För en kort dikt om hur Python-kod bör skrivas, skriv följande kommando i en Python-interpretator:
import thisExtramaterial
Sidansvarig: Peter Dalenius
Senast uppdaterad: 2025-10-20
