Ohjelmoinnin peruskurssi Y2, kurssimateriaali

5.1. Ohjelman suorituksen tarkastelua

«  5. Kierros 5 (DL 6.4.2015 klo 23:59)   ::   Etusivulle   ::   5.2. Rinnakkainen suoritus  »

5.1. Ohjelman suorituksen tarkastelua

Tutkaillaan ohjelman suoritusta ja tutustutaan kahteen Pythonin työkaluun. Moduli trace näyttää muun muassa ohjelman suorittamat lauseet (ks. The Python Standard Library: 27.6. trace — Trace or track Python statement execution). Moduli pdb puolestaan on Pythonin interaktiivinen debuggeri eli virheenjäljitin (ks. The Python Standard Library: 27.3. pdb — The Python Debugger).

Ohjelman sekventiaalinen suoritus

Kuten tähän mennessä on jo varmaan tullut selväksi, ohjelman suoritus tapahtuu lause kerrallaan edeten ohjelmatekstissä ylhäältä alaspäin. Ehtolauseissa ohitetaan epätosia vaihtoehtoja vastaava koodi, toistolauseissa hypätään takaisin lauseen alkuun aina kun toistoehto on voimassa ja metodikutsuissa hypätään kutsuttavaan koodiin. Tätä kutsutaan sekventiaaliseksi suorittamiseksi. Ohjelman suoritus muodostaa sekvenssin lauseita tai käskyjä. Perehdytään kahteen työkaluun, joilla voi tutkia ohjelman suoritusta. Käytetään seuraavaa esimerkkifunktiota (iteratiivinen_kertoma.py.), joka laskee annetun luvun kertoman iteratiivisesti.

def kertoma(n):
    tulos = 1
    while n > 0:
        tulos = n*tulos
        n -= 1
    return tulos

kertoma(4)

Pythonin kirjaston moduli trace sisältää jäljittimen, jolla saamme näkyviin kaikki suoritetut lauseet.

> python3 -m trace -t iteratiivinen_kertoma.py
 --- modulename: iteratiivinen_kertoma, funcname: <module>
iteratiivinen_kertoma.py(1): def kertoma(n):
iteratiivinen_kertoma.py(8): kertoma(4)
 --- modulename: iteratiivinen_kertoma, funcname: kertoma
iteratiivinen_kertoma.py(2):     tulos = 1
iteratiivinen_kertoma.py(3):     while n > 0:
iteratiivinen_kertoma.py(4):         tulos = n*tulos
iteratiivinen_kertoma.py(5):         n -= 1
iteratiivinen_kertoma.py(3):     while n > 0:
iteratiivinen_kertoma.py(4):         tulos = n*tulos
iteratiivinen_kertoma.py(5):         n -= 1
iteratiivinen_kertoma.py(3):     while n > 0:
iteratiivinen_kertoma.py(4):         tulos = n*tulos
iteratiivinen_kertoma.py(5):         n -= 1
iteratiivinen_kertoma.py(3):     while n > 0:
iteratiivinen_kertoma.py(4):         tulos = n*tulos
iteratiivinen_kertoma.py(5):         n -= 1
iteratiivinen_kertoma.py(3):     while n > 0:
iteratiivinen_kertoma.py(6):     return tulos
 --- modulename: trace, funcname: _unsettrace
trace.py(80):         sys.settrace(None)

Voimme tarkastella suoritusta myös Pythonin pdb-debuggerilla. Tätä varten ladataan moduli pdb sekä omasta modulistamme funktio kertoma. Käynnistetään debuggeri komennolla pdb.run('kertoma(4)'), jonka jälkeen voimme askeltaa suoritusta komennolla s (eli step) ja asettaa debuggerin tulostamaan muuttujan arovn aina kun se muuttuu (esim. display tulos).

> python3
Python 3.4.2 (default, Jan  7 2015, 11:54:58)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb
>>> from iteratiivinen_kertoma import kertoma
>>> pdb.run('kertoma(4)')
> <string>(1)<module>()
(Pdb) s
--Call--
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(1)kertoma()
-> def kertoma(n):
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(2)kertoma()
-> tulos = 1
(Pdb) display n
display n
display n: 4
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(3)kertoma()
-> while n > 0:
(Pdb) display tulos
display tulos
display tulos: 1
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(4)kertoma()
-> tulos = n*tulos
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(5)kertoma()
-> n -= 1
display tulos: 4  [old: 1]
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(3)kertoma()
-> while n > 0:
display n: 3  [old: 4]
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(4)kertoma()
-> tulos = n*tulos
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(5)kertoma()
-> n -= 1
display tulos: 12  [old: 4]
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(3)kertoma()
-> while n > 0:
display n: 2  [old: 3]
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(4)kertoma()
-> tulos = n*tulos
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(5)kertoma()
-> n -= 1
display tulos: 24  [old: 12]
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(3)kertoma()
-> while n > 0:
display n: 1  [old: 2]
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(4)kertoma()
-> tulos = n*tulos
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(5)kertoma()
-> n -= 1
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(3)kertoma()
-> while n > 0:
display n: 0  [old: 1]
(Pdb) s
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(6)kertoma()
-> return tulos
(Pdb) s
--Return--
> /Users/enu/y2/y2-course-material/k05/iteratiivinen_kertoma.py(6)kertoma()->24
-> return tulos

Debuggerin tarjoamiin komentoihin kannattaa perehtyä, sillä debuggerilla on usein helpointa selvittää, miksi ohjelma toimii väärin.

Kutsupino

Jotta Python-tulkki voisi suorittaa ohjelmaa, tarvitsee se joitain aputietorakenteita. Yksi näistä on kutsupino (engl. call stack) eli suorituspino, johon talletetaan jokaista funktio/metodikutsua kohti yksi pinokehys (engl. stack frame) eli *aktivaatiotietue (engl. activation record). Pinokehys sisältää tiedon kutsuttavasta funktiosta sekä sen parametreista ja lokaaleista muuttujista (eli siis nimiavaruuden).

Tämänkaltaista kutsupinoa käytetään kaikissa käyttöjärjestelmissä ohjelmien suorittamiseen. Tarkemmin aiheeseen voi tutustua esim. Wikipedian artikkelissa Call stack.

Tutustutaan kutsupinoon käyttäen esimerkkinä kertoman rekursiivisesti laskevaa ohjelmaa rekursiivinen_kertoma.py. Ohjelmaan on lisätty apufunktio show_stack(), joka näyttää pinon sisällön, kun kertoma-funktio saavuttaa sisimmän rekursiotason.

Palaute

«  5. Kierros 5 (DL 6.4.2015 klo 23:59)   ::   Etusivulle   ::   5.2. Rinnakkainen suoritus  »