Klasser - Intro

Skip to content

Dictionaries (som dere så i Python 6) er gode for å samle data. Men, når programmet blir stort, oppstår nye problemer ganske fort.

  • 🚫 Mange dictionaries, alle med samme nøkler 🗝️.
  • 🚫 Funksjoner som hører til dictionariet, eksempel: funksjonen som skrev ut filmen i Python 6.
  • 🚫 Her kan det fort bli lett å gjøre feil.
    • Se for deg at du skriver "directer" feil i stedet for "director".

Når du skriver feil i dictionary

Minor Spelling Mistake

For å unngå alle disse problemene: klasser.

Klasser hva er det? 🏛️🤔

En klasse er et slags “blueprint 🗺️” på ett eller annet. Dette blueprintet lager et objekt som du kan bruke.


La oss se på hoved-eksempelet fra Python 6, der vi lagde et dictionary for en film. Hvordan hadde dette sett ut som en klasse?

class Movie:
    def __init__(self, title, year, director, rating):
        self.title = title
        self.year = year
        self.director = director
        self.rating = rating

What…? 🥺👉👈

For å forstå alt dette må vi forklare en del konsepter!! 😱


Nytt Konsept! - Hva betyr class?

Først og fremst for å lage en klasse må vi bruke ordet class, etterfulgt av et navn. Navnet til en klasse er vanlig å skrive i CamelCase, altså hvert ord begynner med stor bokstav (ingen mellomrom).


Nytt Konsept! - Hva betyr __init__?

__init__ er en spesiell innebygd funksjon som forteller Python hvordan et objekt skal “bygges”. I dette tilfellet blir alle verdiene som nevnt over opprettet i objektet.

  • 🚫 Ikke tenk så mye på hva alt dette betyr akkurat nå, det kommer til å gi mening! 👍

Nytt Konsept! - Hva betyr self?

self er et innebygd ord i Python. Det betyr “denne” konkrete filmen. Igjen, et konsept som er litt vanskelig å skjønne med det første. Men vi kan se på det slik:

  • self.title betyr tittlen til akkurat denne filmen.
  • Men hva er “denne”? 🤔
    • Dette håper jeg blir forståelig når vi begynner å lage klasser, så la oss gjøre det nå.

❓ Hvor kommer title fra og hvor blir title av?

title kommer fra utsiden, dette skal vi se når vi lager et objekt i neste steg. Der den havner til slutt er i seg selv: self. title blir lagret i seg selv, altså self.title. title blir dermed en attributt i klassen. Fortsatt forvirrende? Det kan jeg forstå! Her er det bare å jobbe med det igjen og igjen så gir det plutselig mening!

👍👍 La oss heller gjøre noe praktisk:

✅ Lage et objekt ved hjelp av en klasse.

For å lage et objekt kan vi bruke oppskriften som er definert over. Dette skrives veldig likt som en funksjon:

movie1 = Movie("Inception", 2010, "Christopher Nolan", 8.8)

Det vi kan se her er at det nesten fungerer som en funksjon. Vi skriver navnet på det vi skal ha, så hiver vi inn variabler. Men her er forskjellen på en funksjon og en klasse. Her lages et objekt, en ting, en greie, en duppedings. Denne kan vi bruke videre.

CamelCase

Her håper jeg dere ser nytten med å ha forskjell på variabelnavn og klassenavn. Siden variabler er bare små bokstaver (med understrek _ i mellom ord) og klasser er CamelCase, er det lettere å se akkurat hva dette er i koden når vi skriver den. Vi vet at CamelCase er klasser.

✅ Bruke objektet

movie1 er en variabel som inneholder objektet vårt. Som med dictionaries kan vi hente ut og endre verdier i denne.

✅ Skrive ut verdier

Du kan skrive ut verdier slik:

print(movie1.title) # skriver ut "Inception"

Hva betyr punktum .

Her brukes punktum . i stedet for hakeparenteser [] som i dictionaries. Det gjør det samme. Men, punktum er en grei måte å se at noe er et objekt og ikke et dictionary.

✅ Endre på verdier

Du kan skrive ut verdier slik:

print(movie1.rating) # skriver ut "8.8"
movie1.rating = 9.0
print(movie1.rating) # skriver ut "9.0"

✅ Funksjoner i Klasser

