Tapaaminen 28.01.2010

Aiheina:

  • moduulit
  • nimiavaruus
  • tiedostojen käsittely

Linkkejä:

Tiedostot

Usein käsitelty tieto halutaan tallentaa tietokoneen levylle talteen ja myöhemmin avata taas käyttöön. Tarvitsemme siis keinot luoda, kirjoittaa ja avata tiedostoja. Pythonissa tämä on pyritty toteuttamaan mahdollisimman riippumattomaksi alla olevasta järjestelmästä. Tiedostojen käyttö on siis samanlaista riippumatta käytössä olevasta käyttöjärjestelmästä ja tiedostojärjestelmästä.

Tiedostojen käsittely

Pythonissa lähes kaikkea käsitellään olioina ja siten siis myös tiedostoja. Käytettävä tiedosto avataan open()-funktiolla. Tämä luo uuden tiedosto-olion, ja yhdistää sen annetun nimiseen tiedostoon.

>>> myfile = open('tiedosto.dat','w')
>>> print myfile
<open file 'tiedosto.dat', mode 'w' at 0x7f7687e3fd78>

Tiedostoa avatessa, pitää open()-funktiolle kertoa myös moodi, jossa tiedosto avataan. Edellä tiedosto tiedosto.dat avattiin kirjoitusmoodiin argumentilla w (write).

Jos kyseisen nimistä tiedostoa ei ole vielä olemassa, se luodaan. Jos tiedosto taas on jo ennestään olemassa, korvataan se uudella.

Tiedostoon kirjoittaminen tapahtuu nyt tiedosto-olion write()-metodilla.

>>> myfile.write('Nyt on aika')
>>> myfile.write('sulkea tiedosto')

Tiedosto suljetaan tämä jälkeen close()-metodilla.

>>> myfile.close()

Tämä kertoo järjestelmälle, että olemme saaneet kirjoitettua tiedostoon kaiken haluamamme.

Seuraavaksi voimme avata tiedoston lukemista varten, eli moodiin r (read).

>>> myfile.open('tiedosto.dat','r')

Olemattoman tiedoston avausyritys tuottaisi virheilmoituksen.

Tiedostoa voi lukea tiedosto-olion read()-metodilla, joka lukee kerralla koko tiedoston yhtenä merkkijonona.

>>> text = myfile.read()
>>> print text
Nyt on aikasulkea tiedosto

Voidaan huomata, että sanat aika ja sulkea on kirjoitettu yhteen. Ja tosiaan, kun kirjoitimme tiedostoon, emme todellakaan kirjoittaneet näiden sanojen väliin mitään. Ei välilyöntiä, ei rivinvaihtoa. Voimme antaa read()-metodille myös argumenttina, miten pitkä pätkän tiedostoa haluamme lukea.

Avaamme tiedoston uudelleen, että pääsemme sen alkuun, ja luemme viisi merkkiä.

>>> myfile.open('tiedosto.dat','r')
>>> text = myfile.read(5)
>>> print text
'Nyt o'

Seuraava read()-metodin suoritus jatkaa siitä kohdasta, johon edellisellä jäätiin, ja jos pyydetty merkkijonon pituus on enemmän kuin jäljellä oleva tiedosto, niin read() palauttaa loput tiedoston loppuun saakka.

>>> text = myfile.read(4)
>>> print text
'n ai'
>>> text = myfile.read(200000)
>>> print text
'kasulkea tiedosto'

Tiedoston lopun saavuttamisen jälkeen read() palauttaa vain tyhjän merkkijonon.

>>> myfile.read()
''
>>> myfile.close()

Tekstitiedostot

Tekstitiedostojen, siis merkeistä, välilyönneistä ja rivinvaihdoista koostuvien tiedostojen käsittelyyn Pythonista löytyvät varsin kattavat välineet. Kirjoitetaan aluksi kolme riviä sisältävä tekstitiedosto.

>>> outfile = open('tiedosto.txt','w')
>>> outfile.write('rivi yksi\nrivi kaksi\nrivi kolme\n')
>>> outfile.close()

Kukin rivi päätettiin tässä rivin vaihtoa esittävällä \n-merkillä.

Seuraavaksi luemme tätä tiedostoa readline()-metodilla, joka lukee tiedostosta rivin kerrallaan.

>>> infile = open('tiedosto.txt','r')
>>> print infile.readline()
rivi yksi
>>>

Ruudulle tulostui siis ensimmäinen rivi sekä sen päättävä rivinvaihto.

