Operatorer

KategoriOperatorer
Aritmetikk**
* / // %
+ -
Relasjoner== != < <= > >= in not in is is not
Logikknot
and
or
Betingelse... if ... else ...

Aritmetikk med tall

Symbolene + - * / ** utfører henholdsvis addisjon, subtraksjon, multiplikasjon, divisjon og eksponentiering med to tall.

Alle operatorene fungerer likt for både heltall (int) og flyttall (float), men merk at divisjon / alltid returnerer et flyttall, selv om resultatet numerisk sett er et heltall.

print(6 + 2) # 8
print(6 - 2) # 4
print(6 * 2) # 12
print(6 / 2) # 3.0
print(6 ** 2) # 36
print(36 ** 0.5) # 6.0 (en eksponent på 0.5 er det samme som kvadratrot)
Aritmetikk med strenger
# Strenger repeteres flere ganger med gangesymbol (*) og et heltall
print("bar" * 2) # barbar
# Strenger konkateneres (limes sammen) med pluss (+)
a = "foo"
b = "bar"
c = a + b
print(c) # foobar
Heltallsdivisjon og modulo

Heltallsdivisjon med restverdi er den første formen for divisjon vi lærte på barneskolen. La oss si at du skal fordele 14 gullmynter på 4 pirater: da kan hver pirat få 3 gullmynter, og så blir det 2 gullmynter til overs. Vi kan uttrykke regnestykket i Python ved å benytte operatorene for heltallsdivisjon (//) og modulo (%) slik:

coins = 14
pirates = 4
coins_per_pirate = coins // pirates
remainder = coins % pirates

print(coins, "gullmynter skal fordeles på", pirates, "sjørøvere.")
print("Hver sjørøver får da", coins_per_pirate, "gullmynter",
      "og det blir", remainder, "mynter til overs.")

Heltallsdivisjon er som vanlig divisjon, men runder alltid nedover (mot negativ uendelig).

print("Operatøren / utfører vanlig divisjon")
print(" 7 / 4  =", (7/4))  # 1.75
print()
print("Operatøren // utfører heltallsdivisjon:")
print(" 7 // 4 =", ( 7//4)) # 1 (runder nedover)
print("-1 // 4 =", (-1//4)) # -1 (runder også nedover)
print("-7 // 4 =", (-7//4)) # -2 (runder også nedover)
print("Når nevneren er negativ")
print(" 7 // -4 =", (7//-4)) # -2 (runder også nedover)
print("-7 // -4 =", (-7//-4)) # 1 (runder altså alltid nedover uansett)

Modulo-operatoren (%) returnerer «resten» etter heltallsdivisjon. Vi kan bruke dette for å avgjøre om et tall er delelig med et annet (hvis resten er 0, er det delelig).

print(8 % 3) # 2
print(7 % 3) # 1
print(6 % 3) # 0    6 er delelig med 3
print(5 % 3) # 2
print(4 % 3) # 1
print(3 % 3) # 0    3 er delelig med 3
print(2 % 3) # 2
print(1 % 3) # 1
print(0 % 3) # 0    0 er delelig med 3
print(-1 % 3) # 2
print(-2 % 3) # 1
print(-3 % 3) # 0   -3 er delelig med 3
print(-4 % 3) # 2
print(-5 % 3) # 1
print(-6 % 3) # 0   -6 er delelig med 3

En annen vanlig bruk av modulo er å finne siste siffer i et tall:

print(123 % 10) # 3
print(1234 % 10) # 4
print(12345 % 10) # 5

En siste vanlig bruk av modulo, er for å få en verdi til å «gå i ring», eller holde seg innenfor et visst intervall. For eksempel, la oss si at vi ønsker at en viss variabel alltid skal befinne seg innenfor intervallet 0-400. Da kan vi bruke modulo-operatoren til å «wrappe» verdien tilbake til intervallet dersom den skulle komme utenfor:

x = 385

...

x = (x + 10) % 400
print(x) # 395 (som forventet når vi gjør 385 + 10)

...

x = (x + 10) % 400
print(x) # tilbake til 5 i stedet for 405, fordi 405 % 400 blir 5
Sammenligning av verdier

Relasjons-operatorene benyttes for å sammenligne to verdier, og resulterer alltid i en boolsk verdi (enten True eller False).

print("== sammenligner om to verdier er like")
print(2 == 2) # True
print(2 == 3) # False
print(2 == 2.0) # True
print("foo" == 'foo') # True
print("foo" == "bar") # False
print()

print("!= sammenligner om to verdier er ulike")
print(2 != 2) # False
print(2 != 3) # True
print(2 != 2.0) # False
print("foo" != 'foo') # False
print("foo" != "bar") # True
print("< sammenligner om venstre side er «mindre enn» høyre side")
print(2 < 3) # True
print(2 < 2) # False
print(2 < 1) # False
print("foo" < "barbar") # False (sammenligner «ASCII-alfabetisk»)
print("foo" < "foo") # False
print("barbar" < "foo") # True 
print()

print("<= sammenligner om venstre side er «mindre enn eller lik» høyre side")
print(2 <= 3) # True
print(2 <= 2) # True
print(2 <= 1) # False
print("foo" <= "barbar") # False (sammenligner «ASCII-alfabetisk»)
print("foo" <= "foo") # True 
print("barbar" <= "foo") # True

Operatorene > og >= fungerer likt som < og <=, men med motsatt fortegn.

Flyttall og avrundingsfeil

Se også videoen Floating point numbers av Computerphile.

print(0.1 + 0.1 == 0.2)        # True, men...
print(0.1 + 0.1 + 0.1 == 0.3)  # False! 
print(0.1 + 0.1 + 0.1)         # gir 0.30000000000000004 (oj sann!)
print((0.1 + 0.1 + 0.1) - 0.3) # gir 5.55111512313e-17 (lite, men ikke 0!)

Derfor: Ikke bruk == for å sammenligne flyttall! Sjekk i stedet at de to tallene som sammenlignes er nesten like.

def almost_equals(a, b):
    epsilon = 0.0000000001
    return abs(a - b) < epsilon # abs()-funksjonen gir absolutt-verdien

print(0.1 + 0.1 + 0.1 == 0.3)  # Feil
print(almost_equals(0.1 + 0.1 + 0.1, 0.3))  # Riktig
Medlemskap

Operatorene in og not in brukes for å sjekke om en verdi er medlem av en liste, tuple, mengde eller streng.

# Sjekk om symboler finnes i strenger
print("a" in "abc") # True
print("d" in "abc") # False
print("A" in "abc") # False ("A" og "a" er forskjellige symboler)

print("a" not in "abc") # False
print("d" not in "abc") # True
print()

print("bc" in "abc") # True
print("ac" in "abc") # False (selv om både "a" og "c" er i "abc")
# Sjekk om en verdi finnes i en liste eller ikke
print(1 in [1, 2, 3]) # True
print(4 in [1, 2, 3]) # False
print(1 not in [1, 2, 3]) # False
print(4 not in [1, 2, 3]) # True
# Sjekk om en verdi finnes i en tuple eller ikke
print(1 in (1, 2, 3)) # True
print(4 in (1, 2, 3)) # False
print(1 not in (1, 2, 3)) # False
print(4 not in (1, 2, 3)) # True
# Sjekk om en verdi finnes i en mengde eller ikke
print(1 in {1, 2, 3}) # True
print(4 in {1, 2, 3}) # False
print(1 not in {1, 2, 3}) # False
print(4 not in {1, 2, 3}) # True
Logiske operatorer

Logiske operatorer bruker vi for å kombinere boolske verdier. De tre logiske operatorer er and, or og not.

print("and returnerer True hvis begge leddene er True")
print(True and True) # True
print(True and False) # False
print(False and True) # False
print(False and False) # False
print()

print("or returnerer True hvis minst ett av leddene er True")
print(True or True) # True
print(True or False) # True
print(False or True) # True
print(False or False) # False
print()

print("not returnerer motsatt boolsk verdi")
print(not True) # False
print(not False) # True

Det er vanlig å benytte logiske operatorer for å binde sammen flere uttrykk som hver for seg evaluerer til boolske verdier.

age = 2000
if (age < 0) or (age > 130):
    print("I find it quite hard to believe you're", age, "years old!")
Uttrykk med betingelse (if else)
print("Foo" if True else "Bar") # Foo
print("Foo" if False else "Bar") # Bar
print("Foo" if 1 < 2 else "Bar") # Foo
print()

x = -3
print(0 if x < 0 else x) # 0 (fordi -3 < 0 er True)
Presedens og assosiativitet

En av de aller vanligste feilene som gjøres (f. eks. på eksamen) er at man gjør feil antakelse om hvilken rekkefølge operatorer i et større uttrykk utføres i; hvordan de «usynlige parentesene» i uttrykket er plassert.

For aritmetikk gjelder de samme presedens-reglene som er vanlig i matematikk.

print("Presedens:")
print(2 + 3 * 4)  # gir 14, ikke 20   ( * har høyere presedens enn + )
print(5 + 4 % 3)  # gir  6, ikke 0    ( % har høyere presedens enn + )
print(2 ** 3 * 4) # gir 32, ikke 4096 (** har høyere presedens enn * )
Presedenstabell

Vi gir her en oversikt over noen operatorer rangert fra høyeste til laveste presedens. Parenteser vil alltid overstyre presedens og assosiativitet, og er derfor øverst på listen. Alle operatører untatt ** og relasjonene assosierer venstre-til-høyre dersom det er aktuelt.

Operatorer
()
Parentes. Det som er mellom parentesene evalueres før en operator utenfor parentesen.
**
Eksponentiering. Assosierer høyre-til-venstre.
* / // %
Multiplikasjon, divisjon og modulo.
+ -
Addisjon og subtraksjon.
< <= > >= == != in not in is is not
Relasjoner. Disse vil ikke assosiere verken til høyre eller venstre; dersom man har flere slike etter hverandre vil de komponeres som en konjunksjon i stedet. For eksempel, -1 < 0 == False gir det samme svaret som -1 < 0 and 0 == False, og altså ikke det samme som (-1 < 0) == False slik man ellers kunne trodd.
not
Logisk negasjon.
and
Logisk konjunksjon.
or
Logisk disjunksjon.
if else
Betinget verdi.

I presedenstabellen over (og også i tabellen øverst på denne siden) er operatorene sortert etter presedens. Det vil si, ** har høyeste presedens mens ... if ... else ... har den laveste. Operatorer i samme rad har samme presedens (for eksempel har + og - samme presedens).

Det er operatorene med høyest presedens som utføres «først» med mindre parenteser indikerer noe annet.

Assosiativitet

Dersom flere operasjoner med samme presedens forekommer i samme uttrykk, utføres de som hovedregel fra venstre til høyre.

print("Assosiativitet: venstre til høyre")
print(5 - 4 - 3)  # det samme som (5 - 4) - 3, altså -2 (ikke 4)
print(9 // 3 // 3) # det samme som (9 // 3) // 3, altså 1 (ikke 9)

Det finnes likevel noen unntak:

Parenteser

Parenteser vil alltid overstyre presedens og assosiativitet. Det er god stil å bruke parenteser for å vise hvilken rekkefølge du ønsker at operatorene utføres i, selv om det ikke alltid er nødvendig – det gjør koden din mer lesbar og mindre utsatt for feil som skyldes at du ikke husker presedenstabellen.

Eksempler

Under er det noen eksempler hvor det er fort gjort å feiltolke hvordan uttrykket evalueres fordi det ikke er angitt parenteser. Bruk reglene for presedens og assosiativitet kombinert med presedenstabellen og prøv å forutsi hva hvert uttrykk evaluerer til før du kjører koden og ser fasiten.

print(True or True and False) 
print(not False or True)
print(not (False or True))
print()
print(2 < 3 < 4)
print(not 3 < 2 < 1)
print(not 3 < 2 and 2 < 1)
print()
print("b" in "box")
print("b" in "box" == True) # (krasjer i nettleseren; men prøv på egen maskin)
print("a" and "b" in "box")
print("a" or "z" in "box")

Moralen i historien: benytt parenteser for å vise hva du mener. Det er fort gjort å huske feil rekkefølge, og du kan heller ikke forvente at dine kolleger og ditt fremtidige jeg (som senere skal vedlikeholde koden) husker den.