Osa 4

Mera strängar och listor

Du är redan bekant med syntaxen [] för att plocka ut/slica en delsträng:

strang = "exempel"
print(strang[3:7])
Exempelutskrift

mpel

Samma syntax fungerar med listor. Dellistor kan extraheras på samma sätt som delsträngar:

lista = [3,4,2,4,6,1,2,4,2]
print(lista[3:7])
Exempelutskrift

[4, 6, 1, 2]

Mera extrahering

Syntaxen [] fungerar faktiskt mycket lika som range-funktionen, vilket innebär att vi också kan ge den steg-information:

strang = "exempel"
print(strang[0:7:2])
lista = [1,2,3,4,5,6,7,8]
print(lista[6:2:-1])
Exempelutskrift

eepl [7, 6, 5, 4]

Om vi lämnar bort något av indexen kommer operatorn att inkludera alla element. Vi kan därför till exempel skriva ett mycket kort program som svänger på en sträng:

strang = input("Mata in en sträng: ")
print(strang[::-1])
Exempelutskrift

Mata in en sträng: exempel lepmexe

Varning: globala variabler inne i funktioner

Vi har sett att det går att tilldela nya variabler inne i funktionsdefinitioner. Funktionen har också åtkomst till de variabler som finns utanför funktionen, i huvudfunktionen. Dessa variabler kallas globala variabler.

Att använda globala variabler inifrån funktioner är oftast en dålig idé. Det kan orsaka en hel del problem, till exempel buggar som är svåra att spåra.

Här är ett exempel på en funktion som använder en global variabel "av misstag":

def svangd_utskrift(namn: list):
    # använder av misstag den globala variabeln namnlista
    i = len(namnlista) - 1
    while i >= 0:
        print(namnlista[i])
        i -= 1

# global variabel
namnlista = ["Antti", "Emilia", "Erkki", "Margaret"]
svangd_utskrift(namnlista)
print()
svangd_utskrift(["Louise", "Ophelia", "Lotta"])
Exempelutskrift

Margaret Erkki Emilia Antti

Margaret Erkki Emilia Antti

Även om funktionen anropas korrekt skrivs alltid namnen i den globala variabeln namnlista ut.

All kod som testar funktioner ska skrivas inom ett separat block så att TMC-testen accepterar koden. Föregående exempel ska alltså skrivas så här:

def svangd_utskrift(namn: list):
    # använder av misstag den globala variabeln namnlista
    i = len(namnlista) - 1
    while i >= 0:
        print(namnlista[i])
        i -= 1

# kod som testar funktionen placeras här
if __name__ == "__main__":
    # global variabel
    namnlista = ["Antti", "Emilia", "Erkki", "Margaret"]
    svangd_utskrift(namnlista)
    print()
    svangd_utskrift(["Louise", "Ophelia", "Lotta"])

Nu definieras också den globala variabeln i if-blocket.

TMC-testen körs alltid så att koden inom dessa if-block inte körs. Därför fungerar funktionen inte ens i teorin eftersom variabeln namnlista inte finns då testen körs.

Loading

Strängar är oföränderliga

Strängar och listor har en hel del likheter, framför allt då det kommer till hur de fungerar med olika operatorer. En nyckelskillnad är att strängar är oföränderliga. Det betyder att de inte kan ändras.

strang = "exempel"
strang[0] = "a"

Vi kan inte byta ut tecken i en sträng, så det här programmet kommer att ge ett felmeddelande:

Exempelutskrift

TypeError: 'str' object does not support item assignment

Ett liknande fel uppstår om du försöker sortera en sträng med sort-metoden.

Strängar är oföränderliga, men variablerna som lagrar dem är inte det. En sträng kan ersättas med en annan sträng.

De följande exemplen är alltså till sin grund olika:

lista = [1,2,3]
lista[0] = 10
4 4 1
strang = "Hej"
strang = strang + "!"
4 4 2

Det första exemplet ändrar på innehållet i den lista som man hänvisar till. I det andra exemplet ersätts referensen till den ursprungliga strängen med en referens till en ny sträng. Den ursprungliga strängen finns fortfarande någonstans i datorns minne, men vi har inte längre någon variabel som är kopplad till strängen, och den kan därför inte längre användas i programmet.

Vi återkommer till det här senare, i samband med listreferenser.

Fler metoder för listor och strängar

Metoden count räknar antalet gånger ett element eller en delsträng finns i en lista eller sträng:

strang = "Hon håsa på hussatimmen så lärar'n sa sakta: städa upp mjölet på golvet så att klassen int' e som en savann"
print(strang.count("sa"))

lista = [1,2,3,1,4,5,1,6]
print(lista.count(1))
Exempelutskrift

5 3

Metoden räknar inte överlappande förekomster. Till exempel i strängen aaaa räknar metoden upp till två förekomster av delsträngen aa, även om det finns tre stycken om överlappande förekomster skulle tillåtas ("aa**" "aa". "**aa").

Metoden replace skapar en ny sträng där en specifik delsträng har ersatts med en annan sträng:

strang = "Hej alla"
ny = strang.replace("Hej", "God eftermiddag")
print(ny)
Exempelutskrift

God eftermiddag alla

Metoden påverkar alla delsträngar som hittas:

