16  Hlutbundin forritun

16.1  Um hlutbundna forritun

Mikilvægt hugtak í ýmsum nútímaforritunarmálum er hlutbundin forritun (object oriented programming, OOP). Hlutbundin forritun var fyrst möguleg í Simula 67 (útgáfa af Simula búin til 1967), en mikilvægustu hlutbundnu forritunarmálin nú eru C++, Python, Java og C#. Í hlutbundinni forritun koma m.a. við sögu hugtökin klasi, hlutur, tilvik, eiginleiki, aðferð, smiður og erfðir.

Byggingareiningar í hlutbundinni forritun

Klasi (class) er í raun gagnatag, og hlutir (objects) eru breytur af viðkomandi tagi, eða tilvik (instance) af klasanum. Yfirleitt innihalda klasar bæði eiginleika (properties, attributes), sem eru einskonar breytur sem lýsa hlutnum, og aðferðir (methods), sem eru í raun föll eða undirforrit (dæmi væri aðferð til að breyta eiginleika). Munurinn á eiginleikum og aðferðum annarsvegar og breytum, föllum og undirforritum hinsvegar er að þau fyrrnefndu eru ekki aðgengileg nema í gegnum hlutinn sem þau tilheyra. Klasaaðferðir (class methods) tilheyra klasanum sjálfum en ekki einstökum tilvikum, og sama gildir um klasabreytur (class variables). Ef gildi þeirra breytast sjá allir hlutir breytinguna.

Sérstök tegund af aðferð er smiður (constructor), sem hefur það hlutverk að búa til nýtt tilvik af klasanum. Hægt er að búa til klasa sem erfir (inherits) eiginleika og aðferðir annars klasa og bætir við sínum eigin (klasinn sem erfir er undirklasi (subclass) og hann erfir frá yfirklasa (superclass)). Stundum setur undirklasi skorður (constraints) á eiginleikana sem erfast.

Loks má geta hugtakanna einka- (private), verndaður (protected) og opinber (public). Einkaaðferðir eru hjálparföll til að útfæra klasa og aðeins aðgengilegar í (öðrum) aðferðum hans, verndaðar aðferðir eru einnig aðgengilegar í undirklösum, og opinberar aðferðir eru aðgengilegar öllum sem nota klasann. Hliðstætt gildir um einka-, verndaða, og opinbera eiginleika.

Dæmi með erfðum

Tökum flatarmyndir og teikningar af þeim á skjá sem dæmi. Gerum ráð fyrir að allar flatarmyndir hafi eiginleikana staðsetningu (t.d. hnit miðju), flatarmál og lit og aðferðirnar stroka_út og breyta_stærð. Flatarmynd er grunnklasi, og frá honum erfast klasarnir (sértilvikin) hringur og rétthyrningur. Hringur bætir við eiginleikanum geisla og rétthyrningur bætir við eiginleikum breidd, hæð og stefnu og auk þess aðferð, snúa (það hefur lítinn tilgang að snúa hring). Báðir þessir erfðu klasar gætu endurskilgreint aðferðina breyta_stærð. Síðan mætti láta ferning erfa frá rétthyrningi með skorðunni að breidd sé sama og hæð. Erfðavenslin má túlka sem „er ein gerð af“. Ferningur er ein gerð af rétthyrningi, hringur er ein gerð af flatarmynd og sömuleiðis rétthyrningur. Myndin hér að neðan sýnir svonefnt klasarit af þessum erfðavenslum, ásamt eiginleikum og aðferðum klasanna.

../_images/klasarit.jpg

Mynd 16.1: Klasarit fyrir flatarmyndir

Kostir og gallar

Kostur við hlutbundna forritun er hægt er að vinna staðbundið. Þegar klasi er útfærður (þ.e. þegar eiginleikar hans eru skilgreindir og aðferðir hans búnar til) þá þarf ekki að hafa allt forritið (eða forritakerfið) undir, heldur nægir að horfa á næsta umhverfi: eiginleika og aðferðir klasans sem unnið er með og (ef við á) klasans sem erft er frá. Annað mikilvægt atriði er svonefnd upplýsingahuld (information hiding), sem felst í því að notandi hefur aðeins (vitneskju um og) aðgang að tilteknum eiginleikum og aðferðum klasa, en hvorki að nánari útfærslu þeirra né að öðrum eiginleikum og aðferðum klasans.

