Osa 9

Metodien näkyvyys

Luokassa olevien metodien näkyvyyteen voidaan vaikuttaa samalla tavalla kuin attribuuttien näkyvyyteen. Jos metodin nimi alkaa kahdella alaviivalla __, metodi ei ole näkyvissä asiakkaille.

Käytännössä mekanismia käytetään hiukan eri tavalla: piilotettujen attribuuttien käyttöä varten kirjoitetaan usein julkiset havainnointi- ja asetusmetodit. Piilotettu metodi on kuitenkin yleensä tarkoitettu vain luokan sisäiseen käyttöön, apumetodiksi asiakkaalta piilotettujen operaatioiden toteuttamiseksi.

Piilotettua metodia voidaan kutsua luokan sisällä normaalisti, mutta kutsuttaessa pitää muistaa self-aluke. Tarkastellaan esimerkkinä sähköpostin vastaanottajaa mallintavaa luokkaa Vastaanottaja, jossa yksityistä apumetodia käytetään tarkistamaan sähköpostiosoitteen oikeellisuus:

class Vastaanottaja:
    def __init__(self, nimi: str, sposti: str):
        self.__nimi = nimi
        if self.__tarkasta_sposti(sposti):
            self.__sposti = sposti
        else:
            raise ValueError("Sähköposti ei kelpaa")

    def __tarkasta_sposti(self, sposti: str):
        # Yksinkertainen tarkastus: osoitteessa on yli 5 merkkiä ja piste ja @-merkki
        return len(sposti) > 5 and "." in sposti and "@" in sposti

Jos asiakas yrittää kutsua metodia, seuraa virhe:

pertti = Vastaanottaja("Pertti Keinonen", "pertti@example.com")
pertti.__tarkasta_sposti("jokumuu@example.com")
Esimerkkitulostus

AttributeError: 'Vastaanottaja' object has no attribute '__tarkasta_sposti'

Samaa apumetodia kannattaa kutsua myös sähköpostia asettaessa - lisätään siis luokkaan esimerkin vuoksi havainnointi- ja asetusmetodit sähköpostille:

class Vastaanottaja:
    def __init__(self, nimi: str, sposti: str):
        self.__nimi = nimi
        if self.__tarkasta_sposti(sposti):
            self.__sposti = sposti
        else:
            raise ValueError("Sähköposti ei kelpaa")

    def __tarkasta_sposti(self, sposti: str):
        # Yksinkertainen tarkastus: osoitteessa on yli 5 merkkiä ja piste ja @-merkki
        return len(sposti) > 5 and "." in sposti and "@" in sposti

    @property
    def sposti(self):
        return self.__sposti

    @sposti.setter
    def sposti(self, sposti: str):
        if self.__tarkasta_sposti(sposti):
            self.__sposti = sposti
        else:
            raise ValueError("Sähköposti ei kelpaa")

Tarkastellaan sitten toista esimerkkiä. Luokka Korttipakka mallintaa nimensä mukaisesti 52 kortin korttipakkaa. Apumetodi __alusta_pakka luo uuden sekoitetun pakan oliota luotaessa. Vastaava alustus voitaisiin toki tehdä myös metodissa __init__, mutta erillisen apumetodin käyttö tekee koodista siistimpää ja mahdollistaa alustusmetodin kutsumisen myös muualta luokasta tarvittaessa.

from random import shuffle

class Korttipakka:
    def __init__(self):
        self.__alusta_pakka()

    def __alusta_pakka(self):
        self.__pakka = []
        # Laitetaan kaikki kortit pakkaan
        maat = ["pata", "hertta", "risti", "ruutu"]
        for maa in maat:
            for numero in range(1, 14):
                self.__pakka.append((maa, numero))
        # Sekoitetaan pakka
        shuffle(self.__pakka)

    def jaa(self, korttien_maara: int):
        kasi = []
        # Siirretään pakasta ylimmät kortit käteen
        for i in range(korttien_maara):
            kasi.append(self.__pakka.pop())
        return kasi

Seuraava koodi testaa luokkaa:

korttipakka = Korttipakka()
kasi1 = korttipakka.jaa(5)
print(kasi1)
kasi2 = korttipakka.jaa(5)
print(kasi2)

Ohjelma tulostaa esimerkiksi

Esimerkkitulostus

[('pata', 7), ('pata', 11), ('hertta', 7), ('ruutu', 3), ('pata', 4)] [('risti', 8), ('pata', 12), ('ruutu', 13), ('risti', 11), ('pata', 10)]

Piilotettuja metodeja tarvitaan yleensä harvemmin kuin piilotettuja attribuutteja. Metodi kannattaa piilottaa, jos asiakas ei tarvitse siihen suoraa pääsyä, ja varsinkin silloin, jos on todennäköistä, että asiakas voisi sotkea olion sisäisen eheyden metodia kutsumalla.

Loading
Seuraava osa: