Olio metodin parametrina: luokka Tasovektori
Halutaan kirjoittaa ohjelma, jonka avulla voi käsitellä kaksiulotteisia
vektoreita. Vektorit ovat siis muotoa \(a\bar{i} + b\bar{j}\), missä
\(a\) kertoo vektorin x-akselin suuntaisen komponentin kertoimen ja
\(b\) vektorin y-akselin suuntaisen komponentin kertoimen. Kirjoitetaan
luokka Tasovektori
kuvaamaan tällaisia vektoreita. Luokan
koodissa edellä mainittuja kertoimia on kuvattu kentillä __x_kerroin
ja
__y_kerroin
.
Yksi vektoreille usein tarvittava toimenpide on pistetulon laskeminen.
Pistetulo lasketaan kahden vektorin välillä. Kun siis määritellään
pistetuloa laskevaa metodia pistetulo
, pitää sille välittää tieto
kahdesta eri vektorista, joiden välillä pistetulo lasketaan. Toinen
vektoreista on luonnollisesti metodin ensimmäinen parametri self
,
joka annetaan metodia kutsuttaessa ennen pistettä ja metodin nimeä.
Toinen vektori voidaan välittää metodille parametrina ihan samalla
tavalla kuin metodille annetaan parametrina esimerkiksi kokonaisluku tai
desimaaliluku.
Pistetulon laskevassa metodissa pitää selvittää molemmista vektoreissa
niiden __x_kerroin
ja __y_kerroin
-kenttien arvot. Koska
myös parametrina annettu toinen_vektori
viittaa saman Tasovektori
-luokan
olioon, voidaan tämä
tehdä suoraan käyttämällä pistenotaatiota seuraavasti:
def pistetulo(self, toinen_vektori):
tulo = self.__x_kerroin * toinen_vektori.__x_kerroin + \
self.__y_kerroin * toinen_vektori.__y_kerroin
return tulo
Tässä on siis selvitetty jonkin olion kentän arvo siten, että on annettu
ensin sen oliomuuttujan nimi, joka viittaa käsiteltävään olioon, sitten
piste ja sen jälkeen halutun kentän nimi. Tässä nimi self
tarkoittaa
sitä oliota, jolle metodia kutsutaan (johon viittaavan muuttujan nimi on
metodin kutsussa ennen pistettä) ja nimi toinen_vektori
metodille
parametrina annettua oliota (sitä, jonka nimi on metodin kutsussa
sulkujen sisällä).
Toinen tapa on käyttää kentän arvon selvittämiseen olion luokan omaa
metodia. Alla olevassa metodissa parametrina annetun olion kenttien
arvot on selvitetty käyttämällä saman luokan metodeita
kerro_x_kerroin
ja kerro_y_kerroin
. Tätä tapaa voidaan käyttää
myös silloin, kun parametri viittaa jonkin toisen luokan olioon.
def pistetulo2(self, toinen_vektori):
tulo = self.__x_kerroin * toinen_vektori.kerro_x_kerroin() + \
self.__y_kerroin * toinen_vektori.kerro_y_kerroin()
return tulo
Jos siis metodia kutsutaan esimerkiksi
a_vektori.pistetulo(b_vektori)
tai
a_vektori.pistetulo2(b_vektori)
niin molemmissa tapauksissa metodia lähdetään suorittamaan siten, että
metodissa nimi self
tarkoittaa sitä oliota, johon muuttuja
a_vektori
viittaa ja nimi toinen_vektori
sitä oliota, johon
muuttuja b_vektori
viittaa.
Alla olevassa animaatiossa on vielä kuvattu metodin pistetulo
toimintaa.
Animaatiossa on vain osa luokan Tasovektori
koodista.
Seuraavaksi luokan Tasovektori
koodi kokonaan.
Luokkaan on jätetty vain yksi versio
pistetulon laskevasta metodista. Sen lisäksi luokkaan on määritelty
metodi laske_pituus
, joka laskee vektorin pituuden Pythagoraan
lauseen avulla. Laskemisessa tarvitaan neliöjuuren laskevaa funktiota,
minkä takia luokassa on otetty käyttöön Pythonin valmis moduuli math
ja siihen kuuluva neliöjuuren laskeva funktio sqrt
. Luokassa on myös
metodi kerro_luvulla
, joka kertoo vektorin molemmat komponentit
parametrina annetulla luvulla. Lisäksi luokkaan on määritelty metodi
__str__
tekemään oliosta merkkijonoesitys. Vektoria kuvaava
merkkijono on koottu niin, että jos y-akselin suuntaisen komponentin
kerroin on negatiivinen, vektoria kuvaavassa merkkijonossa on
komponenttien välillä vain yksi miinusmerkki eikä plus- ja miinusmerkkiä
peräkkäin. Metodissa on käytetty myös f-stringejä muotoilemaan
merkkijonoesitykseen sijoitettavia kertoimien arvoja niin, että
ne esitetään kolmen desimaalin tarkkuudella.
import math
# Luokka kuvaa yhta 2-ulotteista vektoria.
class Tasovektori:
# Metodi __init__ alustaa vektorin kertoimet. Halutut
# kertoimet annetaan metodin parametrina.
def __init__(self, eka_kerroin, toka_kerroin):
self.__x_kerroin = eka_kerroin
self.__y_kerroin = toka_kerroin
# Metodi palauttaa vektorin x-akselin suuntaisen komponentin
# kertoimen.
def kerro_x_kerroin(self):
return self.__x_kerroin
# Metodi palauttaa vektorin y-akselin suuntaisen komponentin
# kertoimen.
def kerro_y_kerroin(self):
return self.__y_kerroin
# Metodi laskee ja palauttaa vektorin pituuden. Pituus
# lasketaan Pythagoraan lauseen avulla.
def laske_pituus(self):
return math.sqrt(self.__x_kerroin ** 2 + self.__y_kerroin ** 2)
# Metodi kertoo vektorin molemmat komponentit parametrina annetulla
# luvulla.
def kerro_luvulla(self, kertoja):
self.__x_kerroin *= kertoja
self.__y_kerroin *= kertoja
# Metodi laskee vektorin ja parametrina annetun vektori pistetulon.
# Metodi palauttaa lasketun pistetulon.
def pistetulo(self, toinen_vektori):
tulo = self.__x_kerroin * toinen_vektori.kerro_x_kerroin() + \
self.__y_kerroin * toinen_vektori.kerro_y_kerroin()
return tulo
# Metodi palauttaa merkkijonon, joka kuvaa vektoria.
def __str__(self):
if self.__y_kerroin >= 0:
mjono = f"{self.__x_kerroin:.3f}i + {self.__y_kerroin:.3f}j"
else:
mjono = f"{self.__x_kerroin:.3f}i - {-self.__y_kerroin:.3f}j"
return mjono
Alla on esimerkki pääohjelmasta, joka pyytää käyttäjältä kahden vektorin
tiedot ja suorittaa näille vektoreille erilaisia toimenpiteitä. Ohjelma
lukee käyttäjältä desimaalilukuja. Sitä varten on jälleen määritelty
apufunktio, joka sisältää myös mahdollisten virheellisten syötteiden
käsittelyn. Pääohjelmassa on oletettu, että luokka Tasovektori
on
tallennettu omaan moduuliinsa, jonka nimi on tasovektori
.
import tasovektori
def lue_desimaaliluku():
luku_onnistui = False
while not luku_onnistui:
try:
luku = float(input())
luku_onnistui = True
except ValueError:
print("Virheellinen desimaaliluku!")
print("Anna uusi!")
return luku
def main():
print("Anna ensimmaisen vektorin i-kerroin.")
i_kerroin = lue_desimaaliluku()
print("Anna ensimmaisen vektorin j-kerroin.")
j_kerroin = lue_desimaaliluku()
a_vektori = tasovektori.Tasovektori(i_kerroin, j_kerroin)
print("Antamasi vektori on", a_vektori)
print("Anna toisen vektorin i-kerroin.")
i_kerroin = lue_desimaaliluku()
print("Anna toisen vektorin j-kerroin.")
j_kerroin = lue_desimaaliluku()
b_vektori = tasovektori.Tasovektori(i_kerroin, j_kerroin)
print("Antamasi vektori on", b_vektori)
pituus1 = a_vektori.laske_pituus()
pituus2 = b_vektori.laske_pituus()
print(f"Vektorin {a_vektori} pituus on {pituus1:.3f}")
print(f"Vektorin {b_vektori} pituus on {pituus2:.3f}")
laskettu_tulo = a_vektori.pistetulo(b_vektori)
print(f"Vektoreiden pistetulo on {laskettu_tulo:.3f}.")
print("Milla luvulla ensimmainen vektori kerrotaan?")
kerroin = lue_desimaaliluku()
a_vektori.kerro_luvulla(kerroin)
print("Ensimmainen vektori kertomisen jalkeen", a_vektori)
main()
Esimerkki ohjelman suorituksesta:
Anna ensimmaisen vektorin i-kerroin.
4.5
Anna ensimmaisen vektorin j-kerroin.
-2.3
Antamasi vektori on 4.500i - 2.300j
Anna toisen vektorin i-kerroin.
3.3
Anna toisen vektorin j-kerroin.
5.0
Antamasi vektori on 3.300i + 5.000j
Vektorin 4.500i - 2.300j pituus on 5.054
Vektorin 3.300i + 5.000j pituus on 5.991
Vektoreiden pistetulo on 3.350.
Milla luvulla ensimmainen vektori kerrotaan?
-5.0
Ensimmainen vektori kertomisen jalkeen -22.500i + 11.500j
Luokan metodien sisällä voidaan kutsua saman luokan metodeita myös
käsiteltävälle oliolle self
. Esimerkiksi luokkaan Tasovektori
voitaisiin kirjoittaa metodi onko_pitempi
, joka tutkii, onko
käsiteltävä vektori pitempi kuin parametrina saatu vektori. Vektoreiden
pituuksien laskemisessa voidaan käyttää hyväksi luokassa jo määriteltyä
metodia laske_pituus
:
def onko_pitempi(self, toinen_vektori):
if self.laske_pituus() > toinen_vektori.laske_pituus():
return True
else:
return False
laske_pituus
-metodin kutsu laskee parametrina annetun
Tasovektori
-olion pituuden.Toki pituudet voitaisiin laskea suoraankin vektoreiden kenttien
arvoista käyttämättä lainkaan laske_pituus
-metodia.
Metodia onko_pitempi
voitaisiin käyttää lisämäällä aikaisemmin esitettyyn
pääohjelmaan esimerkiksi seuraavat rivit:
if a_vektori.onko_pitempi(b_vektori):
print("Ensimmainen vektori on pitempi.")
else:
print("Ensimmainen vektori ei ole pitempi kuin toinen.")
laske_pituus
-metodin kutsu laskee käsiteltävänTasovektori
-olion pituuden (sen, joka on annettu metodiaonko_pitempi
kutsuttaessa ennen pistettä).