Her kommer noe av det nyttigste du kan gjøre med klasser. Funksjoner inni klasser. Med dette kan du legge til funksjonalitet til et objekt. I Python 6 lagde du en funksjon som skrev ut informasjon fra et dictionary, her kan vi gjøre dette til en funksjon som printer ut informasjon om seg selv.

class Movie:
    def __init__(self, title, year, director, rating):
        self.title = title
        self.year = year
        self.director = director
        self.rating = rating

    def print_info(self):
        print(f"Filmen {self.title} kom ut i {self.year}.")
        print(f"Filmen ble regissert av {self.director} og fikk {self.rating} i rating.")

Her brukes self mye. Men alt denne gjør er å referere til seg selv. Når funksjonen brukes på objektet selv, vil den hente informasjonen fra seg selv.

Spør deg selv, hvis du skal si navnet ditt, sier du ikke noen andre sitt navn… du sier ditt eget navn. Du henter informasjonen om navnet ditt fra deg selv. Du selv har egenskaper som du vet om selv.

Dermed kan funksjonen brukes slik, husk parentesene ():

movie1.print_info()

Punktum .

Som med verdier i en klasse bruker vi punktum . for å bruke funksjoner i en klasse.

💡 Oppgaver Del 1 - Basic funksjonalitet

I dette oppgavesettet skal vi lage et enkelt RPG (**R**ole **P**laying **G**ame) med en spill-karakter.

Oppgave 1.1 - Lag en klasse

Opprett en ny Python fil som heter game.py.

Lag en klasse kalt Player og legg inn følgende attributter i spilleren:

  • name
  • level
  • health
  • alive
Eksempel-Løsning
class Player:
    def __init__(self, name, level, health, alive):
        self.name = name
        self.level = level
        self.health = health
        self.alive = alive

Oppgave 1.2 - Lag et Player-objekt

Lag en variabel kalt player1 som skal holde på Player-objektet. Her velger du verdiene selv.

Print deretter ut navnet og levelen og helsen til spilleren.

Eksempel-Løsning
player1 = Player("Alex", 1, 100, True)

print(player1.name)
print(player1.level)
print(player1.health)

Oppgave 1.3 - Oppdater verdier

Oppdater health til spilleren til en lavere verdi. Skriv ut den nye helsen.

Eksempel-Løsning
print(player.health) # printer 100

player1.health = 90

print(player.health) # printer 90

Oppgave 1.4a - Print status

Legg til en funksjon i klassen Player som skriver ut informasjon om spilleren kalt print_stats. Her trenger du ingen parametre i funksjonen (utenom self).

Eksempel-Løsning
class Player:
    def __init__(self, name, level, health, alive):
        self.name = name
        self.level = level
        self.health = health
        self.alive = alive

    def print_stats(self):
        print(f"Spiller: {self.name} (Level {self.level})")
        print(f"Helse: {self.health}")

Du kan teste om dette fungerer med følgende kode:

player1.print_stats()

Oppgave 1.5a - Lever jeg?

Lag en funksjon i klassen kalt print_alive som skriver ut en melding om spilleren lever eller ikke.

Eksempel-Løsning
class Player:
    def __init__(self, name, level, health, alive):
        self.name = name
        self.level = level
        self.health = health
        self.alive = alive

    def print_stats(self):
        print(f"Spiller: {self.name} (Level {self.level})")
        print(f"Helse: {self.health}")

    def print_alive(self):
        if self.alive:
            print("🟢 Spilleren lever!")
        else:
            print("🔴 Spilleren lever ikke! 😭")

Oppgave 1.5b - Alive in Stats

Bruk print_alive funksjonen i print_stats funksjonen for også skrive ut om du lever når du spør om stats.

💡 Hint: Du kan bruke self når du bruker funksjoner også!

Eksempel-Løsning
def print_stats(self):
    print(f"Spiller: {self.name} (Level {self.level})")
    print(f"Helse: {self.health}")

    self.print_alive()

💡 Oppgaver Del 2 - Et enkelt kamp spill

I denne delen skal du lage et enkelt kamp spill der spillere kan miste helse og “dø” 💀.

Nytt Konsept! - Default-verdier!

