2013. április 18., csütörtök

04 - Beolvasás, kiírás

Még mielőtt akárminek is nekikezdenék, szeretném jelezni, hogy igazodva a kor igényeihez, ez a bejegyzés 2016. március 5-én újraírásra került. Az eredeti bejegyzés még a Python 2.7.3 használatával készült, és átkozott hosszú volt. Azóta gyakorlatilag az összes jelentős csomag Python 3 kompatibilis verziója elkészült, és magam is napi rendszerességgel Python 3 nyelvű fejlesztéssel foglalkozok.

Mostanra már mindent tudunk a változókról, operátorokról, kifejezésekről, viszont úgy gondolom, hogy kezd elég unalmas lenni, hogy a programjaink csak úgy lefutnak oszt’ csá. Szóval ebben a részben megnézzük hogy hogyan lehet olyan programot írni, ami képes adatot fogadni a felhasználótól. A bejegyzés másik felében pedig kicsit részletesebben is átvesszük, hogy mire is képes a már korábban elég sűrűn használt print().

Na akkor toljuk, mert sok a teendő.

Adat beolvasása a felhasználótól

Ahhoz hogy a programunk megálljon egy adott ponton, és várjon arra hogy begépeljünk valamit, egy függvényt kell használnunk, ez az input().

Amikor a program futása az input() függvény hívására érkezik, a program egész addig fog állni és várni, amíg Enter billentyűt nem nyomunk. Ekkor megkapjuk a programunkban a begépelt szöveget, ami minden esetben kizárólag str típusú lesz. Igen, akkor is, ha számjegyeket írtunk be.

Oké, akkor lássuk hogy hogy is működik ez:

username = input()
print(username)

Elindítjuk a programot a konzolban, és a villogó kurzoron kívül nem látunk mást. Látszólag olyan mintha lefagyott volna a program, pedig valójából csak várja hogy begépeljünk valamit. Írjunk be bármilyen tetszőleges szöveg, és a végén nyomjunk Enter-t. A gépelésünk alatt azonnal megjelenik még egyszer a szöveg, és kilép a program.

Lássuk tételesen hogy mi történt:

  1. A program futása az input()-ra érkezett. Itt várakozott a program.
  2. Lenyomtuk az Enter-t, így véget ért a várakozás. Az input() vissza tért a begépelt szöveggel, amit az értékadó operátor eltárolt az username nevű változóban
  3. A 2. sorban a print() kiírta a username változó értékét, ami pont a begépelt szöveg.

Függvényhívás röviden

Bár ez a bejegyzés nem a függvényekről szól, de hát ugye már itt a print() és most az input() is. Tehát mi ez a függvényesdi?

A függvényeket arról lehet felismerni, hogy hasonlóan kell leírni a nevüket mint egy változóét, de a végükre zárójelet kell tenni. A print() esetén már láttuk korábban, hogy a zárójelek közé beírhatunk kifejezéseket is. Azzal hogy leírtuk a zárójelet, megtörténik a függvény hívás.

A függvények működéséről egyelőre elég annyit tudni, hogy valamilyen forráskódot rejtenek magukban. Ez a forráskód várhat különböző adatokat. Ezen adatokat soroljuk fel a zárójelek közé írva, és argumentumnak hívjuk őket. A függvény a futása mindig eredményez valamilyen adatot, amihez hozzáférünk majd ott, ahol meghívtuk a függvényt. Ezt az adatot hívják visszatérési értéknek.

Ezt mondhatjuk úgy is, hogy a függvényhívás mint kifejezés kiértékelésének eredménye a függvény visszatérési értéke.

Hogy hívnak?

Sokkal értelmesebb lenne a fenti program, ha először kérdezne, és csak aztán várakozna a program. Akkor írjunk egy olyan programot, ami megkérdezi a felhasználótól a nevét, és utána illedelmesen köszönti.

print('Hogy hívnak?')
name = input()
print('Szia ' + name)

A program először kiírja a Hogy hívnak? üzenetet, majd kurzor leugrik a következő sorra és várja hogy beírjunk valamit. Ez eltárolódik majd a name változóban. A print()-ben pedig jól kiírjuk a begépelt nevet, és még az elejére ragasztjuk azt hogy Szia.

Rövidebb forma

Az a művelet-kombináció elég gyakori, hogy ha be akarunk olvasni valamit a felhasználótól, akkor előtte kiírunk egy üzenetet. Pontosan ezért, az input() paraméterül kaphat egy kifejezést, praktikusan egy str-t, amit először kiír úgy mint a print(), és csak utána kezd várakozni a begépelésre. Nem mellékesen ilyenkor rögtön a kiírás mellett villog a kurzor, ami esetenként szebb, mint ha tök új és üres sorba gépelnénk.

