Subsections


7. Bemenet és kimenet (2.4 doc)

Egy program kimenete többféleképpen jelenhet meg: például ember által olvasható nyomtatott formában, vagy későbbi feldolgozás céljából fájlba írva. Ez a fejezet a lehetőségek közül többet is bemutat.


7.1 Esztétikus kimenet kialakítása

Az értékek kiírására két lehetőségünk van: Saját kimenet-formázás függvényekkel ??? és a print utasítás. (a fent említett harmadik lehetőség a write() metódust használja fájl objektumok kezelésére; a szabványos kimeneti fájlt a sys.stdout -ként érhetjük el. A referencia könyvtárt érdemes megnézni (Library Reference), ott több információt találunk a szabványos kimenet használatáról.

Gyakori igény, hogy a programozó az egyszerű - szóközökkel tagolt kimeneti formázásnál több lehetőséget szeretne. A kétféleképpen formázhatod a kimenetet:

Egy kérdés maradt hátra: hogy hogyan konvertálhatsz egy számjegyekből álló karakterláncot értékkel bíró számmá? Szerencsére a Python erre több lehetőséget is biztosít: add át a karakterláncot a repr() vagy az str() függvényeknek. A fordított egyszeres idézőjelek (``) használata egyenértékű a repr() függvény hívásával, de használatuk helyett a függvényhívást javasoljuk.

Az str() függvény az értékek ember által olvasható formájával tér vissza, míg a repr() függvény visszatérési értéke az interpreter számára értelmezhető adat. (vagy SyntaxError kivételt vált ki nem megfelelő szintaxis esetén.)

Azon objektumok esetében, amelyeknek nincs emberi olvasásra szánt ábrázolása, az str() függvény ugyanazzal az értékkel tér vissza, mintha a repr() függvényt hívtuk volna meg. Néhány érték, például a számok vagy a struktúrák esetében - mint például a listák vagy a szótárak, bármely két fent említett funkciót használva ugyanazt az eredményt kapjuk. Karakterláncok és lebegőpontos számoknak két eltérő ábrázolási módjuk van:

Néhány példa:

>>> s = 'Helló, világ.'
>>> str(s)
'Helló, világ.'
>>> repr(s)
"'Helló, világ.'"
>>> str(0.1)
'0.1'
>>> repr(0.1)
'0.10000000000000001'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'x értéke: ' + repr(x) + ', és y értéke: ' + repr(y) + '...'
>>> print s
x értéke: 32.5, és y értéke: 40000...
           
% >>> # The repr() of a string adds string quotes and backslashes:
>>> # A repr() függvény idézőjelek közé rakja a stringet,
>>> # és kijelzi a különleges (escape) karaktereket is:
... hello = 'helló világ\n'
>>> hellos = repr(hello)
>>> print hellos
'helló világ\n'
           
>>> # A repr() függvénynek akár objektumokat is átadhatunk:
... repr((x, y, ('hús', 'tojás')))
"(32.5, 40000, ('hús', 'tojás'))"
           
% >>> # reverse quotes are convenient in interactive sessions:
>>> # A visszahajló idézőjeleket (`) interaktív módban használhatjuk,
>>> # ugyanazt érjük el, mint ha a repr() függvényt hívtuk volna meg:
... `x, y, ('spam', 'eggs')`
"(32.5, 40000, ('spam', 'eggs'))"

Ha akarunk készíteni egy táblázatot, amiben a számok második és harmadik hatványai szerepelnek, két lehetőségünk is van:

>>> for x in range(1, 11):
...     print repr(x).rjust(2), repr(x*x).rjust(3),
%...     # Note trailing comma on previous line
...     # Figyelem! az előző sor végén szereplő vessző miatt a
...     # következő print az előző sor végén folytatja a kiírást!
...     print repr(x*x*x).rjust(4)
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
>>> for x in range(1,11):
...     print '%2d %3d %4d' % (x, x*x, x*x*x)
... 
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

(Megjegyzés: az oszlopok között 1 szóköznyi helyet a print utasítás hagyott - az utasítás a paraméterei között mindig 1 szóközt hagy.)

Ez a példa bemutatja a szöveges (karakterlánc) objektumok rjust() metódusát, ami a megadott karakterláncot jobbra igazítja, majd a megadott szélességig feltölti üres karakterekkel a baloldalt. Ehhez hasonlóak a ljust() és a center() függvények. Ezek írási műveletet nem végeznek, egyszerűen visszatérnek az új karakterlánccal. Ha a bemenetként megadott szöveg túl hosszú, azt nem csonkolják - változatlanul adják vissza az eredeti karakterláncot. Ez elrontja ugyan a kimenet rendezettségét, de rendszerint jobb, mintha a függvény valótlan (csonkított) értékkel térne vissza. (Ha valóban szeletelni akarod a karakterláncot, ezt így tudod megtenni: "x.ljust( n)[:n]".)

Létezik egy másik metódus, a zfill(), amely az adott numerikus karakterláncot balról nulla karakterekkel tölti fel. Ez könnyen megérthető a plusz és minusz jelek esetében:

>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'

A % operátort használata így néz ki:

>>> import math
>>> print 'PI értéke megközelítőleg %5.3f.' % math.pi
PI értéke megközelítőleg 3.142.

Ha a karakterláncban egynél több formázást szeretnél használni, akkor az alábbi példát követve egy tuple változót kell paraméterként használnod:

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print '%-10s ==> %10d' % (name, phone)
... 
Jack       ==>       4098
Dcab       ==>       7678
Sjoerd     ==>       4127

A legtöbb formázás pontosan ugyanúgy működik, mint C-ben, és a megfelelő típusú változó átadását igényli. Ha kivétel váltódik ki, és azt a kódodban nem kapod el, ???not a core dump???.

A %s formázás ennél rugalmasabb: ha a csatolt paraméter nem egy karakterlánc, akkor a str() beépített függvény használatával automatikusan azzá konvertálja. A * használata a szélesség, vagy a pontosság meghatározására egy külön paraméterként (integer) lehetséges. A következő C formázások nem támogatottak: %n, %p.

Ha egy nagyon hosszú formázott karakterláncot szeretnél használni, amit nem akarsz darabokra felosztani, szép lenne, ha hivatkozni tudnál a formázandó változókra azok neveivel, pozíciójuk helyett. Ezt a %(name)format forma használatával teheted meg, például így:

>>> table = {'Bea': 1975, 'Balazs': 1978, 'Fanni': 2003}
>>> print 'Fanni: %(Fanni)d; Bea: %(Bea)d; Balazs: %(Balazs)d' % table
Fanni: 2003; Bea: 1975; Balazs: 1978

Ez különösen hasznos az új vars() függvénnyel együtt, amely egy szótár típusú változóval tér vissza, amely az összes helyi változót tartalmazza.


7.2 Fájlok írása és olvasása

Az open() függvény egy object objektummal tér vissza, és rendszerint két paraméterrel használjuk: "open(filename, mode)".

>>> f=open('/tmp/munkafile', 'w')
>>> print f
<open file '/tmp/munkafile', mode 'w' at 80a0960>

Az első paraméter egy fájlnevet tartalmazó karakterlánc. A második paraméter néhány karakterből áll csupán, és a fájl használatának a módját (írás, olvasás) állíthatjuk be vele. A megnyitás módja (mode) lehet 'r' mikor csak olvassuk a fájlt - 'w', ha kizárólag írni szerenténk (a már esetleg ugyanezen néven létező fájl tartalma törlődik!) - és 'a', amikor hozzáfűzés céljából nyitjuk meg a fájlt; ilyenkor bármilyen adat, amit a fájlba írunk, automatikusan hozzáfűződik annak a végéhez. A 'r+' megnyitási mód egyszerre nyitja meg a fájlt írásra és olvasásra. A mode paraméter beállítása nem kötelező; elhagyása esetén 'r' alapértelmezett értéket vesz fel.

Windows és Macintosh rendszereken a megnyitási módhoz hozzáfűzött 'b' karakterrel bináris módban nyithatjuk meg a fájlt, például így: 'rb', 'wb' vagy 'r+b'. A Windows megkülönbözteti a szöveges és bináris fájlokat; a szöveges fájlban a sorvéget jelző karakterek (end-of-line) kis mértékban automatikusan megváltoznak adat írása vagy olvasása esetén.

Ez a háttérben zajló módosítás ugyan megfelelő az ASCII szöveges fájlok számára, de a bináris fájlokat használhatatlanná teszi (pl. JPG vagy .EXE fájlokat). Ezért nagyon figyelj oda, hogy a bináris módot használd olvasáskor és íráskor. (Megjegyezzük, hogy Macintosh-on a használt C könyvtártól függ a megnyitási módok pontos működése.


7.2.1 A fájl objektumok metódusai

A fejezet további példái feltételezik, hogy már létezik az f fájl objektum.

A fájl tartalmának olvasásához hívd meg az f.read(size) metódust, ami a megadott adatmennyiségnek megfelelő hossszúságú karakterlánccal tér vissza. A size egy opcionális paraméter - elhagyása, vagy negatív értéke esetén a teljes tartalmat visszaadja a metódus - ha esetleg a fájl kétszer akkora, mint a gépedben lévő memória, az esetleg problémát jelenthet neked.

Ha használod a size paramétert, akkor a visszatérési értékként kapott karakterlánc hosszát maximalizálni tudod. Ha eléred a fájl végét, az f.read() egy üres karakterlánccal tér vissza ("").

>>> f.read()
'Ez a fájl teljes tartalma.\n'
>>> f.read()
''

A f.readline() egy sort olvas ki a fájlból. A sor végét az újsor karakter (\n) jelenti, amely a beolvasott karakterlánc végén található. Ez a karakter egyetlen esetben maradhat ki a visszaadott karakterlácból: ha a fájl utolsó sorát olvassuk be, és az nem újsor karakterre végződik.

Ez a visszatérési értéket egyértelművé teszi: ha a f.readline() metódus üres karakterlánccal tér vissza, az olvasás elérte a fájl végét. Ekkor az üres sort a '\n' karakter jelképezi - a karakterlánc egyetlen egy újsor karaktert tartalmaz.

>>> f.readline()
'Ez a fájl első sora.\n'
>>> f.readline()
'A fájl második sora.\n'
>>> f.readline()
''

A f.readlines() metódus egy listával tér vissza, amely a fájl minden sorát tartalmazza. Ha megadjuk a sizehint paramétert, a metódus a megadott számú byte-ot kiolvassa a fájlból, és még annyit, amennyi a következő újsor karakterig tart. (A fordító megjegyzése: sizehint paramétert hiába adtam meg, 2.1-es pythont használva a teljes fájltartalmat kiolvasta.)

>>> f.readlines()
['Ez a fájl első sora.\n', 'Ez pedig a második\n']

A f.write(string) metódus a string tartalmát a fájlba írja, és None értékkel tér vissza.

>>> f.write('Tesztszöveg, az írás bemutatására\n')

Ha egy karakterlánctól eltérő típusú változót szeretnénk kiírni, akkor azt előbb karakterlánccá kell konvertálni:

>>> value = ('a valasz', 42)
>>> s = str(value)
>>> f.write(s)

Ford.: Ha megnézzük a keletkezett fájl tartalmát, az ('a valasz', 42) lesz.

Az f.tell() metódussal a fájl objektum aktuális pozícióját kérdezhetjük le - bájt-ban, a fájl kezdetétől számolva. (pl.: hányadik bájt-ot olvassuk most éppen)

A fájl objektum pozíciójának (a kurzornak) a megváltoztatásának módja: "f.seek(léptetés, innen_kezdve)". Az innen_kezdve ponttól léptetés mennyiséggel mozgatjuk a kurzort. (Példa: ha van egy 100 bájtos fájl, amiben éppen a 39. karakternél állunk, akkor az aktuális pozícióhoz képest ugorhatunk tovább, megadott lépésekben)

A from_what value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as the reference point. from_what can be omitted and defaults to 0, using the beginning of the file as the reference point.

Az innen_kezdve paraméter a következő értékeket veheti fel:

>>> f = open('/tmp/munkafajl', 'r+')
>>> f.write('0123456789abcdef')
>>> f.seek(5)     # Ugorj a 6. bajthoz a fajlban 
>>> f.read(1)        
'5'
>>> f.seek(-3, 2) # Ugorj a fajl vegehez kepest harom karakterrel vissza
>>> f.read(1)
'd'

Ha már minden módosítást elvégeztél a fájl-al, hívd meg a f.close() metódust a fájl bezárásához (a rendszererőforrások felszabadításához). A f.close() hívása után a fájl objektum használatára tett kísérletek automatikusan meghiúsulnak.

>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file

A fájl objektumoknak van néhány kiegészítő metódusuk, például az isatty() és a truncate() - ezek ritkábban használtak. A Referencia könyvtárban teljes útmutatót találsz a fájl objektumok használatához.


7.2.2 A pickle modul

A karakterláncokat könnyű fájlba írni és onnan kiolvasni. A számokkal kicsit nehezebb a helyzet, mert a read() metódus mindent karakterként ad vissza, amit aztán át a számmá történő átalakítás miatt például az int() függvénynek kell átadnunk, ami a '123' karakterláncból a 123-as értéket adja vissza.

Hogyha összetettebb adattípusokat akarsz menteni, például listákat, szótárakat vagy osztály-példányokat, egyre bonyolultabbá válik a dolgod.

Ahelyett, hogy a felhasználóknak állandóan adatmentő algoritmusokat kelljen írnia és javítania, a Python rendelkezik a pickle modullal. Ez egy elképesztő modul, ami képes a legtöbb Python objektumot karakterláncként ábrázolni. (even some forms of Python code!???) Ezt a folyamatot pickling-nek hívják.

Az objektum karakterláncból történő létrehozását pedig unpickling-nek nevezik.

A karakterlánccá történő konvertálás és a visszakonvertálás között a karakterlánc jelképezi az objektumot. Ezt akár fájlban, akár más formában tárolhatjuk. (hálózaton elküldve másik gépen, vagy adatbázisban)

Ha van egy x objektumod, és létezik az írásra megnyitott f fájl objektum, a legegyszerűbb út az objektumod tárolására a következő egysoros kód:

pickle.dump(x, f)

Ha újból elő kívánod állítani az objektumot, és az f egy olvasásra megnyitott fájl objektum:

x = pickle.load(f)

(Vannak más variációi is ennek, amik több objektum tárolásánál / újbóli előállításánál használatosak, illetve akkor, ha nem akarod a tárolási formába alakított objektumodat ténylegesen fájlba írni; a téma teljes dokumentációja: pickle a Python Library Reference-ben.)

A pickle a szabályos módja a Python objektumok készítésének, amiket tárolhatsz, vagy újra felhasználhatsz más programokkal, vagy akár a jövőbeni felhasználás céljából a jelenlegi programoddal. Ennek a technikai megnevezése: persistent objektumok (állandó, tartós). Azért, mert a pickle széles körben elterjedt, a legtöbb Python kiegészítést készítő programozó figyelmeztet, hogy bizonyosodj meg arról, hogy az új adattípusok tárolhatók és újra előállíthatók (mintha egy matricát leragasztanál, majd újra felvennéd).

See About this document... for information on suggesting changes.