Að lokum má nefna að hlutir geta komið í stað uppflettitaflna undir vissum kringumstæðum og táknmálið til að vísa í eiginleika er í mörgum forritunarmálum, t.d. Python, styttra og einfaldara en uppfletting í töflu (hlutur.lykill í stað hlutur["lykill"])

En öll þessi gæði koma ekki alveg ókeypis. Hlutbundin forritakerfi geta oft orðið stærri og flóknari en samsvarandi kerfi forrituð án klasa. Á Wikipediu má lesa meira um hvernig ýmsir fræðimenn hafa fjallað um slíka ókosti. Til dæmis skrifar einn: Þig vantar banana en færð í kaupbæti górillu sem heldur á honum og allan frumskóginn með.

Segja má að mikilvægast við góða hugbúnaðargerð sé að brjóta forritin niður í litlar einingar, og hvort það sé gert með hlutbundinni forritun eða með öðrum hætti sé ekki aðalatriði.

Það er nauðsynlegt að skilja klasa

Að lokum má nefna að mörg tölvukerfi, eru þannig að þau samanstanda af fjölsrúðugu klasasafni, og notendur þeirra þurfa svo ýmist að búa til tilvik af klösunum eða búa til nýja klasa sem erfa frá þeim innbyggðu með einföldum viðbótum. Þetta á við um marga Python-pakka sem fjallað hefur verið um í þessum nótum, m.a. NumPy, Matplotlib og Pandas. Því er gagnlegt að hafa nokkurn skilning á hlutbundinni forritun þótt menn ætli sér ekki að smíða stór og mikil hlutbundin forritakerfi frá grunni.

16.2  Hlutbundin forritun í Python

16.2.1  Skilgreining klasa

Klasaskilgreiningar í Python eiga ýmislegt sameiginlegt með skilgreiningu falla. Þær má setja hvar sem er framan við fyrsta stað þar sem klasinn er notaður. Hefðbundið er að byrja nafn klasa á stórum staf. Hér er sniðmát sem algengt er að nota fyrir klasa sem ekki á sér yfirklasa:

class Klasi:

    klasabreyta = 42   # skilgreiningar klasabreyta
    ...                #

    def __init__(self, stiki,...):        # smiður
        self.eiginleiki1 = stiki          #
        self.eiginleiki2 = gildi          #
        self._verndaðureiginleiki = gildi #
        self.__einkaeiginleiki = gildi    #
        ...                               #
        # engin return skipun             #

    def aðferð(self, stiki...)  # opinber aðferð
        skipanir                # nota má self.eiginleiki til að vísa í eiginleika
        return                  # má sleppa ef aðferð skilar engu

    def _vernduðaðferð(self, stiki...)  # vernduð aðferð, aðeins ætluð til
        ...                             # notkunar í öðrum aðferðum klasans
        ...                             # og undirklasa hans

    def __einkaaðferð(self, stiki...)   # einkaaðferð, aðeins ætluð til
        ...                             # notkunar í klasanum sjálfum

    def __str__(self): # útskriftaraðferð
        skipanir       # ... sem búa til streng str úr self
        return str     # print(hlutur) kallar sjálfkrafa á þessa aðferð

    @classmethod                    # skilgreiningar klasaaðferða
    def klasaaðferð(cls, stiki...)  # (má sleppa)
        skipanir                    #

Klasabreytur eru sameiginlegar með öllum hlutum af klasataginu, gagnstætt eiginleikum sem eru sérstakir fyrir hvern hlut (ef aðferð breytir klasabreytu þá verður breytingin strax sýnileg í öðrum hlutum). Vísað er í klasabreytu með punktrithætti og nafni klasans Klasi.klasabreyta.

Eins og sést er smiður skilgreindur með því að nota sérstakt nafn, __init__. Fyrsti stikinn í smiðnum, self, er hluturinn sem á að smíða. Hann er eiginleikalaus í byrjun, en í lokin á hann að vera fullsmíðaður hlutur sem smiðurinn skilar. Smiðurinn ætti að gefa öllum eiginleikum gildi, annaðhvort einhver föst sjálfgefin eða útfrá stikunum sem hann fær inn.

Venjulegar aðferðir hafa líka self-stika fremst. Hann fær gildi sem er hluturinn sem viðkomandi aðferð tilheyrir. Í skilgreiningu aðferðarinnar er vísað í eiginleika viðkomandi hlutar með forskeyti self., t.d. self.eiginleiki.