Akkor írjuk át a fenti példát:

name = input('A neved: ')
print('Szia ' + name)

Figyeljetek rá, hogy a kiírt string végén legyen szóköz, máskülönben tök hülyén fog kinézni a konzolban, hogy nem látszódik hogy hol ért véget az a szöveg amit a program írt ki, és az amit a felhasználó kezdett beírni.

Számológép

Írjunk egy olyan egyszerű számológépet, ami beolvas két számot, összeadja őket és kiírja az eredményt. Mi sem egyszerűbb ennél:

a = input('Első szám: ')
b = input('Második szám: ')
c = a + b
print('Az összeg: ' + str(c))

Az első két sorban kiírogatjuk a formai dolgokat. Az első szám az a, a második szám pedig a b nevű változóban kerül eltárolásra. Összeadjuk ennek a két változónak az értékét és eltároljuk az eredményt a c változóban. A program végén pedig kiírjuk hogy Az összeg:. Fontos: mivel ugye c változó számot tartalmaz, ezért ezt először át kell alakítani str-é, hogy elé tudjuk rakni a kis feliratot. Ha ezt nem tesszük akkor hibát kapunk.

Akkor most beírok két számot, nálam ez történik:

Első szám: 5
Második szám: 6
Az összeg: 56

Az meg mi a lófasz hogy 56?

Típuskonverzió

Aki esetleg elfelejtette, az input() mindig string típusú értéket eredményez. Tehát hazudtam az előbb amikor azt írtam hogy “… mivel ugye a c változó számot tartalmaz …”. Az is, meg az a és a b is végig str-ek voltak.

Ha összeadunk két str-t akkor mit kapunk? A két stringet eggyé fűzve. Pontosan ezért tud megjelenni az 56 a képernyőn, ami a memóriában valójából '56', és nem 56 !

Ahhoz tehát hogy számként dolgozhassunk a kapott adattal azt számmá kell alakítani.

Számológép ami számol is

A fentiek szellemében javítsuk ki a programot. Feltételezzük hogy int (egész) értéket kapunk majd:

a = int(input('Első szám: '))
b = int(input('Második szám: '))
c = a + b
print('Az összeg: ' + str(c))

És tápoljunk be pár értéket:

Első szám: 5
Második szám: 6
Az összeg: 11

Na erről van szó kérem szépen.

Lehet elsőre émelyítő ez a sok zárójel az 1. és 2. sorban, de a Pythonnak ez meg se kottyan. Ahogy korábban írtam, a legtöbb kifejezés egymásba ágyazható. Amit a kódban írtam igen gyakori, tehát hogy a típuskonverziót végző függvény egyből megkapja argumentumul az input() visszatérési értékét.

Első szám: kettő

Nekem elhihetitek, mindig van valaki aki poén adatokat írogat be a programba. Ha most mi is így teszünk, és az első kérdésre nem számjegyeket, hanem valami szöveget, sőt, egy törtet írunk be, akkor a program kilép hibával, és valami ValueError-t lehel ki utolsó lélegzetéből.

Ezzel egyelőre nem foglalkozunk, de lehet lelkiekben készülni arra, hogy ahhoz hogy ne lehessen csak úgy összeomlasztani a programunkat, kezelnünk kell az ilyen nagyon vicces eseteket is. A tételmondat tehát:

Sose bízz meg abban amit a felhasználó begépel.

Mert mindig szétkúrják amit csinálsz.

Igazából a valóságban többnyire nem szándékosan rontják el a másik játékát, hanem mondjuk azért mert olyan formátumba írták be az adatot amire nem voltunk felkészülve. A tört számok elfogadása teljesen reális igény lenne a mostani programunktól, mi mégis feltételeztük hogy egész számot kapunk.

Kiírás

Sokat használtuk (és még fogjuk is) már a print() függvényt, de nem volt még rendes bemutatkozó fejezete, úgyhogy akkor most csak róla fogunk beszélni.

A print() egy olyan függvény, ami kiír mindent a standard outputra, (stdout, standard kimenet) amit argumentumul kap. Amikor konzolból fut a programunk, akkor ez a kimenet alapértelmezetten maga a konzol, hiszen ott jelenik meg a szöveg.

