Subsections

 
7. Vstup a výstup

Program často potřebuje nějakým způsobem předat uživateli data, která vznikla jeho činností. Existuje mnoho možností, jak získat výstup z programu - data mohou být vytisknuta v čitelné formě na standardní výstup nebo je program může zapsat do souboru a umožnit tak jejich další zpracování.

 
7.1 Formátování výstupu

Na začátku této knihy jsme si probrali dvě možnosti, jak vytisknout nějakou hodnotu na obrazovku: vyhodnocení výrazu v interaktivním interpretru a příkaz print. (Třetí možností je použití metody write() souborového objektu "standardní výstup" na nějž se můžeme odkazovat pomocí proměnné sys.stdout. Pro více informací o standardních souborových objektech nahlédněte do dokumentu Library Reference.)

Pravděpodobně budete chtít větší kontrolu nad formátováním výstupu vašeho programu než je pouhé vytisknutí hodnot oddělených mezerou. Jsou dvě cesty, kterými se můžete dát - první je napsat si veškerou obsluhu dat sám za použití slice konstrukcí a operací spojení. Standardní modul string  obsahuje mnohé užitečné funkce pro zarovnávání řetězců na určitou šířku sloupce. Druhou možností je použití operátoru % s řetězcem na místě prvního operandu. Operátor % interpretuje levý operand jako formátovací řetězec se syntaxí podobnou C funkci sprintf() a pravý operand jako seznam argumentů, přičemž vrátí řetězec odpovídající formátovací operaci.

Zbývá poslední otázka: jak převést nějakou hodnotu na řetězec? Naštěstí Python má možnost zkonvertovat libovolnou hodnotu na řetězec - předání této hodnoty jako argument funkci str() nebo repr(). (Můžete také hodnotu zapsat mezi obrácené apostrofy (``), což je ekvivalent funkce repr()).

Funkce str() vrací řetězcovou reprezentaci argumentu, která je určena především pro uživatele, zatímco funkce repr() je navržena pro vytváření takových řetězců, které mohou být zpět načteny samotným interpretrem. Pro objekty, které nelze zapsat v čitelné formě, vrátí funkce str() stejnou hodnotu jako funkce repr(). Mnoho hodnot jako čísla nebo strukturované typy (především seznamy nebo slovíky) jsou reprezentovány stejnou hodnotou za použití obou funkcí. Výjimkou jsou řetězce a čísla v plovoucí řádové čárce, která mají dvě rozdílné reprezentace:

>>> s = 'Ahoj světe.'
>>> str(s)
'Ahoj světe.'
>>> `s`
"'Ahoj světe.'"
>>> str(0.1)
'0.1'
>>> `0.1`
'0.10000000000000001'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'Hodnota x je ' + `x` + ' a y ' + `y` + '...'
>>> print s
Hodnota x je 32.5 a y 40000...
>>> # Obrácené uvozovky je možné použít i s jinými typy:
... p = [x, y]
>>> ps = repr(p)
>>> ps
'[32.5, 40000]'
>>> # Konvertování řetězců přidá uvozovky a zpětná lomítka:
... ahoj = 'ahoj světe\n'
>>> ahojs = `ahoj`
>>> print ahojs
'ahoj světe\n'
>>> # Argumentem obrácených uvozovek může být i tuple:
... `x, y, ('spam', 'eggs')`
"(32.5, 40000, ('spam', 'eggs'))"

Zde jsou ukázány dva způsoby, jak vypsat tabulku druhých a třetích mocnin:

