Funksjoner#

Læringsutbytte

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

  1. bruke funksjoner til å strukturere og gjenbruke kode.

  2. forklare hva som menes med globale og lokale variabler.

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 kan gjøre programmet mer oversiktlig og håndterbart. I tillegg er det nyttig med funksjoner når vi skal gjøre samme ting flere ganger. Si at vi for eksempel har en vilkårlig matematisk funksjon \(f(x) = x^2 + x - 5\). Dersom vi vil regne ut \(f(x)\) for alle heltallsverdier av \(x\) mellom 1 og 50, kan vi gjøre dette med funksjoner. Først definerer vi funksjonen:

def f(x):
    return x**2 + x - 5

Vi definerer her en funksjon med kodeordet def og gir den et funksjonsnavn, her f. Deretter spesifiserer vi hva inn-verdien/variabelen til funksjonen skal hete i parentes. Her kaller vi den x. I programmering kaller vi en slik størrelse for en parameter. Gitt én verdi av x, skal funksjonen returnere (spesifisert ved return-kommandoen) en funksjonsverdi. Legg merke til at syntaksen er ganske lik vilkår (if-tester), while- og for-løkker, med et kolon etter funksjonsnavnet og innrykk på alt som tilhører funksjonen.

Vi får derimot ikke noe output av å definere en funksjon. For å få et output, må vi bruke (vi sier også “kalle på”) funksjonen:

funksjonsverdi = f(2) # Kaller på funksjonen
print(funksjonsverdi)

# Eller
print(f(2))           # Kaller på funksjonen inni en print-funksjon
1
1

Underveisoppgave

Lag en Python-funksjon som representerer den matematiske funksjonen \(f(x) = \frac{-x}{2} + \sqrt{x}\). Lag ei løkke som skriver ut 100 ulike funksjonsverdier.

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

# Definerer to funksjoner
def f(x):
    print(x**2 + x - 5)
    
def gratulerer(navn):
    print("Gratulerer med dagen,", navn)

# Kaller på funksjonene
f(2)
gratulerer("Silje")
1
Gratulerer med dagen, Silje

Her ser vi at vi ikke trenger å skrive print når vi kaller på funksjonene. Dette ser da enda enklere ut enn å bruke retur-verdier, så hvorfor bruker vi return i det hele tatt?

Det er faktisk bedre å bruke return enn print, der det er mulig. Hvis vi for eksempel er interessert i å gjøre noe annet med funksjonsverdiene enn å printe dem, må vi ha konkrete verdier å jobbe med. La oss si at vi ønsker å finne differansen mellom to funksjonsverdier. Hvis vi skal regne med funksjonsverdier, må vi ha en returverdi. Det fungerer nemlig ikke å trekke fra hverandre to print-funksjoner. Eksempelet nedenfor illustrerer dette. Følgende kodesnutt vil gi riktig resultat:

def f(x):
    return x**3 - 1/x
    
print(f(3) - f(1))
26.666666666666668

Mens denne kodesnutten vil gi feilmelding:

def f(x):
    print(x**3 - 1/x)
    
f(3) - f(1)
26.666666666666668
0.0
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [2], line 4
      1 def f(x):
      2     print(x**3 - 1/x)
----> 4 f(3) - f(1)

TypeError: unsupported operand type(s) for -: 'NoneType' and 'NoneType'
import numpy as np

def areal_sirkel(r):
    A = np.pi*r**2
    return A

def volum_sylinder(r, h):
    V = np.pi*r**2*h
    return V

Vi kan også skrive np.pi*r**2 og np.pi*r**2*h direkte etter return i funksjonene ovenfor, istedenfor å gjøre det på to linjer. Dette er litt smak og behag, men ofte kan det være mer oversiktlig å gjøre ting på flere linjer enn på én. Dessuten kan man skrive formelen direkte slik den forekommer i matematikken.

Underveisoppgave

Volumet til ei kule er gitt ved \(\frac{4}{3}\pi r^3\). Lag en funksjon som beregner dette volumet og finner differansen mellom volumet til ei kule med radius 10 og ei kule med radius 5.

