9. Listide muteerimine

Pythoni listid on muteeritavad, st sama list võib programmi käivitamise erinevatel hetkedel sisaldada erinevaid väärtusi. Esmapilgul võib olla raske eristada listi muteerimist ja uue, muudetud listi samasse muutujasse salvestamist, aga erinevused on olemas ning nende mitteteadmine võib valusasti hammustada.

Meetod append

Eelmises peatükis vaatasime ühte skeemi listide kasvatamiseks. See seisnes vana listi ja uue info põhjal uue, pikema listi moodustamises:

>>> a = [1,2,3]
>>> a = a + [4,5]
>>> a
[1, 2, 3, 4, 5]
>>> a += [6]
>>> a
[1, 2, 3, 4, 5, 6]

Tuleb välja, et peaaegu sama efekti saamiseks on olemas alternatiivne viis – meetod append:

>>> a = [1,2,3]
>>> a.append(4)
>>> a.append(5)
>>> a.append(6)
>>> a
[1, 2, 3, 4, 5, 6]

Selles näites me peale esialgset omistamist muutuja sisu otseselt ei muutnud, küll aga muutsime listi enda sisu.

Harjutus. Arvude küsimine

Kirjuta eelmises peatükis toodud arvude küsimise näide ümber append-i kasutades.

Järjendi elementide muutmine

Lisaks sellele, et olemasolevale järjendile on võimalik elemente lõppu juurde lisada, saab välja vahetada järjendi mingil positsioonil olevat elementi. Selleks tuleb teha omistamine kasutades järjendi indekseerimise süntaksit. Uuri ja katseta järgnevat programmi:

a = [1, 2, 3]

# muudame teist elementi (s.o element järjekorranumbriga 1)
a[1] = 22

print(a)

Nagu ikka, võib ka siin kasutada indeksina mingit täisarvulist muutujat.

Harjutus. Täringuvisete statistika

Genereeri 100 täringuviske tulemust (kasutades näiteks eelmises peatükis defineeritud funktsiooni juhuslik_järjend) ning salvesta tulemus muutujasse.

Koosta 6-elemendiline järjend statistika, mis sisaldab täringuvisete statistikat – avaldis statistika[0] peaks näitama, mitu korda tuli täringuviske tulemuseks 1, statistika[1] peaks näitama kahtede sagedust jne.

Kuva statistika ekraanile.

Vihje

Kusagil programmis võiks olla lause statistika = [0, 0, 0, 0, 0, 0]

Vihje

Näidislahendus:

from random import randint

def juhuslik_järjend(n, alates, kuni):
    arvud = []

    for i in range(n):
        arvud.append(randint(alates, kuni))

    return arvud

statistika = [0, 0, 0, 0, 0, 0]
visked = juhuslik_järjend(100, 1, 6)

for vise in visked:
    # visked on arvud 1..6
    # listi statistika indeksid on 0..5
    indeks = vise-1
    statistika[indeks] += 1

print(statistika)

Veel järjendimeetodeid

Lisaks append-ile on listidel veel meetodeid mis ei tagasta midagi, vaid muudavad listi sisu. Järgnev tabel näitab, kuidas mõjuvad erinevad meetodid listile [3,1,2,3,1,4], mis on salvestatud muutujasse a.

Meetodi rakendamine Tagastusväärtus Listi uus sisu Kommentaarid
a.append(7) None [3,1,2,3,1,4,7] lisab elemendi listi lõppu
a.extend([7,8]) None [3,1,2,3,1,4,7,8] lisab listitäie elemente listi lõppu
a.insert(0,34) None [34,3,1,2,3,1,4] lisab näidatud positsioonile näidatud elemendi, järgnevate elementide positsioonid nihkuvad
a.insert(1,34) None [3,34,1,2,3,1,4]
a.remove(1) None [3,2,3,1,4] eemaldab esimese näidatud väärtusega elemendi
a.pop() 4 [3,1,2,3,1] eemaldab viimase elemendi ja tagastab selle
a.pop(0) 3 [1,2,3,1,4] eemaldab näidatud indeksiga elemendi ja tagastab selle
a.clear() None [] eemaldab listist kõik elemendid
a.sort() None [1,1,2,3,3,4] sorteerib
a.reverse() None [4,1,3,2,1,3] pöörab elementide järjekorra ümber