Du kan ha “default” verdier i en klasse. Altså, er det nødvendig å gi at en spiller er alive til å begynne med?

  • 🤔 Er den ikke alltid det?
  • ❗ Som oftest!

Dette kan vi bruke en “default”-verdi til! Slik gjøres det:

class Player:
    def __init__(self, name, level, health, alive=True):
        # resten holder seg likt

Her er eneste forskjellen at det står alive=True, det forteller at den skal være True som default. Nå trenger du ikke lengre å skrive True når du lager objektet!

player1 = Player("Alex", 1, 100)

⚠️ Eksempel-løsningene fremover kommer til å bruke denne!

Oppgave 2.1a - To spillere

Under objektet player1, lag et nytt objekt som heter player2. Gi noen passende verdier her.

player1 = Player("Alex", 1, 100)
player2 = Player("Steve", 1, 90)

Oppgave 2.1b - Print stats

Skriv ut stats til begge spillerene. Hva skjer?

player1.print_stats()
player2.print_stats()

Nyttig!

Her kan vi se at vi har lagd to objekter med helt forskjellig informasjon, og kan skrive ut informasjonen om objektet når vi spør om det det objektet.


💡 Nytt konsept! - Funksjoner med parametre

Til nå har funksjonene våre bare brukt informasjon som allerede finnes inni objektet (self).

Men noen ganger trenger en funksjon ekstra informasjon utenfra.

Eksempel:

  • Hvis vi skal lage en funksjon som gjør “damage”…
    • 🤔 Hvor mye “damage” tar spilleren?

Dette løses med parametere.

✅ Dette skrives akkurat på samme måte som en vanlig funksjon, men, vi må huske å ha med self først.

Oppgave 2.2a - Damage! 🔪😱

Lag en funksjon i Player-klassen som heter take_damage. Denne skal ta inn en parameter: damage. Denne forteller hvor mye helse som skal trekkes fra spillerens helse. Skriv også ut en liten melding når dette skjer.

Eksempel-Løsning
class Player:
    def __init__(self, name, level, health, alive=True):
        self.name = name
        self.level = level
        self.health = health
        self.alive = alive

    # ... print funksjoner fra før er her

    def take_damage(self, damage):
        self.health = self.health - 10

        print(f"{self.name} tok {damage} skade! Spilleren har nå {self.health} helse.")

Oppgave 2.2b - Test om en spiller tar skade

Sett opp en liten test som skriver ut stats til spiller1. Så tar spilleren 20 damage. Hva skjer med stats nå?

Eksempel-Løsning
player1.print_stats()
player1.take_damage(20)
player1.print_stats()

Her ser vi at player1.health går fra 100 til 80.

Oppgave 2.3a - Logikk når spilleren “dør” 💀

Legg til en liten if sjekk i take_damage.

Denne sjekker:

  • Om health er 0 eller mindre.
    • Hvis dette skjer, sett spillerens alive til False.
Eksempel-Løsning
def take_damage(self, damage):
    self.health = self.health - 10

    if self.health <= 0:
        self.alive = False

    print(f"{self.name} tok {damage} skade! Spilleren har nå {self.health} helse.")

Oppgave 2.3b - Helse mindre enn 0

Hva skjer når helsen blir mindre enn null nå? Skjer alt som forventet?

  • ❓ Gir det mening at helse kan være mindre enn 0? 🤔
  • ✅ Fiks dette ved å sette health til 0 også i if-en, slik at den aldri blir mindre enn 0.
Eksempel-Løsning
def take_damage(self, damage):
    self.health = self.health - 10

    if self.health <= 0:
        self.health = 0
        self.alive = False

    print(f"{self.name} tok {damage} skade! Spilleren har nå {self.health} helse.")

Oppgave 2.3c - Final fixes!

Endre på koden til å kun skrive ut "tok skade!" meldingen når spilleren lever. Ellers så skriver du ut at spilleren døde.

Eksempel-Løsning
def take_damage(self, damage):
    self.health = self.health - 10

    if self.health <= 0:
        self.health = 0
        self.alive = False

        print(f"{self.name} døde. 💀")
    else: 
        print(f"{self.name} tok {damage} skade! Spilleren har nå {self.health} helse.")

🔥 Videre…

I Level 2 (kommer senere 🕑), skal vi gjøre dette om til et interaktivt spill der to spillere kan kjempe mot hverandre.