Funksjoner#

Læringsutbytte

Etter å ha arbeidet med dette temaet, skal du kunne:

  1. bruke funksjoner til å strukturere og gjenbruke kode

  2. forklare forskjellen mellom en parameter og et argument

  3. bruke return til å hente verdier ut av en funksjon

  4. forklare hva som menes med lokale og globale variabler

  5. bruke funksjoner til å representere kjemiske sammenhenger og beregninger

Definisjon#

I tillegg til innebygde funksjoner i Python som print og input, kan vi lage funksjoner selv. Dette kan være svært nyttig fordi det gjør programmet mer oversiktlig og håndterbart. Funksjoner er også nyttige når vi skal gjøre den samme typen beregning flere ganger.

I kjemi bruker vi stadig sammenhenger som tar imot noen størrelser og gir oss en ny størrelse tilbake. Fra massen og molmassen kan vi finne stoffmengden. Fra konsentrasjonen av oksoniumioner kan vi finne pH. Fra trykk, volum og temperatur kan vi bruke tilstandslikningen til å beregne stoffmengden. Slike sammenhenger passer naturlig å representere som funksjoner.

Vi begynner med sammenhengen

\[n=\frac{m}{M}\]

der \(n\) er stoffmengden i mol, \(m\) er massen i gram og \(M\) er molmassen i g/mol:

def antall_mol(masse, molmasse):
    stoffmengde = masse / molmasse
    return stoffmengde

Vi definerer her en funksjon med kodeordet def og gir den funksjonsnavnet antall_mol. Deretter spesifiserer vi i parentes hvilke verdier funksjonen trenger. masse og molmasse kalles parametre. Alt som tilhører funksjonen, må ha innrykk.

Kommandoen return bestemmer hvilken verdi funksjonen skal gi tilbake. Det gjør at vi kan lagre resultatet i en variabel eller bruke det videre i en ny beregning.

Vi får ikke noe synlig resultat bare av å definere funksjonen. For å bruke funksjonen må vi kalle på den:

def antall_mol(masse, molmasse):
    stoffmengde = masse / molmasse
    return stoffmengde

mol_NaCl = antall_mol(5.85, 58.44)
print(f"Stoffmengden NaCl er {mol_NaCl:.3f} mol.")

# Vi kan også kalle på funksjonen direkte inni print:
print(antall_mol(5.85, 58.44))

Tallene 5.85 og 58.44 kalles argumenter. De overføres til parameterne masse og molmasse når funksjonen kalles. Parametre er altså navnene vi bruker i funksjonsdefinisjonen, mens argumenter er de konkrete verdiene vi sender inn.

Underveisoppgave

Lag en funksjon som beregner konsentrasjonen \(c=n/V\). Funksjonen skal ta stoffmengde i mol og volum i liter som parametre. Bruk funksjonen til å finne konsentrasjonen når 0,15 mol stoff er løst i 0,50 L løsning.

return og print#

Vi kan lage funksjoner uten returverdi, for eksempel funksjoner som bare skriver ut noe:

def skriv_ut_stoffmengde(masse, molmasse):
    stoffmengde = masse / molmasse
    print(f"Stoffmengden er {stoffmengde:.3f} mol.")

skriv_ut_stoffmengde(5.85, 58.44)

Her trenger vi ikke skrive print når vi kaller på funksjonen, fordi utskriften skjer inni funksjonen. Dette kan se enklere ut enn å bruke en returverdi. Hvorfor bruker vi da return?

Hvis vi skal bruke resultatet videre, må funksjonen returnere en verdi. En utskrift er tekst som vises på skjermen; den er ikke en tallverdi vi kan regne videre med. Dette programmet fungerer:

def antall_mol(masse, molmasse):
    return masse / molmasse

mol_NaCl = antall_mol(5.85, 58.44)
mol_KCl = antall_mol(7.46, 74.55)

total_stoffmengde = mol_NaCl + mol_KCl
print(total_stoffmengde)