mening = "de åtta potatissemlorna förvandlades till en stor potatisplåt i ugnen – läraren, ja hon suckade i sitt hörn av klassen"
print(mening.replace("en", "EN"))
Exempelutskrift

de åtta potatissemlorna förvandlades till EN stor potatisplåt i ugnEN – lärarEN, ja hon suckade i sitt hörn av klassEN

När replace-metoden används, är ett vanligt misstag att man glömmer att strängar är oföränderliga:

strang = "Jag gillar Python"

# vi ersätter en delsträng, men resultatet lagras ingenstans
strang.replace("Python", "Java")
print(strang)
Exempelutskrift

Jag gillar Python

Om den gamla strängen inte längre behövs kan man tilldela den nya strängen till samma variabel:

strang = "Jag gillar Python"

# vi ersätter en delsträng och lagrar resultatet
strang = strang.replace("Python", "Java")
print(strang)
Exempelutskrift

Jag gillar Java

Loading
Loading
Loading
Loading

Skapa ett större programmeringsprojekt

Den här fjärde modulen avslutas med ett lite större programmeringsprojekt där du får utnyttja det du lärt dig hittills.

Den viktigaste regeln när man börjar med ett programmeringsprojekt är att man inte ska försöka lösa alla problem samtidigt. Programmet ska bestå av mindre delar, till exempel hjälpfunktioner. Du ska testa att varje del fungerar innan du går vidare. Om du försöker göra för mycket samtidigt kommer du högst antagligen hamna i en situation som präglas av kaos och mera kaos.

Du kommer att behöva ett sätt att testa dina funktioner utanför huvudfunktionen. Du kan göra det genom att definiera en skild huvudfunktion som du anropar utanför alla andra funktioner i programmet. Det är enkelt att tillfälligt kommentera bort ett funktionsanrop när man testar programmet. De första stegen i ditt programmeringsprojektet skulle kunna se ut så här:

def main():
    poang = []
    # programkod

main()

Nu kan hjälpfunktionerna köras utan att huvudfunktionen körs:

# hjälpfunktion som beräknar vitsord baserat på givet poängantal
def vitsord(poang):
    # funktionens kod

def main():
    poang = []
    # programmets kod

# kommenterar bort huvudprogrammet
#main()

# testar hjälpfunktionen
poang = 35
resultat = vitsord(poang)
print(resultat)

Skicka data från en funktion till en annan

När ett program innehåller flera funktioner uppstår frågan: hur skickar jag data från en funktion till en annan?

I följande exempel ber programmet användare mata in några heltal. Programmet skriver sedan ut dessa värden och utför en "analys" på dem. Programmet är uppdelat i tre skilda funktioner:

def las_fran_anvandare(antal: int):
    print(f"Ange {antal} tal:")
    tal = []

    for i in range(antal):
        t = int(input("Ange tal: "))
        tal.append(t)

    return tal

def skriv_ut(tal: list):
    print("Talen är: ")
    for t in tal:
        print(t)

def analysera(tal: list):
    medeltal = sum(tal) / len(tal)
    return f"Antalet tal {len(tal)}, medeltal {medeltal}, minsta {min(tal)} och största {max(tal)}"

# "huvudprogram" som använder funktionerna
indata = las_fran_anvandare(5)
skriv_ut(indata)
analysens_resultat = analysera(indata)
print(analysens_resultat)

När programmet körs, skulle det kunna se ut så här:

Exempelutskrift

Ange 5 tal: Ange tal: 10 Ange tal: 34 Ange tal: -32 Ange tal: 99 Ange tal: -53 Talen är: 10 34 -32 99 -53 Antalet tal 5, medeltal 11.6, minsta -53 och största 99

Idén är att huvudfunktionen "lagrar" all data som behandlas av programmet. I det här fallet är det enda vi behöver de värden som användaren matat in, i variabeln tal.

Om dessa värden behövs i en funktion skickar vi den motsvarande listvariabeln som ett argument. Det här sker i funktionerna skriv_ut_resultat och analysera. Om funktionen resulterar i data som behövs på annat håll i programmet, returnerar funktionen det. Det här sparas i en variabel i huvudfunktionen. Det här sker med funktionerna indata_fran_anvandare och analysera.

Du kunde också använda den globala variabeln tal från huvudfunktionen direkt i hjälpfunktionerna, men vi har redan gått igenom varför det är en dålig idé. Här följer ännu en annan förklaring: om funktionerna kan ändra på den globala variabeln kan oförutsedda saker börja hända i programmet, framför allt då antalet funktioner ökar.

Att skicka data ut och in från funktioner gör man alltså helst med hjälp av argument och returvärden.

Du kunde också göra huvudfunktionen till en egen funktion. Då skulle variabeln tal inte längre vara en global variabel, utan en lokal variabel i main-funktionen:

# funktion som representerar huvudfunktionen
def main():
    indata = las_fran_anvandare(5)
    skriv_ut(indata)
    analysens_resultat = analysera(indata)

    print(analysens_resultat)

# start av programmet
main()
Loading
Loading...
:
Loading...

Log in to view the quiz

Vänligen svara på en kort enkät om den här veckans material.

Loading...
:
Loading...

Log in to view the quiz

Du har nått slutet av den här delen!

Se dina poäng genom att klicka på cirkeln nere till höger av sidan.