Her ser vi også at den siste funksjonen tar to parametre. Det er mulig å bruke så mange parametre i en funksjon som du ønsker. Det går også an å lage funksjoner uten parametre, for eksempel slik:

def hei():
    print("Hei på deg!")
    
hei()
Hei på deg!

Parameternavn#

La oss se på et eksempel der vi kaller på en funksjon på tre måter.

def fart(s, t):
    v = s/t
    return v

# Funksjonskall 1
s = 10 # Strekning i meter
t = 2  # Tid i s
print("Farten er", fart(s, t), "m/s.")

# Funksjonskall 2
strekning = 10
tid = 2
print("Farten er", fart(strekning, tid), "m/s.")

# Funksjonskall 3
print("Farten er", fart(10, 2), "m/s.")
Farten er 5.0 m/s.
Farten er 5.0 m/s.
Farten er 5.0 m/s.

Vi ser at vi får samme output for alle funksjonskallene. Vi trenger ikke å definere variabler før vi setter dem inn i funksjonen, så funksjonskall 3 er kanskje det enkleste. Men hvis vi for eksempel skal bruke verdien for tid flere steder, kan det være lurt å ha det som en egen variabel. Denne variabelen kan vi kalle hva vi vil, for den blir uansett overført til variabelen t inni funksjonen. Så om vi kaller variablene for strekning og tid eller s og t, har ingenting å si. Inni funksjonen blir likevel verdien til strekning overført til variabelen s og variabelen t får verdien til tid.

Funksjoner med flere returverdier#

I motsetning til funksjoner i matematikk kan en funksjon i programmering ha flere retur-verdier. Disse kan vi tilordne til variabler adskilt med komma, som vist nedenfor.

Underveisoppgave

Forklar hvordan programmet ovenfor fungerer. Modifiser programmet slik at det også returnerer renta, og skriv ut “Det tar {tid} år før du har {penger} kroner i banken med en rente på {renter*100} prosent.”

Lokale og globale variabler#

Hva skjer hvis vi ikke returnerer verdier i funksjonen ovenfor? Vil vi uansett kunne printe renta og antallet år? La oss undersøke dette.

def penger_i_banken(startkapital, sluttkapital, renter):
    kapital = startkapital
    år = 0
    while kapital <= sluttkapital:
        kapital = kapital + kapital*renter
        år = år + 1
    return kapital

penger = penger_i_banken(1000, 3000, 0.01)
print("Det tar", år, "år før du har", round(penger,2), "kroner med en rente på", renter*100, "prosent")
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_39764/3569527658.py in <module>
      8 
      9 penger = penger_i_banken(1000, 3000, 0.01)
---> 10 print("Det tar", år, "år før du har", round(penger,2), "kroner med en rente på", renter*100, "prosent")

NameError: name 'år' is not defined

Her får vi visst en feilmelding, selv om vi klart kan se at “år” er definert som en variabel inni funksjonen. Dette handler om at alle variabler som defineres i en funksjon, kun er tilgjengelig inni denne funksjonen. De kalles derfor lokale variabler. Variabler som er definert utenfor funksjoner, kaller vi da for globale variabler. Disse er tilgjengelig både inni og utenfor en funksjon. Her er to eksempler som viser dette:

def funksjon():
    print(a)

a = "Her er jeg!"

funksjon()
print(a)  # Skriver ut den globale variabelen a
Her er jeg!
Her er jeg!
def funksjon():
    b = "Her er jeg!" # b defineres lokalt inni funksjonen
    print(b)

funksjon()
print(b) # Prøver å skrive ut den lokale variabelen. Vi får dermed en feilmelding
Her er jeg!
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-36-9fcd0c311f14> in <module>
      4 
      5 funksjon()
----> 6 print(b) # Prøver å skrive ut den lokale variabelen. Vi får dermed en feilmelding

NameError: name 'b' is not defined