einkaeiginleikar og -aðferðir eru eins og segir að framan aðeins aðgengilegir innan klasans. Verndaðar aðferðir og verndaðir eiginleikar, með nöfn sem byrja á einu undirstriki, eru auk þess aðgengileg í undirklösum. Í flestum öðrum forritunarmálum eru slíkir hlutir ósýnilegir annarsstaðar. Það gildir líka um einkahlutina í Python en hinsvegar ekki þá vernduðu; fyrir þá er er treyst á að notandi virði bannið

Annað sérstakt nafn er __str__ sem skilgreinir útskriftaraðferð. Ef henni er sleppt koma bara upplýsingar um að um sé að ræða hlut af taginu Klasi þegar hlutur er prentaður, en ekkert um innihald hans.

Klasaaðferðir hafa fyrsta stika cls, og hann fær sjálfkrafa gildi sem er klasatagið sjálft. Í skilgreiningu klasaaðferðar eru eiginleikar ekki aðgengilegir eðli máls samkvæmt, en vísa má í klasabreytur með forskeyti cls. t.d. cls.klasabreyta. Klasaaðferðir má t.d. nota til að gefa klasabreytum gildi, eins og gert er í dimmer-dæminu í næsta kafla. Annað notkunarsvið er að láta þær skila nýjum sérstökum hlutum af klasataginu með tiltekna eiginleika. Um það má fræðast nánar hér og þar og víðar á netinu (fengið með leit að python classmethod factory).

16.2.2  Notkun klasa

Hlutir eru búnir til með því að kalla á smiðinn, en það er gert með því að nota nafn klasans:

hlutur1 = Klasi(2, 3...)
hlutur2 = Klasi(4, 5...)

Þótt hann hafi enga return-skipun virkar hann þannig að hann skilar nýjum hlut af klasataginu þar sem eiginleikum hafa verið gefin gildi.

Náð er í klasabreytur og eiginleika hlutar með punkt-rithætti og sama gildir um köll á aðferðir og klasaaðferðir:

e1 = hlutur1.eiginleiki1 # e1 fær gildið 2
K = Klasi.klasabreyta    # K fær gildið 42
hlutur2.aðferð(4, 5)     # í aðferð er self = hlutur2
Klasi.klasaaðferð(6...)  # í klasaaðferð er cls = Klasi

Fyrsti stikinn í (klasa)aðferðum er sem sé giltur með því sem er fyrir framan punktinn í kallinu og það eru einum færri viðföng en stikar.

Sýnidæmi: Klasi fyrir starfsmann

Hér er einfalt dæmi um klasa sem sýnir notkun smiðs og útskriftaraðferðar og aðferðar til að breyta eiginleika.

class Starfsmaður:
    def __init__(self, nafn, laun):
        self.nafn = nafn
        self.laun = laun
    def __str__(self):
        str = (f"{self.nafn}\n"
               f"   laun {self.laun:.0f} kr.")
        return str

    def hækka_laun(self, prósentuhækkun):
        self.laun *= 1 + prósentuhækkun/100

stm = Starfsmaður("Jón Jónsson", 500000)
stm.hækka_laun(prósentuhækkun=5)
print(stm)

Forritið prentar út:

Jón Jónsson
   laun 525000 kr.

Æfing: Launatengd gjöld

  1. Prófið klasann í sýnidæminu og búið til nýja starfsmenn. Bætið svo við aðferð sem reiknar og skilar launatengdum gjöldum sem eru 25.9% af launum. Prófið hana.

  2. Bætið nú við eiginleikum símanúmeri og heimilisfangi og látið útskriftaraðferðina skrifa út svona:

    Jón Jónsson
       heimili  Litlugötu 42, Litlabæ
       sími     8884444
       laun     525000 kr.
    
  3. Skrifið fall sem tekur inn lista af starfsmönnum og skilar samanlögðum launum þeirra og launatengdum gjöldum. Prófið.

16.2.3  Dæmi um hlutbundna forritun: Dimmer

Í þessu dæmi verður líkt eftir þráðlausum fjarstýrðum ljósaperum eins og hægt er að kaupa t.d. í IKEA. Ljósaperur eru táknaðar með lituðum hringskífum á svörtum bakgrunni, og hægt er að skipta um lit og auka eða deyfa birtuna.

import matplotlib.pyplot as plt
from colorsys import rgb_to_hls, hls_to_rgb
from matplotlib.colors import to_rgb

