Sisällysluettelo |
Python on ohjelmointikieli. Se on kuin mikä tahansa kieli, jolla voidaan toteuttaa mitä erilaisimpia sovelluksia. Siinä on omat vahvuutensa ja heikkoutensa, kuten millä tahansa ohjelmointikielellä. Se on tarkoitettu tiettyihin ympäristöihin ja tietyille käyttöjärjestelmille, aivan vastaavasti kuin muutkin ohjelmointikielet.
Python on ohjelmointikieli, jonka vahvuuksia hyödyntämällä voidaan toteuttaa uskomattomia toimintakokonaisuuksia (ohjelmia, sovelluksia, skriptejä, ...)!
Pythonissa on paljon samoja piirteitä kuin muissakin kielissä. Siinä voidaan luoda muuttujia, funktioita, olioita ja muita ohjelmoinnissa käytettäviä perusasioita. Voidaan käyttää ohjelmoinnin peruselementtejä eli lauseita ja lausekkeita. Siinä on oma kirjoitusasunsa, kuten millä tahansa muulla kielellä. No... mikä sitten tekee Pythonista erilaisen? Miksi ihmeessä kannattaa käyttää Pythonia?
Vapaus, yhteensopivuus ja saatavuus Python on rakennettu Avoimen lähdekoodin -periaatteella. Näkyvin asia avoimuudesta on yhteensopivuus kymmeniin eri käyttöjärjestelmiin ja ympäristöihin. Pythonin saa esimerkiksi Windows-ympäristöihin, ja on oletuksena valmiina lähes jokaisessa Linuxissa. Python löytyy kännyköistä, sulautetuista laitteista ja useista muista eri ympäristöistä. Pythonin takana on yhteisö, johon kuuluu muun muassa yrityksiä, jotka sponsoroivat kehitystyötä. Yhteisössä on vapaaehtoisia jäseniä, joilla on omat roolinsa. Yhteisössä on kehittäjiä, jotka nimensä mukaisesti kehittävät kielen toimintaa. Lopputuloksena on erittäin universaali ja toimiva ohjelmointikieli, joka on yhteensopiva useiden järjestelmien kanssa, ja johon löytyy valtava määrä dokumentaatiota ja muuta ohjeistusta.
Rajapinta laitteistoon ja ohjelmiin Avoimen lähdekoodin -periaatteen eräs loistavimmista puolista on toki yhteensopivuus eri käyttöjärjestelmiin, mutta tämän lisäksi lukematon määrä eri rajapintoja laitteisiin, laitteiston osiin ja ohjelmiin. Pythonilla voidaan esimerkiksi lähettää sähköposteja, ohjata sarjaportteja, USB-portteja sekä hallita verkkoliikennettä. Tämä tapahtuu erilaisten kirjastojen avulla, joita on tarjolla paljon. Monipuoliset kirjastot ja normaalit ohjelmointirutiinit mahdollistavat mitä erilaisimpia sovelluksia.
Rajapinta käyttöjärjestelmään Linuxin ohjelmavalikoima on käsittämättömän suuri. Saatavilla on esimerkiksi kymmeniä WWW-palvelinohjelmistoja, joilla voidaan tarjota WWW-sisältöä verkkoon. Ohjelmavalikoiman monipuolisuus on johtanut monestikin siihen, ettei enää kannata keksiä pyörää uudestaan, eli lähes jokaiseen käyttötarkoitukseen löytyy jo hyvä ja toimiva ohjelma. Kaikilla Linuxissa olevilla ohjelmilla on yksi yhteinen piirre, komentorivi. Sillä voidaan hallita kaikkia järjestelmän toimintaan liittyviä asioita eli esimerkiksi käynnistää ja sulkea ohjelmia. Pythonin subprocess-kirjasto tarjoaa loistavan rajapinnan esimerkiksi mainittuun Linuxin komentoriviin. Tätä kautta aukeaa mahdollisuudet niin monipuoliseen maailmaan, että sovelluskehityksen rajana on vain mielikuvitus.
Rajapinta Graafisiin ympäristöihin Oman vaatimattoman kokemukseni mukaan, graafisten käyttöliittymien tekeminen esimerkiksi C++-kielellä on haastavaa. Pythoniin löytyy tähänkin tarkoitukseen oma rajapinta, jota käyttäen saadaan luotua todella monipuolisia käyttöliittymän. Liittymien rakentamiseen löytyy valtavasti ohjeita, oppaita, foorumeita ja vaikkapa videopätkiä. Videoista on hyvä esimerkki tässä, jossa itseasiassa kerrotaankin kaikki ne seikat, miksi käyttää Pythonia. Tämä rajapinta täydentää jo valmiiksi loistavaa kokonaisuutta.
Rajapinta verkkoympäristöön OSI-mallissa verkkokerroksen yläpuolella olevilta kerroksilta on tuttuja käsitteitä esimerkiksi portit, TCP ja UDP. Näitä kutsutaan yleisesti ottaen soketeiksi ja niiden hallintaa sokettiohjelmoinnniksi. Python tarjoaa tähänkin tarkoitukseen rajapinnan, jolla voidaan tehdä monipuolisia verkkoympäristöä käyttäviä ohjelmia. Jälleen kerran tähänkin asiaan löytyy valtava määrä ohjeistusta ja neuvoja, joiden avulla pääsee helposti alkuun tässäkin asiassa.
Helppous, hauskuus ja mukavuus Python-ohjelmoinnin aloittaminen on helppoa. Työkaluksi käy pelkkä tekstieditori ja esimerkiksi Linuxilla varustettu tietokone. Ei tarvita erillisiä kääntäjiä, vaan ohjelman käyttäminen voidaan aloittaa helposti esimerkiksi komentoriviltä. Loistava ominaisuus on myös interaktiivisen käytön mahdollisuus, eli komentoriviltä voidaan käynnistää Python-tulkki, johon voidaan antaa komentoja rivi kerrallaan. Näin havainnollistuu ohjelmien todellinen toiminta ja mahdolliset virheet. Pythonilla voidaan toteuttaa nopeasti ja näppärästi vaativaankin käyttöä sopivia ohjelmia. Ohjelmat ovat useaan käyttöjärjestelmään ja ympäristöön sopivia, ja tämä tuo ohjelmointiin aivan uudet mahdollisuudet.
Seuraavissa kappaleissa on esitelty Python-ohjelmoinnin perusteita. Tavoitteena on esitellä perusohjelmien tekemistä, joissa on muuttujia ja erilaisia funktioita. Materiaalin tarkoitus ei ole keskittyä vielä tässä vaiheessa ohjelmoinnin syvimpään olemukseen, vaan esitellä aivan perusasioita.
Seuraavassa vastaan tulevat tehtävät ja esimerkit on toteutettu Debian- ja Ubuntu-järjestelmillä. Suurin osa esimerkeistä pitäisi toimia myös Windows-ympäristöstä, mutta tälle allekirjoittanut ei anna mitään takuita. Jos joku, syystä tai toisesta, haluaa Windows-järjestelmää käyttää, löytyy siihen ohjeistusta esimerkiksi täältä.
Python on skriptipohjainen ohjelmointikieli. Skriptipohjaisuus näkyy esimerkiksi siinä, että toimiva ohjelma ei tarvitse erikseen kääntäjää. Ohjelma voidaan tehdää suoraan tiedostoon, joka suoritetaan ohjelman käynnistämiseksi. Tästä tulee nimi skripti eli suoritettava tiedosto, joka tekee tiettyjä toimenpiteitä. Avataan asiaa esimerkillä. Ensimmäiseksi komennolla cat testiskripti.py on näytetty, että testiskripti.py on aivan normaali tiedosto, jossa on kolme riviä tekstiä. Ensimmäisellä rivillä on kerrottu, että tämä on Python komentotulkin läpi ajettava skripti. Toisella rivillä paljon käytetty kommentti ja kolmannella print-funktio. Koska kysymyksessä on suoritettava tiedosto, täytyy Linux-ympäristössä antaa tiedostolle suoritusoikeus komennolla chmod a+x testiskripti.py. Lopuksi skripti suoritetaan komennolla ./testiskripti.py, ja skripti suorittaa print-funktion, joka tulostaa legendaarisen tulostuksen komentoriville.
ville@ubuntu-home:~$ cat testiskripti.py
#! /usr/bin/env python #Tämä on vain kommentti, jolla voidaan esimerkiksi selittää ohjelman toimintaa. print "Hello world!"
ville@ubuntu-home:~$ chmod a+x testiskripti.py ville@ubuntu-home:~$ ./testiskripti.py Hello world! ville@ubuntu-home:~$
Yllä on esimerkiksi skriptistä ja sen käytöstä. Skriptiä ei siis tarvitse kääntää ohjelmaksi ennen suorittamista, vaan skripti-tiedosto on valmis ohjelma. Skriptin suorittaminen voidaan automatisoida tapahtumaan esimerkiksi koneen käynnistymisen yhteydessä, näppäimen painalluksesta tai vaikkapa ajoittaa tietylle ajanhetkelle. Python-skriptien käyttäminen on Linux-järjestelmässä lähes samanlaista kuin perinteisten Bash-skriptien. Bash on äärettömän monipuolinen, joten luulisi sillä pystyvän tekemään samat asiat kuin Pythonilla. Näin ei kuitenkaan ole, sillä Graafisten käyttöliittymien ohjelmoiminen ja sokettien käyttö on lähes mahdotonta.
Edellä mainostettiin Pythonin interaktiivisuudesta. Tämä tarkoittaa käytännössä seuraavassa esimerkissä esitettyä asiaa. Interaktiivinen tila saadaan käyttöön antamalla komennon python. Tämän jälkeen voidaan antaa täsmälleen samoja komentoja, mitä edellä olleessa skripti-tiedostossa oli. Näin päästään testaamaan sitä, että mitä skripti todellisuudessa tekee. Testaaminen onnistuu loistavasti vaihe vaiheelta, ja samalla voidaan testata myös muita komentoja ja toimintalogiikkoja.
ville@ubuntu-home:~$ python Python 2.5.2 (r252:60911, Jul 31 2008, 17:31:22) [GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> print "Hello world!" Hello world! >>> ville@ubuntu-home:~$
Näillä kahdella tavalla päästään alkuun, eli tuottamaan toimivia ohjelmia ja etenemään vikatilanteen yllättäessä. Ohjelmien toiminnallisuuksien, ja sitä kautta skripti-tiedostojen monimutkaistuessa sekä kasvaessa, kannattaa ottaa käyttöön ohjelmakehitystä helpottavia työkaluja. Linux-ympäristöön tällaisia työkaluja löytyy paljon. Yksinkertaisimmillaan normaali tekstieditori tarjoaa jo huomattavan helpotuksen värittämällä tekstin ja siinä esiintyvät Pythonille tutut sanat. Edistyneempiä työkaluja on esimerkiksi monessa ohjelmointikielessä erittäin suosittu Eclipse, johon on saatavana Python-tuki. Alla olevassa kuvassa esimerkki Gedit-editorista ja auki olevasta skripti-tiedostosta.
Jatkossa olevat esimerkit on tehty käyttäen Gedit-editoria ja siihen saatavilla olevaa Python-liitännäistä. Tämä mahdollistaa auki olevan Python-konsolin editorin alareunaan. Ohjelmien tekeminen on suoraviivaista ja selkeää.
Tämän helpompaa ohjelmoinnin aloittaminen ei voi olla!
Lähes jokaisen ohjelman peruselementtejä ovat muuttujat. Niihin esimerkiksi voidaan tallentaa tietoa, niissä olevaa tietoa voidaan käsitellä ja eri muuttujia voidaan yhdistää. Käytännön esimerkkinä vaikkapa ohjelma, joka hakee lämpömittarin anturilta lukeman ja näyttää sen koneen ruudulla. Lukema ei varmasti ole oletuksena celsiusasteena, joten arvoa pitää muokata sopivalla laskutoimituksella ennen ruudulle tuontia. Lukema pitää tallentaa siis muuttujaan, jolle tarvittava laskutoimitus tehdään.
Pythonissa muuttujien käyttö on suoraviivaisempaa kuin esimerkiksi C-kielessä. Pythonissa ei yleensä tarvitse määritellä muuttujan muotoa, vaan se on lähes aina yksi ja sama. Seuraavassa pieni esimerkki, jossa on tehty muuttuja nimeltään teksti, ja siihen tallennettu tekstia muuttujassa. Toinen muuttuja on nimeltään numero, johon tallennettu numero 1233456789. Lopuksi molempien muuttujien sisältö on tulostettu ruudulle.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> teksti = 'tekstia muuttujassa' >>> numero = 123456789 >>> teksti 'tekstia muuttujassa' >>> numero 123456789 >>>
Muuttujia voidaan muokata monellakin tapaa, ja tästä on pieni esimerkki seuraavassa. Aluksi on muuttuja a, jolle on annettu arvo. Sen jälkeen b, jolle on myös annettu arvo. Muuttujilla ollaan tehty laskutoimitus, joka on tallennettu myös uudeksi muuttujaksi. Muuttujien arvot eivät muutu, ellei niille anneta uutta arvoa.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a = 5 >>> a*3 15 >>> a 5 >>> b = 20 >>> a+b 25 >>> a 5 >>> b 20 >>> c=a+b >>> c 25 >>> a 5 >>> b 20 >>> b = 30 >>> b 30 >>>
Muuttujat varaavat aina muistista tietyn suuruisen palasen. Niin kauan kuin ohjelma on käynnissä, muisti pysyy varattuna, käytettiin muuttujaa tai ei. Useissa ohjelmointikielissä, mukaan lukien Python, on käytössä roskien kerääjä, jonka tarkoituksena on poistaa varaus käyttämättömiltä muuttujilta. Jos kuitenkin halutaan itse hallita muuttujien olemassa oloa, voidaan se tehdä seuraavan esimerkin mukaisesti. Ensiksi on määritelty muuttuja a, jolle on annettu arvoksi numero 5. Pythonissa voidaan muuttujan sisältötyyppiä vaihtaa lennosta, eli a:lle on annettu suoraan sisällöksi tekstiä. Muuttuja on poistettu komennolla del(a), ja poiston jälkeen muuttuja ei enää tunneta. Samannimistä muuttujaa voidaan käyttää poiston jälkeen uudelleen.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a = 5 >>> a 5 >>> a = 'Testi' >>> a 'Testi' >>> del(a) >>> a Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined >>> a = 3 >>> a 3 >>>
Muuttujien käytöstä löytyy erittäin paljon ohjeistusta, minkä vuoksi tässä on kerrottu vain ihan perusperiaatteet. Jatkossa näitä sovelletaan esimerkeissä.
Funktioiden tarkoitus on määritellä toiminto, jota voidaan käyttää toistuvasti ja jatkuvasti ilman uudelleen määrittelyä. Edellisissä kappaleissa käytettiinkin jo muutamia Pythoniin sisäänrakennettuja funktioita, joiden tarkoitus on helpottaa ohjelmoijien työtä, eli ei aina tarvitse keksiä polkupyörää uudestaan. Sisäänrakennetuilla funktioilla saadaan tehtyä paljon erilaisia toimia, mutta monesti käy niin, että ohjelmissa pitää määritellä omia funktioita. Näiden määrittelystä on seuraavassa esimerkki, jossa on määritelty funktio a(). a tulostaa siinä määritellyn muuttuja sisällön aina, kun sitä kutsutaan. Kutsu tapahtuu komennolla a().
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> def a(): ... muuttuja = 'Muuttuja funktiosta' ... print(muuttuja) ... >>> a() Muuttuja funktiosta >>>
Seuraavaksi on määritelty funktio, johon kutsumisen yhteydessä viedään ensimmäiseksi kaksi lukua ja toisessa tapauksessa kaksi merkkijonoa. Funktio laskee annetut arvot yhteen ja palauttaa tuloksen.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> def lasku(ensimmainen,toinen): ... return ensimmainen+toinen ... >>> lasku(1,2) 3 >>> lasku(11,4) 15 >>> lasku('jat','kuu') 'jatkuu' >>>
Seuraavaksi esimerkissä on käytetty edellistä funktiota toisen funktion sisällä. Funktio lasku on globaalifunktio, jota luotu uusifunktio kutsuu.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> def lasku(ensimmainen,toinen): ... return ensimmainen+toinen ... >>> lasku(1,2) 3 >>> lasku(11,4) 15 >>> lasku('jat','kuu') 'jatkuu' >>> def uusifunktio(a,b,c,d): ... return lasku(a,b)*lasku(c,d) ... >>> uusifunktio(2,2,5,5) 40 >>>
Viimeisessä esimerkissä on esitelty vastaava toiminnallisuus kuin edellä. Poikkeuksena on se, että nyt lasku-funktio on vain määritelty uusifunktion sisälle. Lasku ei tässä tapauksessa ole globaalifunktio. Tällä saavutetaan sekä etua että haittaa, sillä funktio on kuin muuttuja, joka vie muistiavaruudesta aina tilaa, eli kuluttaa muistia. Jos globaalia funktiota tarvitaan harvoin, muistia kulutetaan turhaan. Toisaalta, jos funktiota tarvitaan usein, kuluu turhaa aikaa sisäfunktion luomiseen.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> def uusifunktio(a,b,c,d): ... def lasku(ensimmainen,toinen): ... return ensimmainen+toinen ... return lasku(a,b)*lasku(c,d) ... >>> uusifunktio(2,2,5,5) 40 >>> lasku(1,2) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'lasku' is not defined >>>
Erilaisia funktioita ja niiden sekoituksia käytetään paljon. Ne ovat ohjelmoinnin arkipäivää!
Reaalimaailmassa joudutaan tekemään jatkuvasti erilaisia päätöksiä. Päätökset voivat olla isoja tai pieniä, mutta yhtä kaikki, päätökset perustuvat jonkinlaiseen tietoon ja arvailuun siitä, että mihin päätös johtaa. Tässä asiassa tietokone on äärimmäisen huono, sillä koneelta puuttuu logiikka, joka meillä ihmisillä on äärimmäisen toimiva ja nopea. Ihmisen logiikka on todella moniulotteinen, sillä se pystyy yhdistämään monia eri asioita, ja johtamaan asioista järkeviä päätöksiä. Logiikan puutteellisuuden vuoksi, koneiden ohjelmissa pitää määritellä joka ainoa asia, jonka halutaan johtavan johonkin järkevään lopputulokseen. Monesti käy niin, että kaikkia mahdollisuuksia ei ole otettu huomioon, jolloin ohjelman toiminta on järjetöntä ja epävakaata.
Ohjelmoinnissa päätöksen tekoa ohjataan muuttujilla, lauseilla ja lausekkeilla. Eräs yleisimmistä on if-lause, jonka toimintaa on esitetty seuraavassa esimerkissä. Aluksi on luotu funktio, jota kutsutaan komennolla ehtolause(luku,luku). Jos kutsun yhteydessä annettujen lukujen summa on alle kymmenen, tulee ilmoitus Summa on alle kymmenen. Jos lukujen summa on yli kymmenen, tulee ilmoitus Summa on yli kymmenen.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> def ehtolause(a,b): ... if a+b < 10: ... print 'Summa on alle kymmenen' ... else: ... print 'Summa on yli kymmenen' ... >>> ehtolause(3,6) Summa on alle kymmenen >>> ehtolause(5,6) Summa on yli kymmenen >>>
Homma toimii hienosti, kun funktion kutsussa annetaan luvut, jotka voidaan laskea yhteen. Heti, kun funktiota kutsutaan jollain muulla kuin luvuilla, toiminnassa ei ole mitään järkeä.
>>> ehtolause('teksti',2) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in ehtolause TypeError: cannot concatenate 'str' and 'int' objects >>> ehtolause('teksti','teksti2') Summa on yli kymmenen >>>
Tästä päästäänkin siihen, että tarvitaan uusi ehto, funktio tai muuttuja, jolla toimintaa järkeistetään. Ohjelma kasvaa ja monimutkaistuu, jolloin myös lisävirheiden määrä kasvaa.
Lähes tulkoon kaikki tietotekniikassa perustuu silmukkoihin eli toimintoon, joka tehdään toistuvasti. Lähtien käyttöjärjestelmän prosessorin toiminnasta tai yksittäisestä sovelluksesta, kaikki perustuu jonkinasteiseen silmukkaan. Pythonilla toteutetuissaa ohjelmissa käytetään paljon for- ja while-silmukoita. Näiden käyttöä on valaistu seuraavilla esimerkeillä. Ensimmäiseksi ollaan ensiksi luotu muuttuja silmukkamuuttuja, joka on tyypiltään listamuuttuja. Sen jälkeen on luotu funktio, joka kertoo kutsussa annetun luvulla kahdella ja palauttaa sen. FOR-silmukalla ollaan kutsuttu funktiota lasku kymmenen kertaa, ja kutsun yhteydessä funktiolle ollaan viety silmukassa käytetty indeksimuuttuja i. Silmukka tulostaa print-funktiolla vastauksen jokaisen kierroksen yhteydessä.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> silmukkamuuttuja = range(10) >>> silmukkamuuttuja [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> def lasku(luku): ... return luku*2 ... >>> for i in silmukkamuuttuja: ... print lasku(i) ... 0 2 4 6 8 10 12 14 16 18 >>> silmukkamuuttuja [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>>
Seuraavaksi on lisätty silmukkaan ehto, joka tulostaa vastauksen ainoastaan silloin kun vastaus on yli kymmenen. Esimerkin tarkoituksena on vain näyttää, että silmukan sisälle voidaan laittaa ehtoja, jotka johtavat tiettyihin operaatioihin.
>>> def silmukka(): ... for i in indeksimuuttuja: ... a = lasku(i) ... if a > 10: print(a) ... >>> silmukka() 12 14 16 18 >>>
Toinen vaihtoehto silmukkaan on while, jonka toimintaa on esitelty seuraavassa esimerkissä. while-silmukan suurin ero on siinä, että se voi pahimmillaan pyöriä määräämättömän ajan. Silmukan toiminta sidotaan aina johonkin lausekkeeeseen, ja jos vastauksena TRUE, suoritetaan silmukka. Seuraavassa on ensiksi luotu muuttuja a, jolle on annettu arvoksi 10. Sitten on määritelty while-silmukka, ja suoritusehdoksi asetettu, että muuttujan a pitää olla nolla tai suurempi. Jokaisen suorituksen yhteydessä tulostetaan muuttuja a, ja tulostuksen jälkeen sitä pienennetään yhdellä. Viimeisenä esimerkissä on suoritettu funktio lasku jokaisen pyörähdyksen yhteydessä.
>>> a = 10 >>> while a >= 0: ... print a ... a -= 1 ... 10 9 8 7 6 5 4 3 2 1 0 >>> a -1 >>> a = 10 >>> while a >= 0: ... print lasku(a) ... a -= 1 ... 20 18 16 14 12 10 8 6 4 2 0 >>>
Silmukoiden käytöstä löytyy paljon esimerkkejä. Lähes jokaisessa esimerkiksi silmukoiden käyttöön yhdistyy erilaisia perusvertailuja ja ehtolauseita.
Erilaiset ehtolauseet ja silmukat, yhdistettyinä muuttujiin, ovat läsnä jokaisessa ohjelmassa!
Edellä käytettiin erilaisia Pythoniin sisäänrakennettuja elementtejä, kuten if ja while. Kaikki käytetyt komennot ja funktiot kuuluvat, johonkin moduliin, joka ladataan oletuksena Pythonin käynnistyessä. Seuraavassa esimerkissä on annettu komento dir(), jolla nähdään ladatut modulit. Huomataan, että käynnistyksen yhteydessä on ladattu muun muassa __builtins__-moduli. Seuraavalla komennolla dir(__builtins__) on tarkistettu, että mitä kyseinen moduli pitää sisällään. Tulostuksesta huomataan, että sieltä muun muassa komento print, jota olemme useaan otteeseen jo käyttäneet.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> dir() ['__builtins__', '__doc__', '__name__', '__package__'] >>> dir(__builtins__) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'] >>>
Ladatut modulit mahdollistavat käytettävät komennot ja funktiot. On luonnollista, ettei oletuksena ladata kaikkia mahdollisia moduleja, vaan ainoastaan peruskäyttöön tarvittavat. Jos halutaan laajentaa käyttömahdollisuuksia, pitää ladata tarkoitukseen sopiva moduli, jossa tarvittavat komennot on esitelty. Hyvänä esimerkkinä vaikka serial-moduli, joka mahdollistaa sarjaportin normaalin käytön eli esimerkiksi ohjaamisen. Seuraavassa esimerkki modulin lataamisesta.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> dir() ['__builtins__', '__doc__', '__name__', '__package__'] >>> sys.platform Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'sys' is not defined >>> import sys >>> dir() ['__builtins__', '__doc__', '__name__', '__package__', 'sys'] >>> sys.platform 'linux2' >>>
Dir-komento on kätevä myös modulin tarjoamia komentoja selvittäessä. Seuraavassa halutaan toiminnallisuus, jossa ohjelma odottaa halutun ajan. Tähän tarvitaan Time-moduli ja sieltä funktio sleep. Asiaa selviä joko Pythonin dokumentaatiosta tai alla esitetyllä tavalla.
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import time >>> dir() ['__builtins__', '__doc__', '__name__', '__package__', 'time'] >>> dir(time) ['__doc__', '__name__', '__package__', 'accept2dyear', 'altzone', 'asctime', 'clock', 'ctime', 'daylight', 'gmtime', 'localtime', 'mktime', 'sleep', 'strftime', 'strptime', 'struct_time', 'time', 'timezone', 'tzname', 'tzset'] >>> dir(time.sleep) ['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] >>> time.sleep(5) >>>
Moduleita voidaan tehdä myös itse, mutta tähän ei yleensä ole tarvetta. Python tarjoaa luonnostaan jo niin paljon erilaisia toimintoja erilaisten modulien kautta, jolloin tee-se-itse -työ ei ole välttämättä järkevää.
Modulien kautta Pythonin käyttöä saadaan laajennettua! Komennot, funktiot ja modulit kulkevat aina käsi kädessä!
Edellisissä kappaleissa jo mainittiinkin, että Pythonissa on paljon valmiiksi määriteltyjä muuttujia ja funktioita. Materiaalissa on tutustuttu myös siihen, miten esimerkiksi määritellään omia funktioita. Näiden lisäksi on käytössä luokat, joilla saadaan luotua vielä monipuolisempia asioita kuin def-määritteellä. Luokalla voidaan määritellä toiminta, jossa yhdistyy esimerkiksi muuttujia ja funktioita. Tätä luokkaa voidaan monistaa, ja silti jokaista käsitellään kuin yksittäistä. Alla on asiasta esimerkki, jossa on ensimmäiseksi määritelty luokka nimeltä Varasto. Alussa luonnollisesti Varaston Saldo on 0. Varastossa on kolme funktiota, joilla lisätään ja poistetaan tavaraa sekä tarkistetaan tilanne. Määrittelyn jälkeen on tehty Peruna- ja Porkkanavarasto, joiden tilannetta on muutettu käytössä olevilla funktioilla.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> class Varasto: ... def __init__(self): ... self.Saldo = 0 ... def tilanne(self): ... print self.Saldo ... def lisaa(self, lisays): ... self.Saldo += lisays ... def vahenna(self, vahennys): ... if self.Saldo >= vahennys : self.Saldo -= vahennys ... else : print 'Varastossa ei ole tarpeeksi' ... >>> Peruna = Varasto() >>> Porkkana = Varasto() >>> Peruna.tilanne() 0 >>> Porkkana.tilanne() 0 >>> Peruna.lisaa(90) >>> Peruna.tilanne() 90 >>> Porkkana.tilanne() 0 >>> Porkkana.lisaa(50) >>> Peruna.vahenna(40) >>> Peruna.tilanne() 50 >>> Porkkana.vahenna(55) Varastossa ei ole tarpeeksi >>> Porkkana.tilanne() 50 >>>
Luokat lisäävät ohjelmointiin tehokkuutta ja parantavat ohjelmien toiminnallisuutta!
Tässä kappaleessa lähtökohtana on se, että on olemassa verkko ja siellä laitteita, joissa on Linux-käyttöjärjestelmät. Jokaisella laitteella on IPv6-osoite. Tarkoituksena on, että laitteet kommunikoivat toistensa kanssa. Kommunikoinnin yhteydessä välitetyistä viesteistä laitteet tekevät päätöksiä. Tällaisia esimerkkejä löytyy todella paljon, sillä esimerkiksi liikennevalojen ohjaus, liikenteen ohjaus, teollisuus- ja kotiautomaatio, toimivat juuri näin. Esimerkkien laitteet muodostavat verkon, jossa laitteilla on muun muassa prosessorit ja käyttöjärjestelmät. Muodostuneissa verkoissa laitteet kommunikoivat toistensa kanssa käyttäen soketteja.
Sokettiohjelmoinnin tarkoitus on mahdollistaa juuri nämä edellä mainitut toiminnallisuudet. Sokettiohjelmoinnilla täydennetään OSI-mallissa olevan verkkokerroksen yläpuolinen alue sellaiseksi, että käyttäjän, joka voi olla esimerkiksi laite tai ihminen, lähettämät viestit menevät perille ja johtavat tiettyihin toimenpiteisiin. Esimerkkinä vaikkapa sähköpostijärjestelmä, jossa ihminen lähettää sähköpostin ensimmäiselle postipalvelimelle, tämä postipalvelimen välittää sen seuraavalle, ja lopulta se on vastaanottajan luettavissa.
Sokettiohjelmoinnin lähtökohtana on aina toimiva verkko, jossa laitteilla on IP-osoitteet. IP-osoitteet on yhdistetty DNS-järjestelmän kanssa sellaiseksi, että käyttäjät voivat IP-osoitteiden sijaan käyttää FQDN-nimiä. Seuraavassa esimerkissä on havainnollistettu tätä asiaa.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> socket.getaddrinfo('www.syo.fi', None) [(2, 1, 6, '', ('213.250.107.183', 0)), (2, 2, 17, '', ('213.250.107.183', 0)), (2, 3, 0, '', ('213.250.107.183', 0))] >>> socket.getaddrinfo('213.250.107.183', None) [(2, 1, 6, '', ('213.250.107.183', 0)), (2, 2, 17, '', ('213.250.107.183', 0)), (2, 3, 0, '', ('213.250.107.183', 0))] >>> socket.gethostbyname('www.syo.fi') '213.250.107.183' >>> socket.getfqdn('www.syo.fi') 'uusiwww.kauhava.fi' >>> socket.gethostbyaddr('213.250.107.183') ('uusiwww.kauhava.fi', [], ['213.250.107.183']) >>> socket.getservbyname('smtp') 25 >>> socket.getservbyport(25) 'smtp' >>>>
Edellä tehtiin erilaisia kyselyjä, joilla havainnollistettiin IP-osoitteiden ja Nimien välistä yhteyttä. Näiden lisäksi tietyille palveluille on varattu tietyt protokollat ja portit. Kuljetuskerroksella käytetään yleisesti kahta eri protokollaa, ja ne tunnetaan nimillä TCP ja UDP. Kuljetuskerroksen yläpuolelle on rakennettu valtava määrä erilaisia protokollia, joista ehkä tunnetuimpia ovat HTTP ja SMTP. Näille protokollille on yhteistä se, että jokainen niistä varaa itselleen portin väliltä 0 - 49151. Tällaiset varatut portit tunnetaan nimillä Well Known Ports ja Registered Ports.
Seuraavissa esimerkeissä Verkkokerroksen osoitteistus on toteutettu IPv6-tekniikalla. Tämä näkyy niin osoitteiden muodossa (fc00:1::1) kuin myös sokettien käytössä (socket.AF_INET6). Esimerkit toimivat vastaavasti myös perinteisellä IPv4-tekniikalla, jolloin edelliset kohdat täytyy muuttaa.
TCP kuljetuskerroksen protokolla, jonka tehtävänä on välittää lähettävän laitteen liikenne kohdelaitteelle. TCP:n vahvuus ei ole suorituskyky, vaan luotettavuus. TCP varmistaa, että lähettävän laitteen viesti menee varmasti kohdelaitteelle perille. Tämä tapahtuu erilaisin kuittausviestein, ja nämä viesti heikentävät suorituskykyä. Seuraavassa on tehty esimerkkiohjelmat, joista ensimmäinen on yksinkertainen viestin lähettävä ohjelma (client) ja toinen vastaanottava (server). Testauksessa kannattaa käyttää Pythonia interaktiivisessa tilassa, ja samalla monitoroida koneen portteja sekä liikennettä. Näin testauksesta saa erittäin paljon kehittävää tietoa ohjelmien toiminnasta.
#! /usr/bin/env python # Basic TCP Client #Sokettiohjelmoinnin tarvitsema moduli import socket #Kohdeosoite ja -portti HOST = 'fc00:1::1' PORT = 50000 ADDR = (HOST, PORT) #Lähetettävä viesti MESSAGE = 'c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eeb30fee0661ee8f798c221fb630794c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eef798c221fb630794' #Luodaan soketti, otetaan yhteys, lähetetään viesti, ja viimeisenä suljetaan soketti client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) client.connect(ADDR) client.send(MESSAGE) client.close() #Suljetaan ohjelma exit()
#! /usr/bin/env python # Basic TCP Server #Tarvittava moduli import socket #Kuunneltava osoite ja portti HOST = '' PORT = 50000 ADDR = (HOST, PORT) #Vastaanotossa käytettävä puskuri MAXBUFFER = 1024 #Viestin vastaanottoon käytettävä muuuttuja MESSAGE = '' #Luodaan soketti, yhdistetään ohjelmaan ja asetetaan kuuntelevaan tilaan server = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) server.bind(ADDR) server.listen(1) #Jäädään kuuntelemaan yhteyksiä connection, addr = server.accept() #Silmukka, joka huolehtii vastaanottopuskurin tyhjentämisestä. Sisältö siirretään STRING-muuttujaan. while 1: DATA = connection.recv(MAXBUFFER) MESSAGE += DATA if len(DATA) < MAXBUFFER: break #Tulostetaan vastaanotettu viesti.. viestinhän voisi tallentaa vaikka tiedostoon. print MESSAGE #Suljetaan yhteys, soketti ja ohjelma connection.close() server.close() exit()
Alla esimerkki Clientin ja Serverin toiminnasta.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> HOST = 'fc00:1::1' >>> PORT = 50000 >>> ADDR = (HOST, PORT) >>> MESSAGE = 'c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eeb30fee0661ee8f798c221fb630794c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eef798c221fb630794' >>> client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) >>> client.connect(ADDR) >>> client.send(MESSAGE) 145 >>> client.close() >>> exit() ville@ville-ibm:~$
basic:~# python Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26) [GCC 4.3.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> HOST = '' >>> PORT = 50000 >>> ADDR = (HOST, PORT) >>> MAXBUFFER = 1024 >>> MESSAGE = '' >>> server = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) >>> server.bind(ADDR) >>> server.listen(1) >>> connection, addr = server.accept() >>> while 1: ... DATA = connection.recv(MAXBUFFER) ... MESSAGE += DATA ... if len(DATA) < MAXBUFFER: break ... >>> print MESSAGE c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eeb30fee0661ee8f798c221fb630794c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eef798c221fb630794 >>> connection.close() >>> server.close() >>> exit() basic:~#
UDP on yhteydetön, ja näin erittäin tehokas, kuljetusprotokolla. Yhteydettömyyden vuoksi ohjelmointi on yksinkertaisempaa kuin edellä. Seuraavassa asiasta esimerkki, jossa on toteutettu vastaavat asiakas-palvelin -ohjelmat kun TCP:n kanssa.
#! /usr/bin/env python # Basic UDP Client #Ladataan moduli import socket HOST = 'fc00:1::1' PORT = 50000 ADDR = (HOST,PORT) MESSAGE = 'c2bcf6251df886e582a2052dfc2886e582a625f8cfef98c221fb630794c2bcf6f8cfef9e6cccee8f798c221fb630794c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eeb30fee0661' #Luodaan soketti, lähetetään viesti ja suljetaan soketti sekä ohjelma client = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) client.sendto(MESSAGE, ADDR) client.close() exit()
#! /usr/bin/env python # Basic UDP Server #Ladataan moduli import socket HOST = '' PORT = 50000 ADDR = (HOST, PORT) server = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) server.bind(ADDR) MAXBUFFER = 1024 MESSAGE = server.recv(MAXBUFFER) print MESSAGE server.close() exit()
Alla on esimerkki Clientin toiminnasta, ja sen jälkeen Serverin.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> HOST = 'fc00:1::1' >>> PORT = 50000 >>> ADDR = (HOST,PORT) >>> MESSAGE = 'c2bcf6251df886e582a2052dfc2886e582a625f8cfef98c221fb630794c2bcf6f8cfef9e6cccee8f798c221fb630794c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eeb30fee0661' >>> client = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) >>> client.sendto(MESSAGE, ADDR) 155 >>> client.close() >>> exit() ville@ville-ibm:~$
basic:~# python Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26) [GCC 4.3.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> HOST = '' >>> PORT = 50000 >>> ADDR = (HOST, PORT) >>> server = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) >>> server.bind(ADDR) >>> MAXBUFFER = 1024 >>> MESSAGE = server.recv(MAXBUFFER) >>> print MESSAGE c2bcf6251df886e582a2052dfc2886e582a625f8cfef98c221fb630794c2bcf6f8cfef9e6cccee8f798c221fb630794c2bcf6251df886e582a2052df606e625f8cfef9e6ccc58c0eeb30fee0661 >>> server.close() >>> exit() basic:~#
Multicast on kätevä tapa lähettää viestejä tietyille laitteille. Multicast on osoite, johon laitteet voivat liittyä. Tuohon osoitteeseen lähetetyt viestit jaetaan kaikille ryhmässä oleville. Viestintätapa on tehokas, eikä aiheuta keskeytyksiä laitteen toimintaan, kuten esimerkiksi Broadcast. Seuraavassa on esimerkki, jossa on toteutettu viestin lähettävä Client ja vastaanottava Server.
#! /usr/bin/env python # Basic Multicast Client #Tarvittava moduli import socket #Kohdeosoite ja -portti HOST = 'ff02::10' PORT = 10000 ADDR = (HOST,PORT) #Luodaan soketti ja lähetetään viesti client = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) client.sendto('c2bcf6251df886e582a2052dfc2bcf6251df886e582a2052df606e625f8cfef9e6ccc630794c2bcf6251df886e58f8cfef9e6ccc58c0eeb30fee0661ee8f798c2a2052df606e625jlkjdeeb30fee0661', ADDR) #Suljetaan soketti ja ohjelma client.close() exit()
#! /usr/bin/env python # Basic Multicast Server import socket MADDR = 'ff02::10' HOST = '' PORT = 10000 ADDR = (HOST, PORT) GROUP = socket.inet_pton(socket.AF_INET6, MADDR)+'\0'*4 #Luodaan soketti ja liitetään Multicast-ryhmään server = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) server.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, GROUP) server.bind(ADDR) #Vastaanotetaan viesti MAXBUFFER = 1024 MESSAGE = server.recv(MAXBUFFER) print MESSAGE server.close() exit()
Alla esimerkki yksinkertaisen UDP-viestin lähettämisestä. Ensimmäisenä on Client ja toisena Server.
ville@ville-ibm:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> HOST = 'ff02::10' >>> PORT = 10000 >>> ADDR = (HOST,PORT) >>> client = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) >>> client.sendto('c2bcf6251df886e582a2052dfc2bcf6251df886e582a2052df606e625f8cfef9e6ccc630794c2bcf6251df886e58f8cfef9e6ccc58c0eeb30fee0661ee8f798c2a2052df606e625jlkjdeeb30fee0661', ADDR) 160 >>> client.close() >>> exit() ville@ville-ibm:~$
basic:~# python Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26) [GCC 4.3.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import socket >>> MADDR = 'ff02::10' >>> HOST = '' >>> PORT = 10000 >>> ADDR = (HOST, PORT) >>> GROUP = socket.inet_pton(socket.AF_INET6, MADDR)+'\0'*4 >>> server = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) >>> server.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, GROUP) >>> server.bind(ADDR) >>> MAXBUFFER = 1024 >>> MESSAGE = server.recv(MAXBUFFER) >>> print MESSAGE c2bcf6251df886e582a2052dfc2bcf6251df886e582a2052df606e625f8cfef9e6ccc630794c2bcf6251df886e58f8cfef9e6ccc58c0eeb30fee0661ee8f798c2a2052df606e625jlkjdeeb30fee0661 >>> server.close() >>> exit() basic:~#
Soketit ja niiden käyttäminen ovat nykyisissä ohjelmissa arkipäivää! Harva ohjelmoija tekee nykyään pelkästään paikallisessa koneessa toimivia pasiansseja!
Python tarjoaa kaksi vaihtoehtoista rajapintaa graafisten käyttöliittymien toteuttamiseen. Ensimmäisessä kappaleessa mainittiin PyGTK, joka käyttää GTK-kirjastoa. Tämä kirjasto löytyy esimerkiksi vakiona Linux-järjestelmistä, joihin on asennettu Gnome järjestelmän hallintaliittymäksi. Tällainen Linux on esimerkiksi Ubuntu.
Toinen vaihtoehto on PyQT, joka nimensä mukaisesti käyttää QT-kirjastoa. Tällainen kirjasto löytyy vakiona esimerkiksi Linuxista, jossa on KDE järjestelmän hallintaliittymänä. QT:n vahvuus on monien, erilaisten toimijoiden tuki. QT:lle löytyy paljon erilaisia ohjelmointia helpottavia työkaluja, mutta tässä kappaleessa keskitytään perusasioihin, jolloin kyseisten työkalujen käyttö ei ole tarpeellista.
Seuraavassa on keskitytty PyGTK-rajapintaan, jonka käytöstä on esitetty muutama esimerkki. Ensimmäisessä on toteutettu yksinkertainen, yhdellä painikkeella varustettu ikkuna. Esimerkin skriptillä lopputulos näyttää alla olevan kuvan mukaiselta.
Tässä ohjelman skripti
#!/usr/bin/env python import gtk # Tätä funktiota kutsutaan aina nappia painettaessa: def click_handler(widget): paaikkuna.destroy() gtk.main_quit() # Luodaan pääikkuna: paaikkuna = gtk.Window() # Järjestetään tulevat palikat pystysuuntaan: pystylaatikko = gtk.VBox() paaikkuna.add(pystylaatikko) # Tehdään nappula: nappula = gtk.Button("Paina tästä!") # Määritellään, että mitä funktiota kutsutaan nappia painettaessa: nappula.connect("clicked", click_handler) # Lisätään nappula laatikkoon ja laitetaan näkyviin: pystylaatikko.pack_start(nappula) nappula.show() # Ikkuna suljetaan yläkulmasta olevast X-napista: paaikkuna.connect("destroy", gtk.main_quit) # Laitetaan palikat ja ikkuna näkyviin pystylaatikko.show() paaikkuna.show() # Laitetaan ohjelma silmukkaan, joka keskeytetään gtk.main_quit-funktiolla gtk.main() # Lopetetaan skriptin suorittaminen exit(0)
Komentoriviltä suoritus näyttää seuraavalta
ville@ubuntu-home:~$ python Python 2.5.2 (r252:60911, Jul 31 2008, 17:31:22) [GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import gtk >>> >>> def click_handler(widget): ... paaikkuna.destroy() ... gtk.main_quit() ... >>> paaikkuna = gtk.Window() >>> pystylaatikko = gtk.VBox() >>> paaikkuna.add(pystylaatikko) >>> nappula = gtk.Button("Paina tästä!") >>> nappula.connect("clicked", click_handler) 6L >>> pystylaatikko.pack_start(nappula) >>> nappula.show() >>> paaikkuna.connect("destroy", gtk.main_quit) 10L >>> pystylaatikko.show() >>> paaikkuna.show() >>> gtk.main() >>> exit(0) ville@ubuntu-home:~$
Toisessa esimerkissä ollaan lisätty ikkunaan painikkeita ja muita elementtejä. Elementtejä on sekoitettu ja ohjelmaan on lisätty funktioita. Ohjelman skriptistä huomaa, että toiminnallisuuksien lisääntyessä skriptin pituus kasvaa. Tästä syystä monimutkaisten ja vaativien käyttöliittymien tekeminen vaatii ohjelmoinnin vankkaa osaamista ja parempia työkaluja, joita on saatavilla paljon. Tällaisia ovat esimerkiksi Glade, Eclipse ja QT Designer. Osaamisen kehittämisessä Python on yksi parhaimmista edellä mainittujen syiden vuoksi. Jos Pythonin tarjoamat toiminnallisuudet eivät riitä, tarjoaa sen parissa tapahtuva opiskelu loistavat lähtökohdat muihin suosittuihin kieliin.
Ohjelman skripti rivi riviltä
#!/usr/bin/env python # -*- coding: utf-8 -*- import pygtk import gtk import time # Pääikkunan sulkeva funktio def sulje_paaikkuna(widget): paaikkuna.destroy() gtk.main_quit() # Teksti-ikkunan puskurin päivittävä funktio. Lukee tiedoston /var/log/dmesg sisällön ja siirtää sen puskuriin. def paivita_puskuri(): tiedosto = open("/var/log/dmesg", "r") if tiedosto: sisalto = tiedosto.read() tiedosto.close() tekstipuskuri.set_text(sisalto) # Teksti-ikkunan sisällön päivittävä funktio. Siirtää automaattisesti sivussa olevan vierityspalkin loppuun. def paivita_sisalto(widget): paivita_puskuri() vertical_scrollbar_end = teksti_ikkuna.get_vadjustment() vertical_scrollbar_end.set_value(vertical_scrollbar_end.upper - vertical_scrollbar_end.page_size) # Pääikkunan asetukset paaikkuna = gtk.Window(gtk.WINDOW_TOPLEVEL) paaikkuna.resize(800, 600) paaikkuna.move(100,100) paaikkuna.connect("destroy", sulje_paaikkuna) paaikkuna.set_title("Lokitiedostojen katselin") paaikkuna.set_icon_from_file('/usr/share/icons/hicolor/48x48/apps/bug-buddy.png') # Luodaan pystyelementti, lisätään pääikkunaan ja laitetaan näkyviin. pystyelementti_1 = gtk.VBox(False, 0) paaikkuna.add(pystyelementti_1) pystyelementti_1.show() # Tehdään tekstiä sisältävä ikkuna pystyelementin sisälle. teksti_ikkuna = gtk.ScrolledWindow() teksti = gtk.TextView() tekstipuskuri = teksti.get_buffer() pystyelementti_1.pack_start(teksti_ikkuna) teksti_ikkuna.add(teksti) teksti_ikkuna.show() teksti.show() paivita_puskuri() # Luodaan vaakaelementti luodun pystyelementin sisälle vaakaelementti_1 = gtk.HBox(False, 10) vaakaelementti_1.set_border_width(10) pystyelementti_1.pack_start(vaakaelementti_1, False, False, 0) vaakaelementti_1.show() # Liitetään vaakaelementtiin kaksi painiketta, joista toinen päivittää teksti-ikkunan sisällön ja toinen lopettaa ohjelman toiminnan paivita_painike = gtk.Button("Päivitä") paivita_painike.connect("clicked", paivita_sisalto) vaakaelementti_1.pack_start(paivita_painike, True, True, 10) paivita_painike.set_flags(gtk.CAN_DEFAULT) paivita_painike.grab_default() paivita_painike.show() sulje_painike = gtk.Button("Sulje") sulje_painike.connect("clicked", sulje_paaikkuna) vaakaelementti_1.pack_start(sulje_painike, True, True, 10) sulje_painike.show() # Pääikkuna näkyviin paaikkuna.show() gtk.main()
Hyvien ja toimivien graafisten käyttöliittymien (GUI) tekeminen on taitolaji! GUI:n tekemiseen Python tarjoaa loistavan mahdollisuuden!