Nagu näha, tagastab enamik neist meetoditest selle veidra väärtuse None, mis tähendab sisuliselt väärtuse puudumist. Teisti öeldes, neid meetodeid käivitatakse vaid kõrvalefekti pärast. Antud juhul on kõrvalefektiks listi muteerimine.

Muudetavate andmetüüpide omapärad

Järjendi muutmisel või täiendamisel (nii append-i kui a[i] = x puhul) tuleb arvestada ühe omapäraga, mis tuleb ilmsiks siis, kui sama järjend on omistatud mitmele muutujale. Uuri järgnevat näidet ning ennusta, mis antakse selle programmi käivitamisel väljundiks:

a = [1, 2, 3]

b = a
b.append(4)

print(a)

Nagu nägid, ilmus ekraanile [1, 2, 3, 4], ehkki programmist ei paista, et kusagil oleks järjendisse a lisatud arv 4. Selle omapära põhjus peitub real b = a, mis mitte ei kopeeri muutuja a väärtust muutujasse b, vaid hoopis paneb muutuja b viitama samale järjendile. Teisisõnu, b on sama järjendi alternatiivne nimi (ingl alias). Seetõttu, kui järjendit muuta kasutades nime b, on muudatus näha ka nime a kaudu (ja vastupidi).

Kuna funktsiooni parameetrid on oma olemuselt samuti muutujad, siis sama efekt ilmneb ka siis, kui parameetrina antud järjendit muudetakse funktsiooni sees:

def lisa(järjend, väärtus):
    järjend.append(väärtus)

arvud = [1, 2, 3]
lisa(arvud, 4)

print(arvud)

Seda omapära võib vahepeal ka enda kasuks kasutada. Kui aga soovid parameetrina saadud järjendit arvutuse käigus muuta nii, et funktsioonist väljaspool muutusi näha poleks, siis tuleks teha saadud järjendist koopia ning muudatused teha vaid koopiale. Koopia tegemiseks saab kasutada viilutamise süntaksit, jättes kirjutamata nii vasaku kui parema indeksi:

a = [1, 2, 3]

b = a[:] # a-st tehakse koopia
b.append(4)

print(a) # a väärtus on endine

Märkus

Eelmises peatükis sai põgusalt mainitud, et listide puhul pole x = x + [y] päris sama, mis x += [y]. Asi on selles, et kasutades += operatsiooni, Python tegelikult ei tee uut listi, vaid täiendab olemasolevat:

>>> a = [1, 2, 3]
>>> b = a
>>> b += [4]
>>> a
[1, 2, 3, 4]
>>> b
[1, 2, 3, 4]

Samas x = x + [y] puhul tehakse alati uus list:

>>> a = [1, 2, 3]
>>> b = a
>>> b = b + [4]
>>> a
[1, 2, 3]
>>> b
[1, 2, 3, 4]

Viitamisest täpsemalt

Kas selline situatsioon, et erinevad muutujad viitavad samale objektile, on võimalik ainult listide korral? Tehniliselt võttes ei – muutujad ja harilik (=-ga) omistamine toimivad alati samamoodi hoolimata andmetüübist.

Kõik Pythoni väärtused on programmi käimise ajal esitatud mingite objektidena, mis asuvad kusagil arvuti mälus. Kui käivitatakse lause x = 7, siis luuakse mälus objekt, mis tähistab arvu 7 ja muutujasse x salvestatakse tegelikult ainult viide sellele objektile. Kui me järgmisena käivitame lause y = x, siis muutujasse y salvestatakse sama viit, mis on muutujas x, aga uut täisarvu objekti ei looda. Seega nüüd viitavad muutujad x ja y samale objektile.