Nem véletlenül vezettem be az stdout fogalmát: bár egy jó ideig minden kiírás a konzolban jelenik meg, át lehet állítani, hogy a standard kimenet egy fájl legyen, vagy a memória, és ez tök izgi.

Ha a print() a standard outputra ír, akkor az input() a standard inputról olvas? Igen, sőt, létezik egy hibakimenet is, amit standard errornak hívnak. Ezek hárman az stdout, stdin és az stderr.

Azt hogy egy egyszerű kifejezést hogy írunk ki már nem mutatom be. Vegyünk néhány érdekesebb dolgot inkább.

Több érték kiírása

Eddigi példáinkban a print() mindig egy értéket kapott argumentumul (és ha például egy szöveget és utána egy számot akarunk kiírni, akkor ezeket először valahogy mindig egymáshoz illesztettük), de ez a függvény tetszőleges mennyiségű argumentum fogadására képes, és ezeket mind egyszerre, szóközzel elválasztva ki tudja írni a képernyőre. Ahogy minden más felsorolást is a Python nyelvben, úgy az argumentumokat is vesszővel elválasztva kell felsorolni.

Tekerjünk vissza a számológépes példára és írjuk át ennek szellemében:

a = int(input('Első szám: '))
b = int(input('Második szám: '))
c = a + b
print('Az összeg:', c)

Az utolsó sor változott csak, és szerintem sokkal természetesebb is így a forráskód: a print() először írja ki a szöveget, aztán a c változó értékét. Magától, impliciten str-é változik mindenki.

Ha lefuttatjuk ezt a programot, pontosan ugyan úgy jelenik meg minden, mint az eredeti példa esetén.

Kiírás ugyan abba a sorba

A print() a neki adott értékeken kívül a dolga végeztével mindig kiír egy láthatatlan vezérlőkaraktert, ami miatt a kurzor a konzolban új sorba ugrik, annak is az elejére (tehát olyan, mintha a print() “nyomna egy Enter-t”). Ezt a karaktert ezerféleképp hívják, angolul new line vagy line feed, magyarul soremelés vagy sortörés. (Ebben a bejegyzésben ennyit elég is tudni róla.)

Ha nem akarjuk hogy a print() a kiírás végén új sort kezdjen, akkor felül kell definiálni ezt a karaktert. Nagyon egyszerű, így néz ki:

print('Első szám: ', end='')
a = input()

Bizony, a print() zárójelei közé felsorolást kell írni, és a legutolsó helyen az end=''-nek kell állnia. Ez az end pont úgy néz ki mint egy változó, viszont sehol sincs definiálva. Semmilyen varázslat nem történik itt, az end valójából a “print()-ből jön”, ahhoz tartozik (keyword argumentnek vagy opcionális argumentumnak hívják). Ennél többet nem is kell egyelőre tudni ennek a működéséről.

Ne zavarjon az end='' abban hogy tetszőleges felsorolást írja a print()-be, csupán arra figyelj, hogy a felsorolás legvégén álljon ez az argumentum.
Így eu például teljesen rendbe van: print('Az összeg:', c, end='')

Azt is vegyük észre, hogy az end='' azt jelenti, hogy az end argumentum értékét üres stringre állítjuk a függvény számára.

Van visszatérési értéke a kiírásnak?

Ha minden függvénynek van visszatérési értéke, és az input() esetén ez a begépelt szöveg, akkor egyébként a print() függvénynek mi a visszatérési értéke?

Nincs semmi különös visszatérési értéke, csak a semmi, azaz a None. Írjuk ki:

print(print('Hello World'))

Először megjelen a Hello World majd alatta a None, ami ugye azért történt, mert először a belső kifejezés értékelődött ki, ami kiírta a szöveget a standard outputra, és visszatért a None-al. Ezt pedig a külső kifejezés kiírta.

Zárás

Zárásképp írjuk át a számológépet úgy, hogy az Összeg: felirat helyett jelenjenek meg a begépelt számok, és a műveleti jelek is.

a = int(input('Első szám: '))
b = int(input('Második szám: '))
print(a, '+', b, '=', a + b)

Futtassuk:

Első szám: 5
Második szám: 6
5 + 6 = 11

Szép ez meg jó ez, de eskü’ több a körítés a print()-ben mint a szöveg amit ki akarunk írni. Rövidesen visszatérünk erre a problémára, és imádni fogjátok a megoldást, de a következő részben végre megtornáztatjuk a számítógépet, mert elkezdünk vezérlési szerkezeteket írni.

Ez a bejegyzés a Python tutorialom egyik része. Az összes rész listája itt fellelhető.

-slp