Funksjoner#
Læringsutbytte
Etter å ha arbeidet med dette temaet, skal du kunne:
bruke funksjoner til å strukturere og gjenbruke kode.
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.
Løsningsforslag
import numpy as np
def f(x):
return -x/2 + np.sqrt(x)
for x in range(100):
print(f(x))
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.
Løsningsforslag
import numpy as np
def volum_kule(r):
V = (4/3)*np.pi*r**3
return V
volumforskjell = volum_kule(10) - volum_kule(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!
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)
Løsningsforslag
Vi definerer først en funksjon f som skal returnere funksjonsverdien x + 1. Deretter kaller vi på (bruker) funksjonen ved å beregne summen av f(1) og f(3) og differansen mellom de samme funksjonsverdiene. Da henter programmet informasjon fra funksjonen ovenfor, og beregner slik: addisjon = (1 + 1) + (3 + 1) = 6 og subtraksjon = (1 + 1) - (3 + 1) = -1. Resultatene fra dette skrives så ut.
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\))
Løsningsforslag
from numpy import pi
def volum_kule(r):
V = 4/3*pi*r**3
return V
# Tester funksjonen
print(volum_kule(2))
Oppgave 5.3
Hvert program i denne oppgava inneholder noen feil. Finn feilene og rett på dem slik at programmene kan kjøres korrekt.
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))
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))
Programmet skal skrive ut funksjonsverdien G(1).
def G(t):
a = t**2 - 2
return a
t = 1
print(a)
Løsningsforslag
Uttrykket \(1/2*x + 1\) regner ut \(f(x) = x + 1\), og ikke den ønskede funksjonen. For at programmet skal regne ut hva x blir i den ønskede funksjonen, må parentes brukes i uttrykket for nevneren. Variabelen x er heller ikke definert. Variabelen kan settes til å være lik 4. Vi kan også kalle funksjonen direkte med f(4).
def f(x):
return 1/(2* x) + 1
print("f(x) = ",f(4))
Her må cosinus importeres fra et passende bibliotek. Vi må også ha et innrykk på return i \(f(x)\), fordi return tilhører funksjonen. Leddet \(3x\) må omskrives til \(3*x\). Til slutt må variabelen \(y\) omgjøres til float for at programmet skal kunne gjøre flytallsoperasjoner på den gitte verdien fra brukeren.
from numpy import cos
def f(x):
return 3*x + cos (x)
y = float(input(" Skriv inn verdi for x i radianer: "))
print("f(x) =",f(y))
For å finne hva funksjonsverdien til G, må vi huske å kalle på funksjonen:
def G(t):
a = t**2 - 1
return a
t = 1
print(G(t))
Oppgave 5.4
Lag et program eller flere programmer som bruker funksjoner til å regne ut:
Arealet til en sirkel.
Radius til en sirkel gitt arealet.
Omkretsen til en sirkel.
Volumet til ei kule.
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.
Løsningsforslag
from numpy import pi
# 1
def sirkel_areal(r):
return pi*r**2
# 2
def sirkel_radius(A):
return (A/pi)**0.5 # Opphøyer i 0.5 eller kan bruke sqrt fra numpy
# 3
def sirkel_omkrets(r):
return 2*pi*r
# 4
def kule_volum (r):
return 4/3*pi*r**3
# 5
def kule_overflate (r):
return 4*pi*r**2
Oppgave 5.5
\i
Løsningsforslag
Verdien til x blir None fordi funksjonen f ikke returner en verdi. For å sørge for at x får en tallverdi etter å ha kalt på f, må f returnere noe – i dette tilfellet et tall.
def f(x):
return 2*x
x = 12
x = x + 12
x = f(x)
print(x)
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.
Løsningsforslag
def karvonen(hvilepuls, intensitet, alder):
p = intensitet
maks = 220 - alder
puls = (maks - hvilepuls)*p/100 + hvilepuls
return puls
puls = karvonen(70, 60, 20)
print(" Personen vil ha en puls på",puls )
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.
Løsningsforslag
def antall_mol (masse , molmasse ):
return masse/molmasse
stoff = input(" Hvilket stoff vil du finne antall mol til ?: ")
masse = float(input(" Skriv inn massen ( gram ): "))
molmasse = float(input(" Skriv inn molmassen ( gram /mol): "))
mol = antall_mol (masse , molmasse )
print("Stoffet", stoff, "består av", mol ,"mol.")
Oppgave 5.8 (kjemi)
Lag et program som regner ut pH fra \([H_3O^+]\) ved hjelp av en funksjon.
Løsningsforslag
from numpy import log10
def ph_H3O(konsentrasjon):
return -log10 (konsentrasjon)
ph = ph_H3O(1E-5)
print("pH av den gitte konsentrasjonen er:", ph)
Oppgave 5.9
Programmer én av bevegelsesformlene (kinematikklikningene) fra fysikk som en funksjon. Du kan selv velge hva programmet skal regne ut.
Løsningsforslag
def posisjon(v0 , a, t):
return v0 + a*t
v = posisjon(2, 10, 5) # Tester funksjonen med v0 = 2, a = 10 og t = 5.
print("Farten til legemet er:", v, "m/s.")
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}\).
Løsningsforslag
# Konstanter
B = 2.18E-18
h = 6.636E-34
c = 3e8
#Bohrs formel
def Bohr(n,m):
f = B/h *(1/ m**2 - 1/n **2)
bl = c/f # bølgelengde i meter
bl_nm = bl*1E9 # bølgelengde i nanometer
return bl_nm
#Energinivåer
n = int(input("Skriv inn en verdi for n:")) #skallet det deeksiteres fra
m = int(input("Skriv inn en verdi for m:")) #skallet det deeksiteres til
print("Bølgelengden til lyset fra n =",n ,"til m =", m,
"er:", round(Bohr(n,m)),"nm")
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.
Løsningsforslag
def andregradsformelen(a, b, c):
rotuttrykk = b**2 - 4*a*c
if rotuttrykk > 0:
x1 = (-b + rotuttrykk**0.5)/(2*a)
x2 = (-b - rotuttrykk**0.5)/(2*a)
return x1, x2
elif rotuttrykk < 0:
return "Likningen har ingen reelle løsninger."
elif rotuttrykk == 0:
x = -b/(2*a)
return x
print(andregradsformelen(1, 2, 3))
print(andregradsformelen(1, -2, 1))
print(andregradsformelen(1, -4, 3))
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
Løsningsforslag
$_x_$ er en global variabel utenfor funksjonen. Den får verdien 3. I tillegg finnes det en lokal variabel med samme navn inni funksjonen. Denne variabelen får verdien $_x = x + 3 = 3 + 3 = 6_$, men denne variabelen er ikke tilgjengelig utenfor funksjonen.
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.
Løsningsforslag
def trykk(V, n, T):
R = 8.3144598 # J/(mol*K)
P = n*R*T/V
return P
def temperatur(P, V, n):
R = 8.3144598 # J/(mol*K)
T = P*V/(n*R)
return T
print(trykk(100, 1, 300))
print(temperatur(100, 1, 1))
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)
Løsningsforslag
Variablene c_, d og e er globale variabler, mens x og y er lokale variabler som kun eksisterer inni funksjonen. Når vi printer f(c, d) + e, overføres verdien av c og d til de lokale variablene x og y i funksjonen. Deretter beregnes e ved hjelp av x, y og den globale e, som har verdien 3. Variabelen e fra funksjonen (nå med verdien 6) defineres som global, og overskriver dermed den tidligere e (med verdien 3). Det er denne e-en som legges til f(c, d) i print-kommandoen til slutt.
Oppgave 5.15
I en løsning er pH et mål på konsentrasjonen av oksoniumioner:
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?
Løsningsforslag
# a
import numpy as np
def surhet(oksonium):
return -np.log10(oksonium)
print(f"pH-en er {surhet(1E-5):.2f}")
# b
def surhet(oksonium):
pH = -np.log10(oksonium)
if pH > 7:
print("Løsningen er basisk.")
elif pH < 7:
print("Løsningen er sur.")
else:
print("Løsningen er nøytral.")
return pH
surhet(1E-5)
# c
def surhet(oksonium):
pH = -np.log10(oksonium)
if round(pH,1) == 7.0:
print("Løsningen er nøytral.")
elif pH < 7:
print("Løsningen er sur.")
else:
print("Løsningen er basisk.")
return pH
surhet(1.1E-7)
# d
def surhet(oksonium):
tol = 0.2
pH = -np.log10(oksonium)
if pH > 7 + tol:
print("Løsningen er basisk.")
elif pH < 7 - tol:
print("Løsningen er sur.")
else:
print("Løsningen er nøytral.")
return pH
surhet(1.3E-7)
Fordelen med å bruke toleranseparametere er at vi unngår problemet med at en verdi sjeldent blir eksakt på en datamaskin. I tillegg kan vi bruke en toleranse der vi ønsker at verdiene skal avvike litt fra en verdi, slik som med pH-beregningene ovenfor.
Oppgave 5.16
pH-en i en buffer med bufferparene HA (svak syre) og A\(^-\) (korresponderende svak base) er gitt ved bufferlikningen:
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.
Løsningsforslag
# a
import numpy as np
def bufferpH(pKa, c_base, c_syre):
pH = pKa + np.log10(c_base/c_syre)
return pH
# b
pH = bufferpH(4.76, 2.0E-3, 2.3E-3)
print(f"pH-en i bufferen er {pH:.2f}")
Video#
I videoen nedenfor kan du få en innføring eller repetisjon i den grunnleggende teorien bak funksjoner.