Koodi, jossa on kaksi luokkaa. Ei ole niin monimutkainen kuin miltä näyttää.

class Rect:
    def __init__(self, width, height):
        self.width, self.height = width, height # voi tehdä samalla rivillä

    def draw(self, char):
        for i in range(self.height):
            print (self.width * char)

class Triangle:
    def __init__(self, side):
        self.side = side
        
    def draw(self, char):
        width = self.side
        for i in range(self.side):
            width -= 1
            indentation = self.side - width # indentation on kolmion kavennus
            print (indentation * ' ' + width * char * 2)

Kutsuminen

muokkaa

1. suoraan

Rect(20, 10).draw('O')
Triangle(10).draw('X')

2. olion, ilmentymän (engl. instance) avulla

sq = Rect(20, 10)
sq.draw('O')
tr = Triangle(10)
tr.draw('X')

Tulostaa: Neliön ja sen perään kolmion.

OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOO
 XXXXXXXXXXXXXXXXXX
  XXXXXXXXXXXXXXXX
   XXXXXXXXXXXXXX
    XXXXXXXXXXXX
     XXXXXXXXXX
      XXXXXXXX
       XXXXXX
        XXXX
         XX

Ohjeteksti

muokkaa

Luokalle, samoin kuin funktioille ja moduuleille, voi kirjoittaa ohjetekstin yksittäisenä merkkijonona välittömästi luokan sisälle.

class Rect:
    """Luokka neliöiden tulostamiseen.

    Parametrit:
      width: neliön leveys
      height: neliön korkeus
    """

    def __init__(self, width, height):
        self.width, self.height = width, height

    def draw(self, char):
        """Piirtää neliön annetulla merkillä.

        Parametrit:
          char: merkki, jolla neliö tulostetaan
        """
        for i in range(self.height):
            print (self.width * char)

Ohjetekstiin pääsee käsiksi help-komennolla komentotulkistaa, pydoc-työkalulla ja luokan jäsenestä __doc__. Tässä oletetaan, että koodi tallennettiin tiedostoon nimeltä shapes.py.

>>> help(shapes.Rect)

Tulostaa

Help on class Rect in module shapes:

class Rect(builtins.object)
 |  Rect(width, height)
 |  
 |  Luokka neliöiden tulostamiseen.
 |  
 |  Parametrit:
 |    width: neliön leveys
 |    height: neliön korkeus
 |  
 |  Methods defined here:
 |  
 |  __init__(self, width, height)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  draw(self, char)
 |      Piirtää neliön annetulla merkillä.
 |      
 |      Parametrit:
 |        char: merkki, jolla neliö tulostetaan
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

Ohjetekstien muotoiluun on monia erilaisia käytäntöjä.

Luokan periyttäminen toisesta luokasta

muokkaa

Olemassa olevaa luokkaa voi laajentaa tai muuttaa periyttämällä siitä uuden luokan. Peritty luokka kirjoitetaan sulkuihin luokan nimen perään. Perivä luokka sisältää kaikki samat metodit kuin kantaluokkakin, mutta voi sisältää uusia metodeja tai muuttaa olemassa olevia.

class Shape:
    def __init__(self, width, height):
        self.width = width
        self.height = height

class Rect(Shape):
    def __init__(self, width, height):
        pass

Kantaluokan metodeja voi tarvittaessa kutsua perivän luokan sisällä super-funktion avulla.

class Rect(Shape):
    def __init__(self, width, height):
        super().__init__(width, height)

Jäsenmuuttujat

muokkaa

Jokaisella luokan instanssilla voi olla omia muuttujiaan. Niihin, samoin kuin instanssin metodeihin, viitataan olion sisällä self-avainsanalla.

class Rect():
    def __init__(self, width, height):
        self.width = width
        self.height = height

Olion ulkopuolelta niihin viitataan muodossa olio.jäsen.

>>> s = Rect(10, 15)
>>> s.height
15

Yksityiset jäsenmuuttujat ja metodit

muokkaa

Yksityinen jäsenmuuttuja on olion jäsen, johon ei voi viitata olion ulkopuolelta. Jäsenmuuttujan voi merkitä yksityiseksi aloittamalla sen nimen kahdella alaviivalla. Tämä on ainoastaan käytäntö eikä se kokonaan estä muuttujan käyttämistä ulkopuolelta. Sen nimi ainoastaan muutetaan toiseksi, ettei siihen pääse käsiksi alkuperäisellä nimellä.

