Python-kielen ja CGI-ohjelmoinnin perusteita

Esimerkkiohjelmia

Luentomalli 2019 ( lähdekoodi)

hello.py

hello_luento.cgi (lähdekoodi)

Luentovideoita

Python-luento (2019)

Python-luento (2018)

Vanha Python-luento (2016)

Vielä vanhempi Python-luento (2014)

Python

Python-kielestä on kaksi versiota: Python 2 ja Python 3. Käytämme tällä kurssilla Python 3 -kieltä. Osa esimerkeistä on kirjoitettu vanhemmalla Python 2 -kielellä, mutta ne on helposti muunnettavissa Python 3 -yhteensopiviksi.

Python 3:sta uusin versio on 3.9.1. Käytämme tällä kurssilla hieman vanhempaa Python 3.7.9. Näissä ei ole merkittäviä eroja.

Python 2 ja Python 3 erot

Tärkeimmät eroavaisuudet:

Python 3Python 2
print-funktioprint("foo")print "foo"
Kokonaislukujen jakolaskuKokonaislukujen jakolaskun tulos on liukulukuKokonaislukujen jakolaskun tulos on kokonaisluku
UnicodeMerkkijonot ovat oletuksen unicodeunicode-merkkijonojen edessä täytyy olla u
"kissa"
iterointirangexrange

Python on korkean tason ohjelmointikieli, jonka suunnittelussa on panostettu erityisesti kielen luettavuuteen. Monesta muusta kielestä poiketen Python käyttää koodin sisennyksiä koodilohkojen merkintään.

Python

Pythonin syntaksiin kannattaa tutustua esim. seuraavien tutoriaalien ja ohjeiden avulla:

Seuraavassa on käyty läpi tärkeimpiä Pythonin piirteitä.

Muuttujat

Merkkijonot

Python 2.7:ssa oli hämäävästi kahta eri tyyppiä olevia merkkijonoja: str ja unicode. Python 3:ssa on vain unicode-merkkijonoja ja tavujonoja.

>>> foo = "testi"
>>> bar = b"testi"
>>> type(foo)
<class 'str'>
>>> type(bar)
<class 'bytes'>

Pythonissa merkkijonoja voidaan esittää seuraavilla tavoilla:

Listat

Lista on pythonissa vastaava rakenne kuin esim. Javascriptin taulukko

Listojen palastelu tapahtuu samaan tapaan kuin merkkijonoilla.

Listoja voi muuttaa päinvastoin kuin merkkijonoja

a = [1, 2, 3, 'foo', 'bar']
a[0] = 3 # [3, 2, 3, 'foo', 'bar']
a[1] = a[2] * 3 #[3, 9, 3, 'foo', 'bar']
a[2:1] = [u'kukku',u'luuruu'] #  [3, 9, 3, u'kukku', u'luuruu', u'foo', u'bar']

Yhteisiä funktioita merkkijonoille ja listoille:

Listojen metodeja

Operaattorit

Seuraavassa on listattu Pythonin tärkeimmät operaattorit:

if

a = 3
if a> 0:
  print "a on suurempi kuin 0"
elif a < 0:
  print "a on pienempi kuin 0"
else:
  print "a on 0"

Toistorakenteet

laskuri = 12

while laskuri> 0:
  laskuri = laskuri - 1


a = [1,2,3,u'foo',u'bar']

for x in a:
  print( x )

for x in a[:]:  #tekee kopion a:sta. tarpeellinen jos aikoo muuttaa listaa
  print( x )

for i in range(1, 5): #range-funktio luo listan halutulta numeroväliltä
  print( i )

Pythonissa ei ole do..while-toistorakennetta.

for käy järjestyksessä läpi rakenteen kaikki alkiot. vrt. Perlin foreach.

Läpikäytävää rakennetta ei pidä muuttaa läpikäynnin aikana. Jos muutoksia pitää tehdä niin on syytä käydä läpi rakenteen kopiota.

Funktiot

def summa(a, b):    # laskee lukujen summan
  summa = a + b
  return summa

Funktioiden parametrit ovat referenssejä joten niiden arvojen muuttaminen vaikuttaa suoraan kutsuvaan ohjelmaan (call-by-reference).

Jos parametrina vie immutable-tyyppisiä muuttujia niin niitä ei tietenkään voi muuttaa funktiossa. Esim. kokonaisluvut, merkkijonot ja tuplet ovat immutable. Kts. Parameter Passing

Moduulit

