Operatorer
Kategori | Operatorer |
---|---|
Aritmetikk |
**
|
*
/
//
%
|
|
+
-
|
|
Relasjoner |
==
!=
<
<=
>
>=
in
not in
is
is not
|
Logikk |
not
|
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.
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 uttrykk utføres i; hvordan de «usynlige parentesene» i uttrykket er plassert.
Presedens
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 * )
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:
**
er høyre-assosiativ (det vil si at2 ** 3 ** 4
er det samme som2 ** (3 ** 4)
)- Relasjonene (altså
==
!=
<
<=
>
>=
in
not in
is
is not
) assosierer hverken til høyre eller til venstre; dersom man har flere slike i et uttrykk vil de komponeres som en konjunksjon i stedet. For eksempel,-1 < 0 == False
vil tolkes som(-1 < 0) and (0 == False)
, og altså ikke som(-1 < 0) == False
.
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 presedensrekkefølgen for operatorene gitt i tabellen øverst på siden 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) # (Brython/nettleser krasjer, men prøv i python)
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.