class Pera:

    ásar = None
    perustærð = 40

    def __init__(self, x, y, litur):  # x og y eru á bilinu [0, 5]
                                      # litur er litanafn eða (r,g,b)
       self.RGB = to_rgb(litur)    # (r,g,b)
       self.birta = 50             # 50%
       h = Pera.ásar.plot(x, y, 'o', c=litur, ms=Pera.perustærð)
       self._mynd = h[0]           # litaður hringur sem táknar peruna

    def stilla_birtu(self, birta):  # birta í prósentum
       (r,g,b) = self.RGB
       (hue, _, saturation) = rgb_to_hls(r, g, b)
       self.birta = max(0, min(1, birta/100))
       self._mynd.set_color(hls_to_rgb(hue, self.birta, saturation))

    def breyta_lit(self, litur):
       self.RGB = to_rgb(litur)
       self.stilla_birtu(self.birta*100)

    def skila_birtu(self):     # í prósentum
       return self.birta*100

    @classmethod
    def undirbúa(cls, figure):
        ásar = figure.add_axes([0, 0, 1, 1])  # hnitakerfi fyllir upp í mynd
        ásar.axis([0, 5, 0, 5])               # 5x5 hnitakerfi
        ásar.set_facecolor('black')
        ásar.tick_params(length=0)
        ásar.grid()
        cls.ásar = ásar               # gefa klasabreytunni ásar gildi

figure = plt.figure(figsize = (3,3))
Pera.undirbúa(figure)
p1 = Pera(1, 1, 'red')
p2 = Pera(3, 4, 'green')
p3 = Pera(4, 2, 'violet')
p4 = Pera(2, 3, 'yellow')
p1.stilla_birtu(30)
p3.stilla_birtu(90)
p1.breyta_lit('blue')

Byrjað er á að nota Matplotlib til að búa til ferningslaga mynd, kallað er á klasaaðferðina undirbúa sem fyllir upp í myndina með hnitakerfi með svörtum bakgrunni og hnitum frá 0 til 5 bæði í x- og y-stefnu, og loks er klasabreytan ásar frumstillt með því. Hnitakerfið er síðan notað í smiðnum til að teikna í það nýjar perur. Alls eru smíðaðar fjórar perur hver í sínum lit, og síðan er rauða peran deyfð og birtan í þeirri fjólubláu aukin, og loks er lit þeirrar rauðu breytt í bláan. Eftirfarandi mynd birtist:

../_images/perumynd.jpg

Mynd 16.2: Nokkrar „perur“, gul, græn, deyfð blá, og björt fjólublá.

Athugasemd: Frekari skýringar

Það eru tveir verndaðir eiginleikar, _mynd sem er Matplotlib-bendill á viðkomandi hringskífu, og _RGB sem er RGB-þrennd (þar sem rauður, grænn og blár litaþáttur fá hver um sig gildi á bilinu 0–1) og svo er opinber eiginleiki birta sem er tala á bilinu 0 (slökkt) til 100 (hámarksbirta). Smiðurinn teiknar viðeigandi hringskífu og gefur eiginleikunum gildi: _mynd kemur úr plt.plot, _RGB úr stikanum litur, og birta er sett 50%. Loks eru þrjár aðferðir, til að stilla og skila birtu (gefinni í prósentum), og til að breyta lit.

Nokkur hjálparföll koma við sögu, to_rgb sem breytir litanafni í RGB-þrennd, rgb_to_hls sem breytir yfir í HLS-þrennd (hue, lightness, saturation) og hls_to_rgb sem breytir til baka. Birtu peru er stýrt með lightness tilsvarandi HLS-þenndar. Einnig sést hvernig aðferð getur kallað á aðra aðferð: breyta_lit kallar á stilla_birtu.

16.2.4  Lifandi Matplotlib mynd

Hér er svo skemmtilegt tvist á notkun dimmer-klasans þar sem bætt er við sleða (slider) og þar með líkt enn betur eftir raunverulegum dimmer. Til að fá forritið til að virka í JupyterLab og verða lifandi þarf að nota annan bakenda á Matplotlib teikningar en þann venjulega. Hér er miðað við svonefndan widget bakenda sem opnar lifandi (interactive) mynd inni í vinnubókinni, en aðrir bakendar eru m.a. tk og qt sem báðir teikna í sérstakan glugga á skjánum. KJ hefur ekki tekist að fá þetta dæmi til að keyra í Google Colab.

%matplotlib widget

def búa_til_sleða(p):
    from matplotlib.widgets import Slider
    def nota_dimmer(gildi):
        p.stilla_birtu(gildi)
    sleðaásar = plt.axes([0.1, 0.08, 0.8, 0.04], xticks=[], yticks=[])
    sleði = Slider(sleðaásar, '', valmin=0, valmax=100, valinit=50)
    sleði.on_changed(nota_dimmer)
    return sleði

