Níže uvedený text pochází z prvního vydání. Nad tímto textem se nachází aktuální stav po revizi směřující k druhému vydání.

Konverzace s uživatelem

O čem si budeme povídat?

Řekneme si, jak máme dát uživateli najevo, že má vložit data, a jak je můžeme přečíst poté, když je vložil. Ukážeme si načítání jak numerických dat, tak řetězců. Podíváme se také na to, jak můžeme získat údaje, zapsané v podobě parametrů na příkazovém řádku při spuštění programu.

Naše programy zatím používaly pouze statická data. Taková data jsme mohli, pokud jsme to potřebovali, prozkoumat ještě před spuštěním programu, takže jsme program mohli napsat tak, aby jim vyhovoval. Ale většina programů taková není. Většina programů očekává, že budou řízeny uživatelem. Přinejmenším očekávají, že jim uživatel sdělí jaký soubor mají otevřít, upravit jeho obsah a podobně. Jiné programy si v kritických místech od uživatele vyžádají vstup dat. Než půjdeme dál, ukážeme si, jak se toho dá dosáhnout.

>>> print raw_input("Něco napište: ")

Jak můžete pozorovat[1], raw_input jednoduše zobrazí zadanou výzvu a zachytí vše, co uživatel napíše jako odpověď. Příkaz print pak tuto odpověď zobrazí. Odpověď bychom ale mohli místo zobrazení přiřadit do proměnné:

odpoved = raw_input("Jak se jmenuješ? ")
print "Tak ty se jmenuješ %s! Jsem rád, že jsem tě poznal." % odpoved

Příkaz raw_input má bratrance jménem input. Rozdíl spočívá v tom, že raw_input sesbírá uživatelem napsané znaky a chápe je jako textový řetězec, zatímco input se z nich bude snažit vytvořit číslo. Pokud například uživatel napíše znaky '1', '2' a '3', pak input tyto tři znaky přečte a převede je na číslo 123.

Použijme nyní příkaz input k tomu, aby uživatel rozhodl, která tabulka násobků se má tisknout:

nasobitel = input("Vyberte hodnotu násobitele: ")
for j in range(1, 13):
    print "%d x %d = %d" % (j, nasobitel, j * nasobitel)

Použití příkazu input je naneštěstí velmi záludné. Je to dáno tím, že input se nesnaží vyhodnocovat jen čísla, ale snaží se na libovolný vstup pohlížet jako na kód v jazyce Python a snaží se jej provést. To znamená, že by znalý uživatel se zákeřnými úmysly mohl napsat příkaz jazyka Python, který by například vymazal nějaký soubor na vašem PC! Z tohoto důvodu bude lepší, když se budete držet příkazu raw_input a výsledný řetězec si budete převádět na potřebný datový typ použitím zabudovaných konverzních funkcí jazyka Python. Ve skutečnosti je to velmi jednoduché:

nasobitel = int(raw_input("Vyberte hodnotu násobitele: "))
for j in range(1, 13):
    print "%d x %d = %d" % (j, nasobitel, j * nasobitel)

Vidíte? Volání raw_input jsme jednoduše obalili voláním int. Efekt je stejný, jako kdybychom použili input, ale je to mnohem bezpečnější. Existují i jiné konverzní funkce, takže uživatelský vstup můžete stejně dobře převádět na reálná čísla a na další typy.

Vstup v jazyce BASIC

V jazyce BASIC se vstup zadávaný uživatelem čte příkazem INPUT. Takže můžeme psát:

INPUT "Vyberte hodnotu násobitele: ";M
FOR J = 1 to 12
    PRINT M "x" J "= " M*J
NEXT J

Jak vidíte, velmi se to podobá vstupu v jazyce Python až na to, že proměnnou uvádíme až na konci příkazu. BASIC navíc používá INPUT jak pro načítání čísel, tak pro řetězce. Příkaz INPUT má obvykle ještě některé další vlastnosti, proto byste u každé verze jazyka BASIC měli nahlédnout do příslušné části dokumentace.

Čtení vstupu v Tcl

Tcl má svůj vlastní mechanismus vstupu založen na souborech (které zahrnují i standardní vstupní a standardní výstupní soubor) a na příkazu zvaném gets. Ten načítá vstup z předepsaného souboru. V našem případě to bude stdin.

Poznámka: Následující program nebude pracovat, pokud se jej budete snažit zadat ze standardního příkazového řádku tclsh80 nebo wish80. Místo toho jej budete muset napsat do souboru (řekněme input.tcl) a spustit jej z příkazového řádku:

    C:\PROJECTS\Tcl>tclsh80 input.tcl

Tcl verze našeho programu vypadá nějak takto:

puts -nonewline stdout "Vyberte hodnotu násobitele: "
flush stdout
set nasob [gets stdin]
for {set j 1} {$j <= 12} {incr j} {
    puts [format " %d x %d = %d" $j $nasob [expr $nasob * $j] ]
    }

Volba -nonewline příkazu puts zabrání kurzoru, aby se po zobrazení výzvy přesunul na další řádek. Příkaz flush donutí standardní výstup stdout aby svůj obsah zapsal ihned — tím zajistíme, aby se objevil na obrazovce. Cyklus for je téměř shodný s verzí, kterou jsme viděli, když jsme se bavili o cyklech.

Pár slov o stdin a stdout

Poznámka: Slovem stdin se v žargonu označuje standardní vstupní zařízení (obvykle klávesnice). Abychom mohli využít kód pro práci se soubory, je to zařízeno tak, aby se standardní vstupní zařízení chovalo jako soubor.