Erinevus listidest tuleneb aga sellest, et täisarvu objekti ei ole võimalik muuta, seetõttu ei ole ilma pingutamata võimalik isegi aru saada, kas need muutujad viitavad samale objektile, või erinevatele objektidele, mis tähistavad sama arvu. Seetõttu ei pidanud me ei arvude ega sõnede puhul viitamise teema peale mõtlema.

Viitamise teema täpsemal uurimisel on abiks funktsioon id, mis tagastab argumendiks antud väärtuse (e objekti) aadressi arvuti mälus – see ongi see viide, mida muutujad sisaldavad. Järgnevas näites luuakse kaks samaväärset sõneobjekti, mille kummagi viide salvestatakse erinevasse muutujasse:

>>> a = "tere hommikust!"
>>> b = "tere hommikust!"

Veendume id abil, et muutujad viitavad erinevatele objektidele:

>>> id(a)
48829968
>>> id(b)
48830088

Nüüd kopeerime ühe viida uude muutujasse:

>>> c = a
>>> id(c)
48829968

Nagu näha, kopeeriti omistamisel muutujasse olemasoleva objekti viit ja uut objekti ei loodud.

Kui proovisid seda eksperimenti lühemate sõnedega või väikeste arvudega, siis võis juhtuda, et Python vältis juba esimeste omistamiste juures kahe samaväärse objekti loomist ja omistas b-le sama viite nagu a-le. Arvude ja sõnede puhul on tal see vabadus, sest programmi tähendus sellest ei muutu. Listide korral aga on kindel, et järgmised omistamised tekitavad alati kaks uut objekti:

>>> x = [1,2,3]
>>> y = [1,2,3]
>>> id(x)
47840952
>>> id(y)
48787328

Erinev id-väärtus näitab, et tegemist on erinevate objektidega – kui me ühte neist muteerime (näiteks append-iga), siis teine sellest ei muutu. Kui me aga uue listi loomise asemel kopeerime viida, siis teeme sellega lihtsalt samale objektile uue nime:

>>> z = x
>>> id(z)
47840952
>>> z.append(4)
>>> z
[1, 2, 3, 4]
>>> x
[1, 2, 3, 4]
>>> y
[1, 2, 3]

Tuleb panna tähele, et muutuja muutmine ei ole sama, mis objekti muteerimine. Kui me omistame z-le uue väärtuse, siis z lihtsalt kaotab seose eelmise objektiga – algne objekt sellest ei muutu:

>>> z = [6,7,8]
>>> id(z)
48766568
>>> x            # x poolt viidatud objekt on sama, mis enne
[1, 2, 3, 4]
>>> y
[1, 2, 3]

Kokkuvõttes: omistamisel salvestatakse muutujasse ainult viit paremal pool näidatud väärtusele. Analoogselt toimib Python ka funktsiooni väljakutsel – parameetrisse satub vaid viit argumendile. Päris uusi objekte saab luua literaale kasutades (aga nagu eespool mainitud, võib Python mittemuteeritavate andmetüüpide puhul siin ka objekte jagada) või kasutades mingit operatsiooni, mis teadaolevalt loob uue objekti.

Kopeerimisest

Nagu eespool põgusalt mainitud, saab listi objekte kopeerida viilutamise süntaksiga:

>>> x = [1,2,3]
>>> y = x[:]
>>> id(x)
30988928
>>> id(y)
48829944

Alternatiivina saab kasutada meetodit copy või teisendusfunktsiooni list:

>>> a = [1,2,3]
>>> b = a.copy()
>>> c = list(a)
>>> id(a)
47840952
>>> id(b)
47844488
>>> id(c)
48830024

Kui list sisaldab omakorda liste, siis toimub kopeerimine ainult välimisel tasemel:

>>> a = [1,2,[3,3]]
>>> b = a.copy()
>>> id(a[2])
47839032
>>> id(b[2])
47839032
>>> a[2].append(4)
>>> a
[1, 2, [3, 3, 4]]
>>> b
[1, 2, [3, 3, 4]]

„Sügava“ koopia tegemiseks tuleks kasutada funktsiooni deepcopy moodulist copy:

>>> from copy import deepcopy
>>> a = [1,2,[3,3]]
>>> b = deepcopy(a)
>>> a[2].append(4)
>>> a
[1, 2, [3, 3, 4]]
>>> b
[1, 2, [3, 3]]

Ülesanded

1. Tagasivaade

Loe läbi selle peatüki lõpus olev Tagasivaade peatükkidele 1-9.

2. Palkade analüüs

Antud on tekstifail palgad.txt, kus igal real on töötaja nimi, tema vanus ja kuupalk. Kirjuta programm, mis väljastab antud andmete põhjal:

  • kõige suurema palgaga töötaja nime ja palga suuruse (vihje: suurima palga otsimisel jäta meelde, milliselt positsioonilt sa selle leidsid);
  • keskmise palga;
  • keskmisest palgast rohkem teenijate arvu;
  • keskmised vanused eraldi neile, kes teenivad keskmisest palgast vähem (või samapalju), ning neile, kes teenivad keskmisest palgast rohkem.

3. minu_shuffle

Pythoni random moodulis on funktsioon shuffle, mis ajab argumendiks antud järjendis elementide järjekorra juhuslikult segamini:

>>> from random import shuffle
>>> a = [1, 3, 3, 4, 5, 5, 5, 6, 6]
>>> shuffle(a)
>>> a
[5, 3, 6, 5, 5, 3, 4, 1, 6]

Kirjuta ise analoogne funktsioon minu_shuffle, mis teeb sama (seejuures pole lubatud kasutada olemasolevat shuffle funktsiooni).

Vihje

>>> from random import randint
>>> randint(1,4)
1
>>> randint(1,4)
1
>>> randint(1,4)
3
>>> randint(1,4)
2
>>> randint(1,4)
4
>>> randint(1,4)
2
>>> randint(1,4)
2

Vihje

Üks võimalus on valida iga listi elemendi jaoks juhuslikult uus positsioon …

Vihje

… ja vahetada need kaks elementi omavahel.

4. Eesti filmide statistika (raskem)

Veebisait http://www.imdb.com kogub ja jagab informatsiooni filmide kohta. Aadressilt ftp://ftp.funet.fi/pub/mirrors/ftp.imdb.com/pub/ saab IMDB poolt kogutud infot alla laadida pakitud tekstifailidena.

Fail filmid.zip (4.5MB) on koostatud faili „countries.list.gz“ põhjal ning see sisaldab filmide (ja telesaadete) loetelu koos riigi nime ning valmimise aastaga. Lae see fail alla ning paki lahti.

Märkus