class Rect():
    def __init__(self, width, height):
        self.__area = width * height

Kirjoitussuojatut jäsenmuuttujat, getterit ja setterit

muokkaa

Jäsenmuuttujan voi tehdä kirjoitussuojatuksi tekemällä sille esimerkiksi yksityisen taustamuuttujan ja @property-dekoraattorilla merkityn lukumetodin (getter).

class Rect():
    # ...

    @property
    def area(self):
        return self.height * self.width

Tällaista ominaisuutta (property) käytetään kuten jäsenmuuttujaa.

>>> s = Rect(10, 10)
>>> s.area
100

Kirjoitussuojattuun muuttujaan voi antaa kontrolloidun pääsyn tekemällä muuttujalle kirjoitusmetodin (setter) @x.setter-dekoraattorilla. X tarkoittaa tässä hakumetodin nimeä.

class Rect():
    # ...

    @area.setter
    def area(self, value):
        import math
        self.height = math.sqrt(value)
        self.width = math.sqrt(value)
>>> s.area = 121
>>> s.height
11

Ominaisuudella voi olla lisäksi poistometodi (deleter), joka tehdään samaan tapaan kuin setteri @x.deleter-dekoraattorilla.

Luokkamuuttujat

muokkaa

Luokkamuuttujat määritellään heti luokan sisällä kuten esim. funktioiden sisäiset muttujat. Nämä ovat kaikille luokan instansseille yhteisiä.

class Rect(Shape):
    unit = "cm"

    def __init__(self, width, height):
        pass

Huomaa, että luokkamuuttujat jaetaan luokan instanssien kesken. Jos luokkamuuttuja on muu kuin yksinkertainen arvo, muuttujan muuttaminen näkyy kaikilla luokan instansseilla.

class Esim:
    lst = []

    def __init__(self, name):
        self.name = name
        self.lst.append(name)

a = Esim("a")
b = Esim("b")

print("a:", a.name, a.lst)
print("b:", b.name, b.lst)

Tulostaa

a: a ['a', 'b']
b: b ['a', 'b']

Luokkametodit

muokkaa

Kun metodi ei käytä luokan instanssin jäsenarvoja eikä muuta sitä, mutta liittyy silti lähteisti tyyppiin, voi metodista tehdä luokkametodin. Luokkametodeihin on Pythonissa kaksi dekoraattoria @staticmethod ja @classmethod. Niiden ero on siinä, että @classmethodin ensimmäinen parametri on luokkatyyppi, kun taas @staticmethod on kuin tavallinen funktio.

class Rect(Shape):
    def __init__(self, width, height):
        super().__init__(width, height)

    @staticmethod
    def make(width, height):
        return Rect(width, height)

Staattista metodia kutsutaan luokan nimellä. Tosin sitä voi myös kutsua instanssin kautta.

>>> Rect.make(25, 25)
<__main__.Rect object at 0x7fc13a7b5c40>

Olion esittäminen merkkijonona

muokkaa

Luokasta voi tehdä tulostusystävällisen toteuttamalla sille __repr__- tai __str__-metodit, jotka palauttavat luokan kuvauksen merkkijonona. Esimerkiksi print-funktio käyttää __str__-metodia muuttamaan olion merkkijonoksi, kun sille annetaan jokin olio argumentiksi. Metodi __repr__ on tarkoitettu palauttamaan mahdollisimman tarkka kuvaus olion sisällöstä mielellään Pythonin synaksia jäljittelevässä muodossa, josta vastaavan olion voisi luoda. Jos tämä ei ole mahdollista, tulisi palauttaa kulmasulkeiden väliin tulostettu muu hyödyllinen kuvaus. Metodi __str__ on tarkoitettu tulostamaan olio ihmisystävällisemmässä muodossa. Jos __str__-metodia ei ole toteutettu, käytetään __repr__-metodia.

class Rect():
    # ...

    def __repr__(self):
        return "Rect(width=10, height=5)"

    def __str__(self):
        return "10×5 rectangle"
>>> rect = Rect(3, 4)
>>> print("Muoto:", rect)
Muoto: 10×5 rectangle
>>> str(rect)
'10×5 rectangle'

Aiheesta muualla

muokkaa