V systému Python je stdin součástí modulu sys a nazývá se sys.stdin. Funkce raw_input() používá stdin automaticky. Tcl může číst z libovolného souboru příkazem gets (což je zkratka pro getstring). Totéž můžeme zapsat i v jazyce Python. Vyzkoušejte:

import sys
print "Zadej hodnotu: ",       # čárka zabrání přechodu na další řádek
hodnota = sys.stdin.readline() # explicitní použití stdin
print hodnota

Funkčnost se téměř shoduje s chováním příkazu:

print raw_input("Zadej hodnotu: ")

Výhodou explicitního použití stdin je to, že standardní vstup můžeme svázat se skutečným souborem, takže program svůj vstup nebude číst z klávesnice, ale z daného souboru. Tento obrat je užitečný při realizaci dlouhých testů programu, kdy místo ručního vkládání vstupních údajů v okamžiku, kdy je program požaduje, necháme vstup přečíst z předem připraveného souboru. (Další výhodou je v takovém případě skutečnost, že test můžeme spouštět opakovaně, přičemž jsme si jisti, že vstup bude pokaždé stejný, takže by tomu měl odpovídat stejný výstup. Tuto techniku opakovaného spouštění dřívějších testů, které mají ověřit, že se nic nepokazilo, programátoři nazývají regresní testování.)

Na závěr uveďme, že existuje i 'soubor' sys.stdout, který můžeme rovněž přesměrovat — tentokrát do fyzického souboru. Příkaz print můžeme zapsat jako:

sys.stdout.write("Ahoj, vy tam!\n") # \n = nový řádek

Pokud tedy stdout nebude svázán s obrazovkou, zapíše se výstup do souboru. Tímto způsobem fungují i příkazy operačního systému, pokud u nich na příkazovém řádku zapíšeme přesměrování do souboru:

C:\> dir
C:\> dir > dir.txt

První z příkazů tiskne obsah adresáře na obrazovku. Druhý tiskne do souboru. Použitím znaku > programu říkáme, že chceme stdout přesměrovat do souboru dir.txt.

Parametry z příkazového řádku

Další typ vstupu představuje příkazový řádek. Dejme tomu, že nějak takto spustíte svůj textový editor:

EDIT Foo.txt

Jak editor zjistí jméno souboru?

Ve většině jazyků systém poskytuje pole nebo seznam řetězců, které obsahují slova z příkazového řádku. Takže první prvek bude obsahovat jméno příkazu, druhý prvek bude obsahovat první argument, atd. Obvykle máme k dispozici nějakou magickou proměnnou, ve které je uložen počet prvků uvedeného seznamu.

V systému Python je zmíněný seznam součástí modulu sys a nazývá se argv (z anglického argument values, čili hodnoty argumentů). Obsah prvků můžeme získat odkazem přes index nebo iterací, čili postupným průchodem, přes jednotlivé prvky seznamu. Můžeme tedy psát:

import sys
for polozka in sys.argv:
    print polozka
    
print "První argument byl:", sys.argv[1]

Poznamenejme, že to bude fungovat jen v případě, kdy uvedený kód uložíte do souboru (dejme tomu args.py) a spustíme jej z příkazového řádku operačního systému, například takto:

C:\Python\Projekty> python args.py 1 23 fred
args.py
1
23
fred
První argument byl: 1
C:\Python\Projekty>

Příkazový řádek Tcl

Tcl používá podobný přístup se třemi proměnnými:

V Tcl zapíšeme příklad demonstrující přístup k argumentům z příkazového řádku takto:

puts "Příkaz byl: $argv0" 
puts "První argument byl: [lindex $argv 0]"

A opět — uvedený kód budeme muset spustit jako skript (musí být umístěn v souboru) z příkazového řádku operačního systému s tím, že současně zadáme nějaké argumenty.

A v jazyce BASIC

Zatímco u Tcl se ukazuje, že nemá ekvivalent příkazu input, zdá se, že BASIC zase nemá ekvivalent argv. I když k zpřístupnění argumentů z příkazového řádku by bylo možné využít vlastností operačního systému. Tak například hodnoty argumentů jsou uloženy v proměnných prostředí (environment variables), takže je můžeme získat použitím funkce GETENV. Z pohledu tohoto kurzu však již jde o příliš pokročilou tématiku. Doporučuji, abyste se v BASICovských programech na hodnoty vyptávali uživatele interaktivně.

A to je k tématu uživatelského vstupu opravdu vše, co budeme v tomto kurzu potřebovat. Je to sice velmi primitivní, ale přesto s tím vystačíte při psaní užitečných programů. V počátcích systému Unix nebo u prvních osobních počítačů představovala tato podoba interakce s uživatelem jedinou dostupnou možnost. V jazycích Python, Tcl a BASIC (ve své inkarnaci označované jako Visual) lze psát i náročné programy s grafickým uživatelským rozhraním, s okny, s dialogy, atd…, ale to je pro tento kurz příliš pokročilá tématika. V případové studii si přesto ukážeme krátký příklad uživatelského vstupu s grafickým uživatelským rozhraním, zapsaný v jazyce Python. Ale nebudeme si vysvětlovat detaily toho, jak to funguje. Jakmile na solidní úrovni zvládnete základy, můžete se zaměřit na webové kurzy, které se touto problematikou zabývají. Některé z nich uvedu na stránce s odkazy na literaturu.

Zapamatujte si

Pokud vás napadne, co by se dalo na překladu této kapitoly vylepšit, zašlete e-mail odklepnutím tohoto odkazu. Tím bude do subjektu dopisu automaticky vložena informace o jméně a verzi tohoto HTML dokumentu.

$Id: cztutinput.html,v 1.2 2004/05/14 10:22:46 prikryl Exp $