readline() palautti tiedostosta seuraavan rivin merkkijonona. Kaikki rivit voidaan lukea metodilla readlines(), joka palauttaa listan, jonka alkioina ovat kaikki rivit merkkijonoina.

>>> print infile.readlines()
['rivi kaksi\n', 'rivi kolme\n']

Tiedoston päätyttyä readline() palauttaa tyhjän merkkijonon ja readlines() palauttaa tyhjän listan.

Koko tiedosto voidaan lukea rivi kerrallaan esimerkiksi while-silmukassa, kuten seuraavassa esimerkissä, joka kopioi yhdestä tekstitiedostosta toiseen kaikki rivit, jotka eivät ala #-merkillä.

def filter(oldfile, newfile):
    infile = open(oldfile, 'r')
    outfile = open(newfile, 'w')
    while True:
        text = infile.readline()
        if text == "":
           break
        if text[0] == '#':
           continue
        outfile.write(text)
    infile.close()
    outfile.close()
    return

Silmukkaa suoritetaan ehdon (True) mukaisesti “loputtomiin”, kunnes se keskeytetään break-komennolla, joka tulee, kun readline()-metodin palauttama arvo on tyhjä merkkijono. (Huom: Tyhjällä rivillä on rivinvaihto ‘\n’) Jos rivin ensimmäisenä merkkinä on #, hypätään continue-komennolla silmukan seuraavan kierroksen alkuun suorittamatta loppua silmukan tästä kierroksesta, siis suorittamatta uuteen tiedostoon kirjoittamista.

Tulevaisuudessa tekstitiedostoa lukiessa voidaan käyttää esimerkiksi with-komentoa, jolla voidaan tiedosto avata kyseisen komennon rungon suorituksen ajaksi. Seuraavassa with on tuotu mukaan __future__-modulista ja tiedostoa on luettu for-silmukan avulla.

>>> with open('tiedosto.txt','r') as f:
...     for text in f.readlines():
...             print text,
...
rivi yksi
rivi kaksi
rivi kolme
>>>

Vastaava voidaan nykyisessä Pythonissa suorittaa seuraavasti:

f = open('tiedosto.txt','r')
try:
    for text in f.readlines():
        print text,
finally:
    f.close()

Hakemistot

Oletuksena avattavia tiedostoja haetaan kyseisellä hetkellä käytössä olevasta työhakemistosta. Tiedoston nimessä voidaan antaa myös polku. Joko suhteellisena nykyisen työhakemiston suhteen tai absoluuttisena hakemistorakenteen juuren suhteen.

Esimerkiksi:

>>> wordsfile = open('/usr/share/dict/words','r')
>>> wordlist = wordsfile.readlines()
>>> print wordlist[:6]
['\n', 'A\n', "A's\n", 'AOL\n', "AOL's\n", 'Aachen\n']

sys-moduli

Modulissa sys on useita hyödyllisiä järjestelmään liittyviä välineitä. Esimerkiksi:

>>> import sys
>>> sys.platform
'linux2'
>>> sys.path
['', '/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2', '/usr/lib/python2.6/lib-tk', '/usr/lib/python2.6/lib-old', '/usr/lib/python2.6/lib-dynload', '/usr/lib/python2.6/dist-packages', '/usr/lib/python2.6/dist-packages/PIL', '/usr/lib/python2.6/dist-packages/gst-0.10', '/usr/lib/pymodules/python2.6', '/usr/lib/python2.6/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.6/gtk-2.0', '/usr/lib/python2.6/dist-packages/wx-2.8-gtk2-unicode', '/usr/local/lib/python2.6/dist-packages']
>>> sys.version
'2.6.4 (r264:75706, Dec  7 2009, 18:43:55) \n[GCC 4.4.1]'

Tässä sys.platform kertoo jotain käyttöjärjestelmästä, jolla Python on käynnissä. Lista sys.path sisältää hakemistot, joista Python etsii käytettäviä moduleja ja paketteja. Merkkijono sys.version-merkkijono sisältää tietoa käytetystä Python-versiosta. Tässä tapauksessa version, käännöspäivämäärän ja kääntäjän version.

Erityisen hyödyllinen on muuttuja sys.argv, joka sisältää Python-ohjelman käynnistämiseen käytetyn komentorivin. Jos kirjoitamme esimerkiksi ohjelman:

#
# demo_argv.py
#
import sys
print sys.argv

voimme kutsua sitä komentoriviltä ja antaa sille argumentteja, jotka se sitten tulostaa.

python demo_argv.py this and that 1 2 3
['demo_argv.py', 'this', 'and', 'that', '1', '2', '3']
$

Modulit