Pythonissa voi jakaa ohjelmansa moduuleihin tai käyttää valmiita moduuleja

import cgi

Oman moduulin voi luoda kirjoittamalla python-funktioita tiedostoon, jonka nimi päättyy .py

Poikkeukset

Pythonissa lähes kaikki virheet aiheuttavat poikkeuksen. Poikkeukset käsitellään seuraavasti:

#!/usr/bin/python3.7
# -*- coding: utf-8 -*-

try:
    if int("a"):
        print("onpas kummaa. a oli kokonaisluk")
#nappaa kiinni kaikki mahdolliset virheet
except:
    print("ei ollunna integer")

# edellä oleva ei ole hyvä debuggaamisen kannalta koska nappaa kiinni
# myös kirjoitusvirheet funktioiden nimissä ja python-tulkin oma
# virheilmoitus jää näyttämättä

try:
    if Int("a"): # tulee virhe koska Int ei ole olemassa
        print("onpas kummaa. a oli kokonaisluk")
#nappaa kiinni kaikki mahdolliset virheet
except:
    print("ei ollunna integer")

# parempi napata kiinni vain se olennainen virhe
try:
    if int("a"):
        print("onpas kummaa. a oli kokonaisluk")
except ValueError:
    print("ei ollunna integer")

# nyt pitäisi toimia tulkin oma virheilmoitus
try:
    if Int("a"):
        print("onpas kummaa. a oli kokonaisluk")
except ValueError:
    print("ei ollunna integer") 

kts. Idioms and Anti-Idioms in Python

Sanakirja (dict)

Pythonissa on myös erittäin kätevä tietotyyppi dict eli sanakirja, jota muissa ohjelmointikielissä kutsutaan mm. assosiatiiviseksi taulukoksi. dict-tietotyyppi on siis järjestämätön taulukko, jossa alkioihin viitataan uniikeilla avaimilla.

>>> testi = dict([[1,2], [2,2], [u'kolme',3], [u'neljä',4]])
>>> testi
{u'nelj\xe4': 4, 1: 2, 2: 2, u'kolme': 3}
>>> for x in testi.keys(): print(x)
...
neljä
1
2
kolme
>>> for x in testi.keys(): print(testi[x])
...
4
2
2
3
>>> testi['kolme']
3
>>> testi[2]
2
>>> testi[1]
2

Monikot (tuple)

Monikko eli tuple on listaa vastaava tietorakenne, jonka sisältöä ei voi muuttaa.

a = (1,2,3,"testi")

print(a)

a=[0] # ei onnistu

Joukko (set)

Pythonin erikoisempiin tietotyyppeihin kuuluu set eli joukko. Joukko ei voi sisältää duplikaatteja ja siihen voi soveltaa joukko-opin operaatioita kuten yhdiste, leikkaus, erotus jne.

>>> lista = [u'tommi', u'antti', u'ville', u'tommi']
>>> joukko = set(lista)
>>> joukko
set([u'ville', u'antti', u'tommi'])
>>> u'tommi' in joukko
True
>>> u'kalle' in joukko
False
>>> joukko2 = set([u'joonas',u'antti',u'kalle'])
>>> joukko2
set([u'joonas', u'kalle', u'antti'])
>>> joukko - joukko2 #henkilöt joukosta jotka eivät ole joukko2:ssa
set([u'ville', u'tommi'])
>>> joukko & joukko2 #henkilöt jotka ovat molemmissa joukoissa
set([u'antti'])
>>> joukko ^ joukko2 #henkilöt jotka ovat jommassa kummassa joukossa mutta eivät molemmissa
set([u'joonas', u'kalle', u'tommi', u'ville'])
>>> joukko | joukko2 #henkilöt jotka ovat jommassa kummassa joukossa
set([u'ville', u'joonas', u'kalle', u'antti', u'tommi'])

Luokat

Luokat toimivat kuten muissakin kielissä. Muutama erikoisuus on syytä huomioida. Lue Class tutorial

#!/usr/bin/python3.7
# -*- coding: utf-8 -*-

#suoraan luokan alla esitellyt muuttujat ovat luokkakohtaisia muuttujia. Tämän huomaa
#jos käyttää tietotyyppejä, jotka sallivat sisältönsä muuttamisen 
class Ihminen:
    nimi = "Kalle"
    tiedot = []   
    def __init__(self, sukupuoli="Nainen"):
        self.data = [sukupuoli]
    def tulosta(self):
        # on käytettävä self
        print(self.nimi, self.tiedot, self.data)
        
   