>>> import string
>>> for x in range(1, 11):
...     print string.rjust(`x`, 2), string.rjust(`x*x`, 3),
...     # Nezapomeňte ukončující čárku na předchozím rádku
...     print string.rjust(`x*x*x`, 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

(Mezery mezi každý sloupec přidal samotný příkaz print, který vždy vloží znak mezery mezi jeho argumenty.)

Tento příklad demonstruje použití funkce string.rjust(), která zarovná řetězec mezerami doprava ve sloupci o zadané šírce. Existují obdobné funkce string.ljust() a string.center(). Tyto funkce nic nevypisují, pouze vrátí nový řetězec. Jestliže jejich vstupní řetězec je delší než požadovaná šířka pole, nedojde k oříznutí řetězce, ale vrátí se nezměněná - to může poničit vaše formátování, ale je to lepší než druhá možnost, která zase vrací chybné výsledky. (Jestliže opravdu vyžadujete oříznutí výsledku, můžete použít slice konstrukci podobnou této: "string.ljust(x, n)[0:n]".)

Modul string nabízí ještě jednu funkci string.zfill(), která doplní číselné řetězce zleva nulami a správně interpretuje znaménka plus a mínus:

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

Operátor % se používá podobně jako funkce sprintf jazyka C:

>>> import math
>>> print 'Hodnota Ludolfova čísla je přibližně %5.3f.' % math.pi
Hodnota Ludolfova čísla je přibližně 3.142.

Obsahuje-li formátovací řetězec více formátovacích příkazů, musíte operátoru % předat jako pravý operand tuple argumentů podobně jako v tomto příkladě:

>>> tabulka = {'Adolf': 4127, 'Běta': 4098, 'Cyril': 7678}
>>> for jmeno, telefon in tabulka.items():
...     print '%-10s ==> %10d' % (jmeno, telefon)
... 
Běta       ==>       4098
Adolf      ==>       4127
Cyril      ==>       7678

Většina formátovacích příkazů funguje stejně jako v C. Předáte-li jim chybný argument, nedostanete core dump jako v C, ale z příkazu se rozšíří výjimka. Příkaz %s je volnější: jestliže odpovídající argument není řetězec, je na něj nejprve převeden pomocí interní funkce str(). Použití * jako šírky sloupce nebo přesnosti namísto integeru je rovněž podporováno, zatímco formátovací příkazy %n a %p z jazyka C není možné používat.

Jestliže máte velice dlouhý formátovací řetězec, který nechcete rozdělovat, může být lepší odkazovat se na proměnné, které mají být použity podle jejich jména a ne podle pozice. To umožňuje druhý tvar formátovacího příkazu %(jméno)formát:

>>> tabulka = {'Adolf': 4127, 'Běta': 4098, 'Cyril': 8637678}
>>> print 'Běta: %(Běta)d; Adolf: %(Adolf)d; Cyril: %(Cyril)d' % tabulka
Břéťa: 4098; Adolf: 4127; Cyril: 8637678

Velice užitečná je tato vlastnost ve spojení s interní funkcí vars(), která vrací slovník obsahující všechny lokální proměnné:

>>> ahoj = 'Vítáme Vás'
>>> print 'Máme pro vás následující zprávu: %(ahoj)s!' % vars()
Máme pro vás následující zprávu: Vítáme Vás!

 
7.2 Čtení a zápis souborů

Funkce open() vrací objekt typu soubor (souborový objekt) a je nejčastěji používána se dvěma argumenty: "open(jméno_souboru, mód)".

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

První argument je řetězec obsahující jméno souboru. Druhý argument je další řetězec složený z několika znaků určujících, jakým způsobem bude se souborem zacházeno. mód může být 'r' bude-li soubor používán pouze pro čtení, 'w' pouze pro zápis (existuje-li již soubor s tímto jménem, bude smazán) a 'a' otevře soubor pro přidávání, takže všechna data zapsana do souboru jsou automaticky přidána na konec souboru. 'r+' otevře soubor jak pro čtení, tak pro zápis. Argument mód je nepovinný, je-li vynechán, předpokládá se 'r'.

Na systémech Windows a Macintosh přidáním 'b' za mód dojde k otevření souboru v binárním módu, takže existují ještě módy jako 'rb', 'wb' a 'r+b'. Windows rozlišují mezi textovými a binárními soubory; znaky konce řádku jsou automaticky obsluhovány při čtení nebo zápisu dat. Tato skrytá konverze souborových dat je dobrá pro textové soubory, ale při zápisu binárních dat typu JPEG nebo třeba .exe velice překáží. Důsledně proto dbejte na pužívání binárního módu při čtení a zápisu takových souborů. (Přesné chování textového módu na OS Macintosh závisí na použité C knihovně).

 
7.2.1 Metody souborových objektů

Všechny příklady v této sekci předpokládají, že jste si již vytvořili souborový objekt nazvaný f.

Pro přečtení obsahu souboru zavolejte f.read(počet_bytů), který přečte určité množství dat a vrátí je jako řetězec. počet_bytů je volitelný číselný argument. Je-li počet_bytů vynecháno nebo záporné číslo, je přečten a vrácen celý obsah souboru (kontrola, jestli soubor není několikrát větší než vaše dostupná operační paměť, je již na vás). Jinak je ze souboru přečteno a vráceno nejvýše počet_bytů bytů. Dosáhlo-li se při čtení konce souboru, f.read() vrátí prázdný řetězec ("").

>>> f.read()
'Toto je obsah celého souboru.\n'
>>> f.read()
''

f.readline() přečte jeden řádek ze souboru, přičemž je znak konce řádku (\n) ponechán na konci řetězce a je vynechán pouze na posledním řádku souboru pokud soubor nekončí na novém řádku. Díky tomu je návratová hodnota jednoznačná - vrátí-li f.readline() prázdný řetězec, pak bylo dosaženo konce souboru, zatímco prázdná řádka je reprezentována řetězcem obsahujícím pouhý znak konce řádku ('\n').

>>> f.readline()
'Toto je první řádka souboru.\n'
>>> f.readline()
'Druhá řádka souboru\n'
>>> f.readline()
''

f.readlines() vrátí seznam obsahující všechny řádky v souboru. Předáte-li jí ještě volitelný číselný argument, pak se přečte tolik bytů plus ještě pár pro dokončení řádku a vrátí se seznam z nich vytvořený. Tato metoda se se používá nejčastěji pro efektivní čtení velkých souborů řádek po řádku aniž by program musel mít načten celý soubor v paměti.

>>> f.readlines()
['Toto je první řádka souboru.\n', 'Druhá řádka souboru\n']

f.write(řetězec) zapíše obsah řetězce řetězec do souboru. Metoda vždy vrací None.

>>> f.write('Zkouška mikrofonu - 1 ... 2 ... 3\n')

f.tell() vrátí celé číslo představující aktuální pozici v souboru měřenou od začátku souboru. Pro změnu této pozice použijte metodu "f.seek(offset, odkud)". Nová pozice je vypočtena připočtením offset k referenčnímu bodu, který je určen argumentem odkud. Při použití hodnoty 0 je referenčním bodem počátek souboru, 1 znamená aktuální pozici a 2 určuje konec souboru. odkud může být také vynechán, v tomto případě je použita jeho implicitní hodnota 0:

>>> f=open('/tmp/workfile', 'r+')
>>> f.write('0123456789abcdef')
>>> f.seek(5)     # Jdi na šestý byte v souboru
>>> f.read(1)        
'5'
>>> f.seek(-3, 2) # Jdi na 3 byte před koncem souboru
>>> f.read(1)
'd'

Jestliže již se souborem nehodláte pracovat, zavolejte f.close() pro uzavření souboru a uvolnění všech systémových prostředků vyhrazených pro tento soubor. Po zavolání f.close() automaticky zhavaruje každý pokus o přístup k tomuto objektu:

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

Souborové objekty mají ještě další metody jako isatty() a truncate(), které jsou ale zřídka používané. Pro jejich popis proto prosím nahlédněte do dokumentu Library Reference.

 
7.2.2 Modul pickle

 

Řetězce mohou být jednoduše čteny a zapisovány do souboru. Čísla potřebují trochu více péče, protože metoda read() vrací pouze řetězce, které mohou být předány funkcím jako string.atoi(), která vezme řetězec jako '123' a vrátí jeho číselnou hodnotu 123. Když budete chtít zapisovat komplexnější datové typy jako seznamy, slovníky nebo instance tříd, pak se věci stanou ještě složitějšími.

Než aby museli uživatelé neustále psát a ladit kód pro ukládání složitějších datových typů, nabízí Python standardní modul nazývaný pickle. Toto je úžasný modul, který umí zkonvertovat většinu objektů jazyka Python (včetně některých forem kódu!) na řetězcovou reprezentaci. Tento proces se nazývá pickling. Rekonstrukce objektu z řetězce se překvapivě jmenuje unpickling. Mezi pickling a unpickling může být řetězcová reprezentace objektu uložena do souboru nebo třeba zaslána po sítí vzdálenému počítači.

Jestliže máte objekt x a souborový objekt f otevřený pro zápis, pak je možné ho jednoduše uložit jedinou řádkou kódu:

pickle.dump(x, f)

Pro načtení objektu zpět použijeme kód (za předpokladu že souborový objekt f je otevřen pro čtení):

x = pickle.load(f)

(Existuje více variant používaných při zápisu více objektů nebo nebo při ukládání pickled dat do řetězce. Kompletní dokumentaci modulu pickle získáte v dokumentu Python Library Reference.)

pickle je standardní cestou, jak vytvářet objekty jazyka Python, které mohou být uloženy a znovu použity jiným programem. Pro takové objekty se používá termín perzistentní objekt. Protože je modul pickle široce používán, mnoho autorů, kteří píší rozšíření jazyka Python, dbá na to, aby nové datové typy (jako matice apod.) bylo možné snadno ukládat a načítat zpět právě pomocí modulu pickle.

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