f = plt.figure(figsize = (3,3))
Pera.undirbúa(f)
p = Pera(2.5, 3, 'red')
sleði = búa_til_sleða(p)
../_images/pera-með-sleða.jpg

Mynd 16.3: Pera með sleða.

Æfing: Líkt eftir dimmer

  1. Keyrið forritin í þessum kafla

  2. Prófið aðra liti, sbr. litatöflu á Wikipedíu

  3. Prófið bakendana qt og tk (það þarf að núllstilla JupyterLab með Restart Kernel ef skipt er um bakenda)

16.3  Erfðir í Python

Sniðmát fyrir Python klasa sem erfist frá öðrum klasa er svona:

class undirklasi(yfirklasi):
    def __init__(self, x, y...):  # smiður
        super().__init__(x)       # kall á smið yfirklasa
        nýr_eiginleiki = y        #

    def endurskilgreind_aðferð(...):
        ...

    def ný_aðferð(...):
        ...

Grunnreglan er sú að allir eiginleikar og aðferðir klasa erfast til undirklasa, en undirklasinn getur svo bæði endurskilgreint aðferðir og bætt við nýjum.

Hugtak nátengt erfðum er afstrakt klasi eða hugrænn (abstract class). Það er klasi sem ekki er hægt að smíða tilvik af en aðrir klasar geta erft. Slíkur klasi inniheldur þá eiginleika sem eru sameiginlegir með öllum erfingjum. Aðferðir hans geta svo ýmist verið afstrakt (þær verður að endurskilgreina) eða konkret. Hugmyndin á bak við afstrakt klasa er að búa til sniðmát fyrir undirklasana. Afstrakt aðferðir geta t.d. haft pass sem sína einu skipun, og afstrakt eiginleikum má gefa gildið None.

16.3.1  Útfærsla flatarmyndaklasa

Sýnidæmin sem hér fylgja eru Python útfærslur á flatarmyndaklösunum sem kynntir voru í kafla 16.1. Byrjað er á að skilgreina afstrakt klasann Flatarmynd sem allar flatarmyndir erfa frá.

Sýnidæmi: Flatarmynd

from numpy import sin, cos, radians, pi
import matplotlib.pyplot as plt, numpy as np

class Flatarmynd:

    ásar = None

    def __init__(self, staðsetning, litur):
        self.staðsetning = staðsetning
        self.litur = litur
        self._polygon = None
        self._teikna()

    def breyta_stærð(self, margf):
        # Margfalda allar stærðir með margf
        pass

    @property
    def flatarmál(self):
        pass

    def stroka_út(self):
        # Aðeins stroka út í konkret klösum
        if self._polygon:
            self._polygon.remove()

    def _teikna(self):
        self.stroka_út()
        (X, Y) = self._útlínur()
        p = self.ásar.fill(X, Y, self.litur)  # teikna
        self._polygon = p[0]  # af tagi Matplotlib Polygon

    def _útlínur(self):
        pass

    @classmethod
    def undirbúa(cls, figure):
        ásar = figure.add_axes([0,0,1,1])
        ásar.axis([0, 10, 0, 10])
        cls.ásar = ásar  # klasabreyta fær gildi

Klasinn hefur eiginleikana sem sýndir eru í klasaritinu á mynd 16.1, staðsetning, flatarmál og litur, og auk þess verndaða eiginleikann _polygon sem er Matplotlib bendill á útlínur myndarinnar. Verndaða aðferðin _teikna býr til sjálfa teikninguna, og í seinni sýnidæmunum kemur í ljós að hana þarf ekki að endurskilgreina í undirklösunum, heldur er hægt að nýta hana óbreytta. Það sama gildir um stroka_út. Hins vegar þurfa undirklasarnir að útfæra báðar afstrakt aðferðirnar breyta_stærð og _útlínur (sú seinni er vernduð). Flatarmálið sýnir hvernig hægt er að skilgreina leseiginleika, sem er ekki hægt að breyta beint, og það þarf auðvitað líka að útfæra í öllum undirklösunum (vefsíða sem útskýrir leseiginleika nánar). Klasaskilgreiningin endar svo á klasaaðferðinni undirbúa sem er lík samsvarandi aðferð í kafla 16.2.3.

Hringur er undirklasi af Flatarmynd sem bætir við eiginleikanum geisli og skilgreinir auk þess konkret útfærslur á breyta_stærð, flatarmál og _útlínur.

Sýnidæmi: Hringur