mies = Ihminen("Mies")
nainen = Ihminen()

mies.nimi = "Tommi"

mies.tiedot.append("180 cm")
mies.tiedot.append("75 kg")

print(mies.nimi)

nainen.nimi = "Hell"

print(nainen.nimi)

print(mies.nimi)

# molemmilla on samat tiedot!
print(mies.tiedot)
print(nainen.tiedot)

nainen.tiedot.append("170 cm")
nainen.tiedot.append("75 kg")

print(mies.tiedot)
print(nainen.tiedot)

# data on kummallakin oma, koska se on esitelty konstruktorissa
print(mies.data)
print(nainen.data)

mies.data.append("30 v")
nainen.data.append("35 v")

print(mies.data)
print(nainen.data)

# voidaan myös lennosta keksiä uusia ominaisuuksia vrt. Javascript
# nämä ovat instanssikohtaisia
mies.osoite = "Taitoniekantie 9 B 701"
nainen.osoite = "Emännäntie 13"

print(mies.osoite)
print(nainen.osoite)

# metodia kutsuttaessa ensimmäisenä olevaa self-parametriä ei käytetä. Python hoitaa tämän automaattisesti
mies.tulosta()
nainen.tulosta()

Pythonin luokista

Tietorakenteita

Katso esimerkki tietorakenteista

Python OneLiners

Tiedostojen käsitteleminen

Pythonissa voi käsitellä tiedostoja open-funktiolla, mutta suositeltavampaa on käyttää io-kirjastoa. io-kirjasto osaa paremmin käsitellä erilaiset merkistöt.

import io
f = io.open("test.txt", mode="r", encoding="utf-8")
print(file.read()) #lukee koko tiedoston. Jos haluaa lukea rivi kerrallaan niin f.readline()
f.close()
# rivi kerrallaan voi lukea myös seuraavasti:
for line in f:
   print(line)
import io
# seuraava sulkee tiedoston automaattisesti käsittelyn loputtua
with io.open('tiedosto.txt', 'w', encoding="UTF-8") as file:
    file.write(u'Kirjoitetaan tiedostoon')

CGI-ohjelmointi Pythonilla

CGI eli Common Gateway Interface on yksinkertaisin rajapinta WWW-sovelluksien tekemiseen

HTML-dokumentti Python-kielellä ja CGI-rajapinnan kautta tuotettuna:

#!/usr/bin/python3.7
# -*- coding: utf-8 -*-
import cgitb
cgitb.enable()

print("""Content-type: text/html; charset=UTF-8

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Malli</title>
  </head>
<body>
  <h1>Tulostetaan Pythonilla:</h1>
  <p>
""")

print("Hello World! Osaatkönä skändejä?")
print("""
  </p>
</body>
</html>
""")

Virheilmoitukset ja asetukset

Pythonilla tehtyjen CGI-ohjelmien debuggaamista helpottaa cgitb-moduulin käyttöönotto:

import cgitb
cgitb.enable()

cgitb aiheuttaa virheraporttien näyttämisen www-selaimessa tai niiden tallentamisen tekstitiedostoon.

Oletuksena cgitb-kirjasto tulostaa virheilmoitukset HTML-muodossa. Jos haluat tekstimuotoisen tulostuksen niin käytä kutsua:

cgitb.enable(format="text")

Lisätietoa: HOWTO Use Python in the web

CGI-ohjelmat users.jyu.fi-palvelimella

Viimeisimmät tiedot löytyvät aina digipalvelujen ohjeesta: CGI/SSI-tekniikoiden käyttäminen www-palveluissa (users.jyu.fi/groups.jyu.fi)

Python ja merkistöt

Tiedostojen käsitteleminen ja JSON

Pythonilla on helppo käsitellä JSON-muotoista tietoa. Pythonin omia tietorakenteita on myös helppo muuntaa JSON-muotoon. JSON-tiedostomuotoa on käsitelty enemmän TIEA2120-kurssilla.

Querystring

Lisätietoa

Käyttäjien kommentit

Kommentoi Lisää kommentti
Kurssimateriaalien käyttäminen kaupallisiin tarkoituksiin tai opetusmateriaalina ilman lupaa on ehdottomasti kielletty!
https://appro.mit.jyu.fi/ties4080/luennot/python/
© Tommi Lahtonen (tommi.j.lahtonen@jyu.fi) <https://hazor.iki.fi/>
2021-01-11 15:23:48
Informaatioteknologia - Jyväskylän yliopiston informaatioteknologian tiedekunta