Hvis funksjonen i stedet bare hadde skrevet ut stoffmengden med print, ville vi ikke kunnet legge sammen resultatene. En funksjon uten return gir verdien None tilbake. Som hovedregel er det derfor lurt å returnere beregnede verdier og bestemme utskriften utenfor funksjonen.

Funksjoner med flere parametre#

En funksjon kan ha så mange parametre som den trenger. Tilstandslikningen for en ideell gass kan skrives som

\[P=\frac{nRT}{V}\]
def trykk_ideell_gass(stoffmengde, temperatur, volum):
    R = 8.314  # J/(mol K)
    trykk = stoffmengde * R * temperatur / volum
    return trykk

# Funksjonskall 1: argumentene er tall
print(trykk_ideell_gass(0.10, 298.15, 0.0025))

# Funksjonskall 2: argumentene er variabler
n = 0.10
T = 298.15
V = 0.0025
P = trykk_ideell_gass(n, T, V)
print(f"Trykket er {P/1000:.1f} kPa.")

Variablene utenfor funksjonen trenger ikke ha samme navn som parameterne. Det er rekkefølgen som bestemmer hvor verdiene havner: Det første argumentet overføres til stoffmengde, det andre til temperatur og det tredje til volum. Gode og kjemifaglig meningsfulle navn gjør likevel programmet lettere å lese.

Funksjoner med flere returverdier#

I motsetning til en matematisk funksjon kan en funksjon i programmering returnere flere verdier. Vi kan for eksempel la en funksjon beregne både sluttkonsentrasjonen og fortynningsfaktoren ved en fortynning:

def fortynning(startkonsentrasjon, startvolum, sluttvolum):
    sluttkonsentrasjon = startkonsentrasjon * startvolum / sluttvolum
    fortynningsfaktor = sluttvolum / startvolum
    return sluttkonsentrasjon, fortynningsfaktor

c2, faktor = fortynning(0.50, 10.0, 100.0)

print(f"Sluttkonsentrasjonen er {c2:.3f} mol/L.")
print(f"Løsningen er fortynnet med en faktor {faktor:.0f}.")

Når funksjonen kalles, fordeles returverdiene på variablene c2 og faktor i samme rekkefølge som de står etter return.

Underveisoppgave

Forklar hvordan programmet ovenfor fungerer. Utvid funksjonen slik at den også returnerer stoffmengden av løst stoff. Anta at volumene er oppgitt i mL. Skriv ut alle tre resultatene med f-strenger.

Du kan kjøre og utvide fortynningsfunksjonen i editoren nedenfor.

Lokale og globale variabler#

Variabler som defineres inni en funksjon, er bare tilgjengelige inni funksjonen. De kalles lokale variabler. Parametrene til funksjonen er også lokale. Variabler som defineres utenfor funksjoner, kalles globale variabler.

R = 8.314  # global variabel

def trykk_ideell_gass(n, T, V):
    trykk = n * R * T / V  # lokal variabel
    return trykk

P = trykk_ideell_gass(0.10, 298.15, 0.0025)
print(P)

Her er R global og kan leses både utenfor og inni funksjonen. Parameterne n, T og V og variabelen trykk er lokale. Variabelen P er global, fordi den opprettes utenfor funksjonen.

Hva skjer dersom vi prøver å bruke den lokale variabelen trykk utenfor funksjonen?

R = 8.314

def trykk_ideell_gass(n, T, V):
    trykk = n * R * T / V
    return trykk

P = trykk_ideell_gass(0.10, 298.15, 0.0025)
print(trykk)  # gir NameError

Vi får en feilmelding selv om vi tydelig kan se at trykk er definert. Årsaken er at variabelen bare eksisterer lokalt mens funksjonen arbeider. Verdien er likevel tilgjengelig utenfor funksjonen fordi vi returnerer den og lagrer den i den globale variabelen P.

Python har et kodeord, global, som kan brukes til å endre en global variabel inni en funksjon. Det er sjelden nødvendig og gjør det ofte vanskeligere å følge hvordan verdier endres. Det er som regel bedre å sende verdier inn som argumenter og hente resultatene ut med return. Da blir funksjonen lettere å teste og bruke i andre programmer.