Takið eftir að smiðurinn endar á að kalla á yfirsmiðinn öfugt við sniðmátið fremst í kafla 16.3. Þess þarf því að yfirsmiðurinn kallar á _teikna sem kallar á _útlínur sem gerir ráð fyrir að eiginleikinn geisli sé kominn.

class Hringur(Flatarmynd):
    def __init__(self, staðsetning, litur, geisli):
        self.geisli = geisli
        super().__init__(staðsetning, litur)

    def breyta_stærð(self, margfaldari):
        self.geisli *= margfaldari
        self._teikna()

    @property
    def flatarmál(self):
        return self.geisli**2 * pi

    def _útlínur(self):
        a = np.linspace(0, 2*np.pi, 360)
        r = self.geisli
        (x,y) = self.staðsetning
        X = x + r*np.cos(a)
        Y = y + r*np.sin(a)
        return (X,Y)

Rétthyrningur er líka undirklasi flatarmyndar. Hann bætir við breidd og hæð og útfærir sömu konkret aðferðirnar og Hringur.

Sýnidæmi: Rétthyrningur

class Rétthyrningur(Flatarmynd):
    def __init__(self, staðsetning, litur, breidd, hæð):
        self.breidd = breidd
        self.hæð = hæð
        self.stefna = 0
        super().__init__(staðsetning, litur)

    @property
    def flatarmál(self):
        return self.breidd * self.hæð

    def breyta_stærð(self, margfaldari):
        self.breidd *= margfaldari
        self.hæð *= margfaldari
        self._teikna()

    def snúa(self, gráður):
        # Rangsælis
        self.stefna += gráður
        self._teikna()

    def _útlínur(self):
        (x, y) = self.staðsetning
        (b, h) = (self.breidd, self.hæð)
        s = np.radians(self.stefna)
        snúningsfylki = np.array([[cos(s),-sin(s)], [sin(s),cos(s)]])
        XY = snúningsfylki @ [[-b, b, b, -b, -b], [-h, -h, h, h, -h]]/2
        return (x + XY[0], y + XY[1])

Svo má skilgreina ferning sem undirklasa rétthyrnings. Hann sýnir enn betur hvernig eiginleikar og aðferðir erfast frá yfirklösum. Hér er nánast allt endurnýtt og aðeins þarf að búa til nýjan smið, sem auk þess nýtir sér smið yfirklasans til að búa til hlut.

Sýnidæmi: Ferningur

class Ferningur(Rétthyrningur):
    def __init__(self, staðsetning, litur, breidd):
        super().__init__(staðsetning, litur, breidd, breidd)

Að lokum er hér sýnidæmi um einfalda notkun á þessum klösum. Þess er gætt að myndin sem búin er til sé ferningslaga svo flatarmyndirnar verði ekki bjagaðar.

Sýnidæmi: Teikning flatarmynda

figure = plt.figure(figsize=(3,3))
Flatarmynd.undirbúa(figure)
R = Rétthyrningur((5,3), 'red', breidd=5, hæð=2)
H = Hringur((3,7), 'blue', geisli=2)
F = Ferningur((8,8), 'green', breidd=2)
R.breyta_stærð(1.3)
R.snúa(30)
print(f'Flatarmál hrings = {H.flatarmál:.3f}')

Forritsbúturinn prentar út:

Flatarmál hrings = 12.566

og birtir eftirfarandi mynd:

../_images/flatarmyndir.jpg

16.3.2  Rétthyrningur sem snýst

Til gamans sýnum við hér að lokum notkun flatarmyndaklasans til að búa til hreyfimynd. Eins og með myndina í kafla 16.2.4 hefur KJ ekki tekist að fá þessa til að birtast í Google Colab, aðeins í JupyterLab, og þá annaðhvort með bakendanum tk eða með qt (widget, sem notað var í kafla 16.2.4 virkar ekki). Auk þess þarf e.t.v. að gefa skipun conda install ipympl áður en keyrt er.

Sýnidæmi: Snúningur

Best er að setja eftirfarandi tvær skipanir í sér glugga sem aðeins þarf að keyra einu sinni.

%matplotlib tk
f = plt.figure(figsize=(4,4))

Hér er svo forrit sem býr til rétthyrning og lætur hann snúast í heilan hring. Það má keyra aftur og aftur.

Flatarmynd.undirbúa(f)
R = Rétthyrningur((5,5), 'red', breidd=8, hæð=1)
for i in range(180):
    plt.pause(0.01)
    R.snúa(2)