Vi kan gjøre en lokal variabel til en global variabel, dersom vi trenger det. Dette er ikke vanlig så vanlig å gjøre, men vi kan gjøre det slik:

def masseenergi(m):
    global c
    c = 3E8 # lyshastigheten i m/s
    E = m*c**2
    return E

print("Energien til legemet er:", masseenergi(1), "joule.")
print("Lysets hastighet i vakuum:", c, "m/s.")
Energien til legemet er: 9e+16 joule.
Lysets hastighet i vakuum: 300000000.0 m/s.

Oppgaver#

Oppgave 5.1

Forklar hvordan programmet nedenfor fungerer.

def f(x):
    return x + 1

addisjon = f(1) + f(3)
subtraksjon = f(1) - f(3)

print(addisjon, subtraksjon)

Oppgave 5.2

I programmet nedenfor definerer vi en funksjon som regner ut volumet til en sylinder. Lag en annen funksjon i samme program som regner ut volumet til ei kule.

(\(V_{kule} = \frac{4}{3}\pi r^3\))

Oppgave 5.3

Hvert program i denne oppgava inneholder noen feil. Finn feilene og rett på dem slik at programmene kan kjøres korrekt.

  1. Funksjonen skal regne ut \(f(x) = \frac{1}{2x} + 1\) og returnere svaret. I programmet skal funksjonen kalles på for \(x = 4\):

def f(x):
    1/2*x + 1

print("f(x) = ",f(x))
  1. Programmet ber brukeren om å skrive en verdi for x og regner ut \(f(x) = 3x + \cos(x)\):

def f(x):
return 3x + cos(x)

y = input("Skriv inn verdi for x i radianer: ")
print("f(x) =",f(y))
  1. Programmet skal skrive ut funksjonsverdien G(1).

def G(t):
    a = t**2 - 2
    return a

t = 1
print(a)

Oppgave 5.4

Lag et program eller flere programmer som bruker funksjoner til å regne ut:

  1. Arealet til en sirkel.

  2. Radius til en sirkel gitt arealet.

  3. Omkretsen til en sirkel.

  4. Volumet til ei kule.

  5. Overflatearealet til ei kule.

Du kan lage en enkel versjon først uten funksjoner. Lag så en versjon som inneholder funksjoner av hver av formlene. Ikke ta input fra brukeren, men sett verdiene direkte inn i funksjonskallene.

Oppgave 5.5

\i


Oppgave 5.6

Karvonens formel kan brukes til å finne pulsen til en person gitt hvilepuls \(H_{hvile}\) og treningsintensitet \(p\) (i prosent):

\(hjerteslag \ per \ minutt = \left(H_{maks} - H_{hvile}\right)\cdot\frac{p}{100} + H_{hvile}\)

der \(H_{maks}\) er maks antall hjerteslag personen kan ha. Den maksimale pulsen kan en finne ved \(H_{maks} = 220 - \textit{alder til person}\). Lag et program som regner ut pulsen til en 20 år gammel person som trener med 60 % intensitet og hvilepuls på \(70\) slag per minutt. Lag Karvonens formel som en funksjon.

Oppgave 5.7 (kjemi)

I kjemi har vi ofte bruk for molregning. Lag et enkelt program som regner ut antall mol dersom brukeren taster inn molmasse og masse av et bestemt stoff. Du kan også be brukeren taste inn stoffet det gjelder, slik at du får dette som output også. Lag formelen som en funksjon.

Oppgave 5.8 (kjemi)

Lag et program som regner ut pH fra \([H_3O^+]\) ved hjelp av en funksjon.

Oppgave 5.9

Programmer én av bevegelsesformlene (kinematikklikningene) fra fysikk som en funksjon. Du kan selv velge hva programmet skal regne ut.

Oppgave 5.10

Bruk Bohrs formel for spektrene til hydrogenatomet: \(f =\frac{B}{h}\cdot \left( \frac{1}{m^2} - \frac{1}{n^2} \right)\)