Standardverdier for parametre#

Noen ganger ønsker vi en parameter som vanligvis skal ha en bestemt verdi, men som brukeren kan endre. Da kan vi gi parameteren en standardverdi. I måledata er det for eksempel sjelden fornuftig å kreve at to flyttall er nøyaktig like. Vi kan derfor undersøke om en målt pH ligger innenfor en valgt toleranse rundt 7:

def er_noytral(pH, toleranse=0.1):
    return 7 - toleranse <= pH <= 7 + toleranse

print(er_noytral(7.05))       # bruker standardverdien 0.1
print(er_noytral(7.15, 0.2))  # bruker toleransen 0.2

Standardparametre står til slutt i parameterlista. Funksjonen kan kalles både med og uten et eget argument for toleranse.

Oppgaver#

Oppgave 5.1

Forklar hvordan programmet nedenfor fungerer, og regn ut resultatet for hånd før du kjører koden.

def masse(stoffmengde, molmasse):
    return stoffmengde * molmasse

masse_NaCl = masse(0.20, 58.44)
masse_H2O = masse(0.20, 18.02)

forskjell = masse_NaCl - masse_H2O
print(forskjell)

Oppgave 5.2

Beer–Lamberts lov er \(A=\varepsilon lc\). Lag en funksjon som tar molar absorptivitet, lysvei og konsentrasjon som parametre og returnerer absorbansen. Test funksjonen med \(\varepsilon=4700\) L/(mol cm), \(l=1,00\) cm og \(c=2,5\cdot10^{-5}\) mol/L.

Oppgave 5.3

Hvert program inneholder feil. Finn feilene, og rett dem slik at programmene kan kjøres korrekt.

  1. Funksjonen skal beregne konsentrasjonen \(c=n/V\):

def konsentrasjon(n, V):
    n / V

print(konsentrasjon(0.25, 0.50))
  1. Programmet skal be om \([H_3O^+]\) og beregne pH:

from numpy import log10

def pH(oksonium):
return log10(oksonium)

H3O = input("Oppgi [H3O+] i mol/L: ")
print(pH(H3O))
  1. Programmet skal skrive ut absorbansen:

def beer_lambert(epsilon, lysvei, konsentrasjon):
    A = epsilon * lysvei * konsentrasjon
    return A

beer_lambert(4700, 1.0, 2.5E-5)
print(A)

Oppgave 5.4

Lag et lite sett med funksjoner for molregning:

  1. En funksjon som beregner stoffmengde fra masse og molmasse.

  2. En funksjon som beregner masse fra stoffmengde og molmasse.

  3. En funksjon som beregner konsentrasjon fra stoffmengde og volum.

  4. En funksjon som beregner nødvendig masse når du kjenner ønsket konsentrasjon, volum og molmasse.

Test funksjonene med selvvalgte, realistiske verdier og enheter.

Oppgave 5.5

Hva blir verdien til c2, og hvorfor? Rett programmet slik at c2 får en tallverdi.

def fortynning(c1, V1, V2):
    c2 = c1 * V1 / V2
    print(c2)

c2 = fortynning(0.50, 10.0, 100.0)
print(c2)

Oppgave 5.6

Prosentutbyttet i en reaksjon er

\[\text{prosentutbytte}=\frac{\text{faktisk utbytte}}{\text{teoretisk utbytte}}\cdot100\ \%.\]

Lag en funksjon som beregner prosentutbyttet. Test funksjonen med et faktisk utbytte på 7,85 g og et teoretisk utbytte på 9,20 g.

Oppgave 5.7

Lag et program som regner ut stoffmengden når brukeren skriver inn navnet på stoffet, massen og molmassen. Selve formelen skal ligge i en funksjon. Bruk en f-streng til utskriften.

Oppgave 5.8

Lag en funksjon som regner ut pH fra \([H_3O^+]\). Test funksjonen med minst tre konsentrasjoner.