Filmide fail on lahtipakitult ligi 18MB suurune. Kui sul ei õnnestu (Windowsis) seda faili avada Notepadiga, siis kasuta vabavaralist programmi Notepad2 (http://www.flos-freeware.ch/notepad2.html).

Failis filmid.txt on ühe filmi andmed ühel real kujul <nimi><tühik>(<aasta>)<tabulaator><riik>. (Notepad2-s saad tühikuid ja tabulaatoreid eristada, kui märgid menüüs View valiku Show whitespace.)

Ülesanne on kirjutada programm, mis otsib sellest failist üles Eestis valminud filmid/telesaated ning koostab statistika selle kohta, mitu filmi/telesaadet mingil aastal valmis.

Vihje

Fail on kodeeringus UTF-8, st faili avamisel tuleks seda mainida: f = open("filmid.txt", encoding="UTF-8").

Vihje

Tabulaatorit kirjutatakse Pythoni sõneliteraalina nii: '\t'.

Vihje

Võibolla tuleb kasuks uurida ülalpool antud ülesannet „Täringuvisete statistika“.

Vihje

Kui sa loed järjenditesse kogu failis sisalduva info, siis võib Pythonil mälust puudu tulla.

Lisaülesande lisa

Täienda programmi selliselt, et see küsib (korduvalt) kasutajalt aastaarvu ning väljastab ekraanile kõik selle aasta Eesti filmid. Kui kasutaja sisestab tühisõne (st vajutab lihtsalt ENTER-it), siis programm lõpetab töö. Selleks tuleb organiseerida sisseloetud filmid aastate kaupa eraldi.

Vihje

Järjend võib sisaldada järjendeid: a = [[1, 2, 3], [5, 5, 6], [4, 4, 3]]. Mõtle, mida võiks tähendada a[2][1]?

Tagasivaade peatükkidele 1-9

On teada, et mingi teema valdamiseks tuleb tegelda vaheldumisi nii teooria kui ka praktikaga. Praeguseks oled harjutanud läbi kõik olulisemad Python keele võimalused ja nüüd on paras aeg astuda samm tagasi ning vaadata juba läbitud materjalile uue, veidi kogenuma pilguga.

Avaldised vs laused

Kõik eelpool käsitletud Python keele elemendid saame jaotada kahte suurde gruppi: avaldised ja laused.

Avaldised on näiteks 2, 2 + 3, brutopalk ja sin(0.5) ** (x-1) – kõigil neil on väärtus ja neid saab seetõttu kasutada nt muutujate defineerimisel ja teistes keerulisemates avaldistes.

Laused (ingl statements) on näiteks omistamislause (x = sin(0.5)), tingimus- ja korduslaused (if, while ja for) ja funktsioonide definitsioonid (def). Eri tüüpi lausete ühine omadus on see, et nad teevad midagi (nt muudavad muutuja väärtust, defineerivad uue käsu või teevad midagi tingimuslikult või korduvalt).

Nii avaldiste kui ka lausete juures on oluline see, et neid saab panna üksteise sisse. Näiteks operaatori + kasutuse üldskeem on <avaldis1> + <avaldis2>, kusjuures nii avaldis1 kui ka avaldis2 võivad olla samuti mingi tehted. if-lause põhiskeem on:

if <avaldis>:
    <laused1>
else:
    <laused2>

kusjuures nii laused1 kui ka laused2 võivad sisaldada suvalisi lauseid, sh if-lauseid, mille sees võib olla omakorda suvalisi lauseid.

Märkus

Funktsiooni väljakutsed (nt sin(0.5)) on tehniliselt küll alati avaldised, aga mõnesid funktsioone kasutatakse tavaliselt lausetena (nt turtle.forward(100) või print("Tere")). Seega, natuke lihtsustades võiks öelda, et nende funktsioonide väljakutsed, mis midagi arvutavad, on avaldised, ja teiste funktsioonide väljakutsed, mis midagi teevad, on laused.

Muutujad

Muutujad võimaldavad meil tegelda väärtustega ilma et me peaks mainima mingit konkreetset väärtust. Näiteks kui me salvestame kaks kasutaja poolt sisestatud arvu muutujatesse a ja b, siis nende kokku liitmisel ei huvita meid enam, mis on nende muutujate konkreetne väärtus.

Soovitatav on lugeda uuesti läbi 2. peatüki osa Muutujad, tõenäoliselt näed nüüd muutujate olemust juba uue pilguga.

Funktsioonid

Kui muutujad võimaldavad meil kasutada mingit väärtust ilma et me peaksime mõtlema mingile konkreetsele väärtusele, siis funktsioonid võimaldavad meil midagi teha või arvutada ilma et me peaksime alati mõtlema selle peale, kuidas see toiming või arvutus täpselt tehakse. Viska pilk peale järgnevale programmile:

def kolmest_suurim(a, b, c):
    if a > b and a > c:
        return a
    elif b > a and b > c:
        return b
    else:
        return c

print(kolmest_suurim(4, 15, 2))

Tõenäoliselt oskad isegi ilma funktsiooni definitsiooni süvenemata arvata, mida taoline programm ekraanile prindib. Põhjus on selles, et antud funktsiooni olemus tuleb välja juba tema nimest ja üldjuhul võime me eeldada, et funktsiooni tegelik definitsioon on tema nimele vastav. Seetõttu, kui meil on sobivad funktsioonid juba defineeritud, siis saame me programmi põhiosas (või järgmiste funktsioonide defineerimisel) töötada kõrgemal tasemel, ilma pisiasjade pärast muretsemata.

Kuna funktsioonide teema on programmeerimise algkursusel tavaliselt tudengitele kõige hägusam, siis on soovitatav lugeda uuesti läbi 5. peatükist vähemalt järgmised osad.

Tingimuslause

Tingimuslause (ehk if-lause ehk hargnemislause) on oma olemuselt küllalt lihtne – teatud tingimusel tuleb täita ühed laused ja vastasel juhul teised. Lisavõimalusena on Pythonis võimalik kirjutada ka üheharulisi (st ilma else-ta) ning mitmeharulisi (elif-iga) tingimuslauseid.

Üks oluline punkt tingimuslause juures on lause päises antud tingimusavaldis. Nagu eelnevalt mainitud, on avaldiste moodustamiseks lõputult võimalusi – võib kasutada konstante, muutujaid, tehteid, funktsiooni väljakutseid või kõigi nende kombinatsioone. Tingimusavaldise juures on oluline, et avaldise tüüp oleks tõeväärtus, st avaldise väärtustamisel saadakse kas True või False.

Mitme tingimuse kombineerimiseks saab kasutada operaatoreid and ja or, tingimuse ümberpööramiseks on operaator not. Ära unusta, et tingimuses saad kasutada ka isetehtud funktsioone, aga need peavad sel juhul tagastama tõeväärtuse.

Korduslaused e tsüklid

Pythonis on kaks erinevat korduslauset – while-tsükkel, mis on väga paindlik, ning for-tsükkel, mis on lihtsam, aga mis ei sobi kõigil juhtumitel.

for-tsükli juures on oluline mõista, et tema tööpõhimõte on while’ist kaunis erinev. Kui while-tsükli kordused põhinevad mingil tingimusel, siis for-tsükli kordused põhinevad mingil järjendil (või järjendisarnasel asjal, nt failil või vahemikul).

Järjendid

Järjendite abil saame koondada mingi hulga andmeid ühe nime alla.

Järjendid on vajalikud neil juhtudel, kus programmi kirjutades pole võimalik öelda, mitme andmejupiga peab programm töötama (vastasel juhul võiksime iga andmejupi jaoks võtta programmis kasutusele ühe muutuja).

Järjendeid saab programmi sisse kirjutada, koostada teiste järjendite põhjal või lugeda failist. Kui järjendeid on vaja ükshaaval järjest läbi vaadata, siis on selleks kõige mugavam kasutada for-tsüklit, kui on vaja lugeda järjendist mingit konkreetset elementi, siis tuleks kasutada indekseerimist.

Kust saab rohkem infot?

Kes soovib läbitud teemade kohta rohkem detaile või lihtsalt teist vaatenurka, siis soovitame lugeda läbi Pythoni ametliku juhendi: http://docs.python.org/3/tutorial/.

Lisalugemine

Pööratud Poola notatsioon

Tänapäeval oleme harjunud kirjutama matemaatilisi avaldisi nõndanimetatud infiksnotatsioonis, kus tehtemärk on nende kahe arvu vahel, millega ta töötab. See tekitab tegelikult aga igasuguseid probleeme seoses sellega, et vahel on raske öelda, mis järjestuses tehteid tegema peab. Koolis õpetatakse meile, et kõigepealt tuleb teha astendamised, siis korrutamised ja jagamised ning alles siis liitmised ja lahutamised. Kui tehteid tuleb mingis muus järjestuses teha, saab kasutada sulge.

Tegelikult on aga juba ammusest olnud tuntud viise avaldiste kirjutamiseks nii, et sulge pole vaja, kuid kõik tehete tegemise järjestused on ometi kirjeldatavad. Ehk tuntuim neist on nõndanimetatud postfiksnotatsioon ehk pööratud Poola notatsioon (Poola notatsioon on nii nimetatud, sest selle põhiline propageerija oli poola matemaatik Jan Łukasiewicz ja ta pakkus selle välja 1920. aastal; pööratud Poola notatsiooni pakkusid välja F. L. Bauer ja E. W. Dijkstra kuuekümnendatel).

Selles ei kirjutata tehe mitte argumentide vahele, vaid järele. Nii teisendatakse näiteks 2 + 3 avaldiseks 2 3 +. Kui üks neist argumentidest juhtub aga olema juba mõne eelneva tehte tulemus, siis tähistabki vastavat tulemust see tehtemärk. Nii saab näiteks 2 + 3 – 1 teisendada kujule 2 3 + 1 -. See tähendab seda, et kõigepealt tehakse liitmine 2 ja 3 vahel ning seejärel lahutamine selle liitmise tulemuse ja 1 vahel. Selline kirjutamisviis kaotab igasuguse vajaduse sulgude jaoks: (2 + 7) * 3 saab kirjutada ju lihtsalt kui 2 7 + 3 * kusjuures on üheselt selge, et kõigepealt tehakse 2 ja 7 liitmine ning alles siis korrutatakse selle tulemus ja kolm omavahel. Muuseas võib juhtuda, et järjest on ka kaks või kolm või isegi enam tehtemärki. Näiteks teiseneb 3 + 2 * (4 - 1) kujule 3 2 4 1 - * +.

Selle kirjapildi teine tõsine eelis on see, et see muudab aritmeetiliste avaldiste töötlemise arvuti jaoks kõvasti lihtsaks. Tuleb vaid meeles pidada, mis arvud parasjagu loetud on, tehtemärki kohates kaks viimati lisatud arvu välja võtta, neile see tehe rakendada ning siis see tulemus uuesti meeles peetud arvude nimekirja lõppu lisada. Seega on väga lihtne koostada programm, mis antud avaldise tulemuse välja arvutab. Toomegi siinkohal programmi, mis seda teeb:

rida = input("Sisesta avaldis: ")
kasud = rida.split()

# töötle avaldis
loend = []

for kask in kasud :
    # liitmine
    if kask == "+" :
        # asenda viimane element tulemusega
        loend[-1] = loend[-2] + loend[-1]
        # eemalda eelviimane element
        loend.pop(-2)

    # lahutamine
    elif kask == "-" :
        loend[-1] = loend[-2] - loend[-1]
        loend.pop(-2)

    # korrutamine
    elif kask == "*" :
        loend[-1] = loend[-2] * loend[-1]
        loend.pop(-2)

    # jagamine
    elif kask == "/" :
        loend[-1] = loend[-2] / loend[-1]
        loend.pop(-2)
    else :
        # polegi käsk, seega loodetavasti hoopis number
        loend.append(float(kask))

print("Tulemus on: " + str(loend[-1]))

Tegu on ka asjaga, mis on praktikas täiesti kasutust leidnud. Oma töötlemise lihtsuse tõttu ehitati selline arvutamise süsteem sisse mõningatesse võimsamatesse kalkulaatoritesse, mida kunagi müüdi. Viimase 15 aasta jooksul on see aga arvutusvõimsuse kasvu tõttu vaikselt kalkulaatorites asendunud meile loomulikuma koolis õpitud infiksnotatsiooniga.

Kommentaarid