Lag et program som regner ut bølgelengden til fotonet som emitteres når et elektron deeksiterer fra skall n til m. Bruk en funksjon.

Husk at vi har følgende sammenheng mellom frekvens og bølgelengde (\(\lambda\)):

\(\lambda = \frac{c}{f}\)

\(B = 2.18\cdot10^{-18}\), \(c = 3.00\cdot10^8\) m/s og \(h = 6.63\cdot10^{-34}\).

Oppgave 5.11

Lag en funksjon som tar tre variabler a, b og c, tilsvarende koeffisientene i andregradsfunksjoner av typen \(f(x) = ax^2 + bx + c\). La funksjonen løse andregradslikninger av typen \(f(x) = 0\) ved hjelp av andregradsformelen.

Oppgave 5.12

Hvorfor har x samme verdi før og etter funksjonen f har blitt kalt på i programmet under?

def f(x):
    x = x + 3
    return 9*x
x = 3
print(x) # Skriver ut 3
y = f(x)
print(x) # Skriver ut 3

Oppgave 5.13

De fleste gasser kan modelleres med tilstandslikninga for ideelle gasser:

\(PV = nRT\)

der P er trykket i pascal, V er volumet i kubikkmeter, n er stoffmengden i mol, \(R = 8.3144598 J/(mol\cdot K)\) er gasskonstanten og T er temperaturen i kelvin.

Lag et program der du bruker denne likninga til å lage en funksjon for P og en annen for T. Test funksjonene.

Oppgave 5.14*

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

def f(x,y):
    global e
    e = x + y + e
    return e

c = 1
d = 2
e = 3

print(f(c, d) + e)

Oppgave 5.15

I en løsning er pH et mål på konsentrasjonen av oksoniumioner:

\[pH = - log([H_3O^+])\]

a) Lag en funksjon som tar som parameter konsentrasjonen av oksoniumioner og returnerer pH-en i løsningen. Test funksjonen med \([H_3O^+] = 1\cdot 10^{-5}\) mol/L, noe som vil gi \(pH = 5\).

b) Utvid funksjonen slik at den også skriver ut hvorvidt løsningen er sur, nøytral eller basisk.

En løsning vil sjeldent ha pH eksakt lik 7, og programmet vil derfor nesten aldri skrive ut at løsningen er nøytral. Vi kan kompensere for dette på ulike måter. Vi kan se på to mulige løsninger her. Den første kan være å runde av pH-en til et visst antall desimaler. Dette kan for eksempel gjøres med funksjonen round(verdi, antall desimaler). Den andre løsningen går på å legge til en toleranseparameter, tol, slik at nøytral pH defineres som \(pH = 7 \pm tol\).

c) Ta utgangspunkt i funksjonen fra b) og bruk avrundingsfunksjonen slik at vi får litt slingringsmonn på nøytral pH. Rund av til ett desimal og gjør justeringer i koden slik at f.eks. \([H_3O^+] = 1.1\cdot 10^{-7}\) gir utskriften “Løsningen er nøytral”.

d) Ta utgangspunkt i funksjonen fra b) og legg inn en toleranseparameter i funksjonen som gjør at \([H_3O^+] = 1.3\cdot10^{-7}\) gir utskriften “Løsningen er nøytral” dersom toleransen er 0.2.

e) Hvilke fordeler er det med å bruke en toleranseparameter i slike beregninger?

Oppgave 5.16

pH-en i en buffer med bufferparene HA (svak syre) og A\(^-\) (korresponderende svak base) er gitt ved bufferlikningen:

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

a) Lag en funksjon som tar \(pK_a\) og konsentrasjonen av syra og korresponderende base som parametere. Funksjonen skal returnere pH-en i løsningen. b) Test funksjonen for en eddiksyre-acetat-buffer (\(pK_a = 4.76\)). Kall på funksjonen med \([CH_3COOH] = 2.3\cdot 10^{-3}\) mol/L og \([CH_3COO^-] = 2.0\cdot 10^{-3}\) mol/L. Testen bør gi pH = 4.82.

Video#

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