Oppgave 5.9

Lag både en funksjon som beregner absorbansen fra Beer–Lamberts lov, og en funksjon som beregner konsentrasjonen fra målt absorbans. Kontroller at de to funksjonene er konsistente ved å sende resultatet fra den første inn i den andre.

Oppgave 5.10

Energien til et elektron i skall \(n\) i hydrogenatomet kan skrives som

\[E_n=-\frac{B}{n^2},\]

der \(B=2,18\cdot10^{-18}\) J. Lag én funksjon som beregner energien til et skall, og én funksjon som beregner bølgelengden til fotonet som emitteres når elektronet går fra skall \(n\) til skall \(m\). Bruk \(\Delta E=hc/\lambda\), \(h=6,626\cdot10^{-34}\) J s og \(c=3,00\cdot10^8\) m/s. Test overgangen fra \(n=3\) til \(m=2\).

Oppgave 5.11

Lag en funksjon som tar startstoffmengden og sluttstoffmengden til en reaktant som parametre. Funksjonen skal returnere både omsatt stoffmengde og omsetningsgrad i prosent. Test funksjonen med 0,250 mol ved start og 0,040 mol ved slutt.

Oppgave 5.12

Hvorfor har den globale variabelen konsentrasjon samme verdi før og etter at funksjonen er kalt?

def fortynn(konsentrasjon):
    konsentrasjon = konsentrasjon / 10
    return konsentrasjon

konsentrasjon = 0.50
ny_konsentrasjon = fortynn(konsentrasjon)

print(konsentrasjon)
print(ny_konsentrasjon)

Oppgave 5.13

De fleste gasser kan tilnærmes med tilstandslikningen \(PV=nRT\). Lag en funksjon for trykket og en annen for temperaturen. Bruk SI-enheter og test funksjonene med realistiske verdier.

Oppgave 5.14

Studer programmet. Hvilke variabler er lokale, og hvilke er globale? Hva skrives ut?

R = 8.314

def volum(stoffmengde, temperatur, trykk):
    beregnet_volum = stoffmengde * R * temperatur / trykk
    return beregnet_volum

n = 1.00
T = 298.15
P = 101325
V = volum(n, T, P)
print(V)

Oppgave 5.15

Lag en funksjon som tar \([H_3O^+]\) og en valgfri toleranseparameter som argumenter. Funksjonen skal returnere både pH og teksten sur, nøytral eller basisk. La standardtoleransen være 0,1 pH-enheter. Test funksjonen med \(1,0\cdot10^{-5}\), \(1,1\cdot10^{-7}\) og \(1,0\cdot10^{-9}\) mol/L.

Oppgave 5.16

pH-en i en buffer med bufferparet HA/A\(^-\) er gitt ved

\[pH=pK_a+\log\left(\frac{[A^-]}{[HA]}\right).\]

Lag en funksjon som tar \(pK_a\), syrekonsentrasjonen og basekonsentrasjonen som parametre. Test funksjonen for en eddiksyre–acetat-buffer med \(pK_a=4,76\), \([CH_3COOH]=2,3\cdot10^{-3}\) mol/L og \([CH_3COO^-]=2,0\cdot10^{-3}\) mol/L.

Oppgave 5.17

I et enkelt kalorimeter kan varmeopptaket beregnes med \(q=mc\Delta T\). Lag en funksjon som tar masse, spesifikk varmekapasitet, starttemperatur og sluttemperatur som parametre. Funksjonen skal returnere både \(q\) og \(\Delta T\).

Oppgave 5.18

Lag en funksjon gyldig_konsentrasjon som returnerer True dersom en konsentrasjon er større enn 0, og False ellers. Bruk funksjonen i en ny pH-funksjon som bare utfører beregningen dersom konsentrasjonen er gyldig. Hva bør funksjonen returnere når verdien ikke er gyldig?

Video#

I videoen nedenfor kan du få en innføring eller repetisjon i den grunnleggende teorien bak funksjoner.