2013. január 29., kedd

03 - Operátorok, kifejezések, utasítások

Még mielőtt akárminek is nekikezdenék, szeretném jelezni, hogy igazodva a kor igényeihez, ez a bejegyzés 2016. február 26-án újraírásra került. Az eredeti bejegyzés még a Python 2.7.3 használatával készült. 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.

Ideje folytatni az előző bejegyzésben elkezdett témát. Hogy kerek legyen a történet, foglalkozzunk kicsit az operátorokkal.

Mik azok az operátorok?

Az operátorok olyan elemi műveletek amikre a programozási nyelv képes. Amikor programot írunk, akkor ezeknek az egyszerű műveleteknek a véges sorozatát írjuk le. Ahhoz pedig hogy abból egy jól működő program legyen csupán a logikánkat kell majd használni.

Már az előző bejegyzésben is találkoztunk pár operátorral, ilyen volt a =, vagy a +. Ezek ismerősek lehetnek a matek órákról, nem véletlenül: a legtöbb matematikai művelethez létezik operátor a Pythonban. Az operátoroknak általában két kifejezéssel dolgoznak: az egyik az operátor bal, a másik a jobb odalára kerül. Ezeket a kifejezéseket operandusoknak hívják.

Nem kell a matek szótól hirtelen pánikot kapni, a programozás Pythonban nem egyenletmegoldásokról szól. Részemről, amikor programozok, vannak olyan napjaim, amikor a legbonyolultabb matematikai kifejezés amit írnom kell az egy egyszerű összeadás. A többi napon még annyi sincs.

Aritmetikai operátorok

Aritmetikai műveletek általában azok amiket számokon értelmezünk. Pythonban ez a fogalom jócskán ki van bővítve, mert objektumokon is értelmezhetőek egyes operátorok. Erről majd később beszélünk egyszer.

Lássuk a leggyakoribb operátorokat:

  • =
    Értékadás (assignment). Vele már találkoztunk az előző részben, most akkor beszéljünk kicsit a működéséről is. Az értékadás mindig jobbról-balra történik, azaz a jel jobb oldalán álló kifejezés eredménye bekerül a bal oldalon álló változóba.
  • +
    Összeadás (add). Konstansok, változók értékeit adatjuk össze vele, de összefűzést is jelent (ahogy az előző részben azt be is mutattam).
  • -
    Kivonás (substract). Erről nem is érdemes többet beszélni.
  • *
    Szorzás (multiply).
  • /
    Osztás (divide). Két int osztása egy float-ot eredményez, még akkor is, ha az eredmény amúgy kerek, nem tört (így tehát ez a való osztás, és mellékesen itt implicit típuskonverzió történt). Bár mára ez már történelem, de anno a Python 2-ben ez az operátor mindig int-et eredményezett, tehát szépen lehagyta a törtet az eredményről.
  • //
    Egész osztás (integer division). Ha ennek az operátornak mindkét oldalán int szerepel, akkor az eredménye is int típusú lesz, még akkor is, ha az eredménye amúgy nem egész. Ilyenkor a törtrész elhagyásra kerül. Tehát a 11 // 2 értéke 5. Negatív számoknál kicsit trükkösebb, mert a -11 // 2 eredménye -6. Tehát valójából az érték lefelé, a kisebb érték felé kerekítődik.
  • %
    Maradék képzés (modulo vagy remainder). Ez az operátor azt mondja meg, hogy két tört osztásának mennyi a maradéka. Aki régen osztott papíron az lehet már elfelejtette hogy mi is az pontosan, úgyhogy itt egy példa:

    7'1'3 : 2 = 356
    1 1 
      1 3
        1  <- Ezt a számot kapjuk eredményül

    A színezésre ne figyeljetek
    Mire jó ez az operátor? Például arra, hogy eldöntsük jól egy számról, hogy páros-e vagy páratlan (ha a maradék 1 akkor páratlan, amúgy páros).

  • **
    Hatványozás (power). Az operátor bal oldalán a hatványalap, jobb oldalán a hatványkitevő áll.

A fenti operátorokkal egy csinos kis számológéppé léptettük elé a Pythont.

Logikai operátorok

Mint ismeretes, a számítógépek a bűvös kettes számrendszert használják. Egyesek és nullák, régi történet. A logikai műveletekkel gyakorlatilag egyértelműen eldönthető kérdéseket teszünk fel a számítógépre, amire ő igennel vagy nemmel tud felelni, vagy inkább igazzal vagy hamissal, ami angolul True vagy False, számítosítva meg 1 és 0. Meg is érkeztünk a kettes számrendszerhez.

Az ilyen kérdésekre (hívjuk feltételeknek) kapott válaszokkal tudunk dolgozni. Nézzük milyen operátorok tudnak segíteni ebben:

  • ==
    Egyenlőség (equal). Logikai értéke True ha a két kifejezés egyenlő. Így vizsgálhatjuk hogy egy változó érték egyelnlő-e egy értékkel, és hasonlók.
  • !=
    “Nem egyenlőség” (not equal). Tehát ez az operátor arra ad választ, hogy a bal- és jobb oldala különböző-e.
  • >
    Nagyobb (greater). Avagy a jó öreg kacsacsőr. Akkor eredményez True-t, ha a bal kifejezés nagyobb mint a jobb.
  • <
    Kisebb (less). Akkor eredményez True-t, ha a bal kifejezés kisebb mint a jobb.
  • >=
    Nagyobb egyenlő. Akkor eredményez True-t, a a bal kifejezés nagyobb vagy egyenlő a jobb oldalival. A félreértések elkerülése végett, bár ez két karakter, egyetlen operátort jelöl, tehát nem lehet helyette olyat írni hogy =>, mert az nem létezik.
  • <=
    Kisebb egyenlő. Akkor eredményez True-t, ha a bal oldali kifejezés kisebb vagy egyenlő a jobb oldalival. Ugyan az igaz az írására, mint a >= esetén.
  • or
    “Vagy”. Bizony, ezt normális latin betűkkel, és nem hieroglifákkal kell írni. Akkor eredményez True-t, ha a két oldalán álló kifejezések közül bármelyik True. Ez akkor jön majd jól, ha olyan algoritmust írunk aminek a futása több dologtól is függ, de elég, ha azok közül legalább egy logikailag igaz.
  • and
    “És”. Akkor eredményez True-t, ha mindkét kifejezés az oldalán True. Ez meg majd akkor jön jól, ha olyan algoritmust írunk, aminek a futásához egyszerre mindennek klappolnia kell, tehát mindenkinek logikailag igaz értékkel kell rendelkeznie.
  • not
    “Nem”. A logikai kifejezés tagadása, negációja. A többiekkel ellentétben ez egy egy operandusú művelet, tehát ennek csak a jobb oldalára kell írni kifejezést. True-ra False-t, False-ra True-t eredményez.

Ezzel véget ért egyelőre a felsorolás, de még akadnak más operátorok is a Python nyelvben. Elég csak az előző részben említett index operátorra gondolni. Ezeket az operátorokat a rájuk jellemző adatstruktúrákkal együtt ismertetem, így lehet majd mihez kötni őket.

Ezeket az operátorokat ugyan úgy írhatjuk kifejezések közé, mint az aritmetikaiakat, de ne felejtsük el, hogy ezek mindig valamilyen bool típusú értéket eredményeznek. Lássunk egy rövid példát:

print(1 == 2)
print(1 > 0 and 1 > -1)

Ha ezt lefuttatjuk, akkor először a False majd a True üzenet jelenik meg a konzolban. Ez teljesen logikus, hisz nem igaz hogy az 1 egyenlő lenne a 2-vel, viszont az igaz, hogy az 1 nagyobb mint a 0 és az 1 nagyobb mint a -1.

Igazságtáblák

A logikai operátoroknak elég jól behatárolt, és nagyon kevés bemenete és kimenete létezik, ezért ezekett táblázatokba szokták gyűjteni, ez az igazságtábla. A fenti utolsó 3 operátor igazságtáblái ezek:

or

A B A or B
False False False
False True True
True False True
True True True

and

A B A and B
False False False
False True False
True False False
True True True

not

A not A
False True
True False

Rövidzár

Az and és az or operátorok képesek a rövidzárásra (short circuit). Ez azt jelenti, hogy ha az első operandus alapján biztos a művelet eredménye, akkor a második operandus nem kerül kiértékelésre. Nézzünk néhány példát:

True or print('Második operandus')
False and print('Második operandus')

Ha ezt a programot lefuttatjuk, akkor a konzolban semmi se jelenik meg. A szerint amit feljebb írtam, az első sorban az or első paramétere alapján már biztos hogy True lesz az eredmény, így a futás rá se ugrik a print()-re.
A második sorban, ha az and első operandusa False akkor biztos hogy False lesz az eredmény, és nem is kerül futtatásra a print().

Ez egy fontos tulajdonság, és nagyon hasznos tud lenni olyan szituációkban, amikor olyan kifejezést írunk, amikor tilos a második operandus kiértékelése akkor, ha az első nem teljesült.

Kifejezések

Az előző jó néhány bekezdésben gyakran jelent meg a kifejezés fogalma. Ennyi szöveg után ideje ezt is elamgyarázni.

A kifejezések a forráskód elemi részei. Egyesek egymásba is ágyazhatóak, tehát léteznek összetett kifejezések.

Ahogy leírjuk egy Python fájlban azt hogy:

number = 1 + 2

Úgy valójában 4 kifejezést hoztunk létre:

  1. Vettük az 1 mint konstans kifejezést
  2. Vettük a 2 mint konstans kifejezést
  3. Előállítottunk egy újabb kifejezést úgy, hogy alkalmaztuk az összeadás műveletét a két konstansra.
  4. Az előbb létrejövő kifejezés eredményét (ami az összeadás eredménye) az értékadó operatár eltárolta a number nevű változóban.

Ha ezt realizáltuk, akkor látható, hogy szinte végtelen mélységig pakolgathatóak egymásba a kifejezések, egyáltalán nem kötelező változókba pakolászni részeredményeket. Egy kérdés maradt már csak: ha egy sornyi kifejezést írok le, milyen sorrendben kerülnek kiértékelésre?

Kiértékelési sorrend

A kiértékelési sorrend (order of operations), avagy erősebb kutya baszik, olyan dolog, amivel soha többé nem találkozik az ember az általános iskola után, egész addig, amíg a Facebookon már megint fel nem bukkan egy olyan furmányos talány hogy:

7 - 1 * 0 + 3 / 3 = ?

Az emberek 74%-a hibás eredményt az erre az egyszerű kérdésre.

Akkor most tápoljuk be egy programba:

print(7 - 1 * 0 + 3 / 3)

Az eredmény természetesen 8. Hogy miért? Mert a számítógép soha nem bassza el.

A programozási nyelvekben, így a Pythonban is, a kifejezések kiértékelési sorrendje balról jobbra történik, és bentről kifelé, pont úgy, ahogy a matematikában. Egyes operátorok előnyt élveznek a többiekkel szemben. A sorrend (először a legerősebb, végül a leggyengébb):

  1. **
  2. *, /, //, %
  3. +, -
  4. <, <=, >, >=, !=, ==
  5. not
  6. and
  7. or

Így már teljesen világos hogy miért is 8 az eredmény.

A zárójel

Ahogy a matematikában, úgy a programozásban is előfordul, hogy ki akarjuk kényszeríteni a kifejezések kirétékelési sorrendjét. Ez megszűnteti az olyan problémákat is, mint hogy ki a faszom emlékezett arra, hogy a szorzás előbb következik mint az összeadás.

Zárójelet bárhol alkalmazhatunk a kifejezésben. Írjuk át a fentit hogy egyértelmű legyen:

print(7 - (1 * 0) + (3 / 3))

Ó, hát persze, 1 * 0 az 0, ezt minden hülye tudja!, 3/3 az 1. És akkor 7 - 0 + 1 az 8.

Zárójelet használni semmibe se kerül, cserébe megelőz minden félreértésből adódó problémát. Nem kell spórolni vele.

Önmarágra hivatkozó változó

Kiemelném azt az esetet, amikor az értékadás mindkét odalán ugyan az a változó szerepel.

Mi történik akkor ha leírjuk hogy:

number = 1
number = number + 1

Az 1. sorban csak deklaráltuk a változót. A második sorban viszont a változónak értékül adtuk saját magát úgy, hogy még 1-et hozzá is adtunk. Ez teljesen normális, hisz a jobb oldallal kezdődik a kiértékelés. Ekkor a number egy létező változó, az összeadás értelmezhető rá. A kifejezés értékét (ami 2 lesz) ez után felveszi a number.

Utasítások

Végére maradtak az utasítások. Ezek olyan kifejezések, amikből a forráskód egy sorában egy, és csak az az egy állhat, így tehát nem ágyazhatóak egymásban. Kiértékelésüket tekintve először mindig az utasítás jobb oldala kerül kiértékelésre, és csak legvégül az utasítás maga. Mindig egy operandusúak… már ha beszélhetünk operandusról, a szó szoros értelmében.

Elsőre ez eléggé szigorú megszorításnak tűnik, de ide tartozik az értékadás is. Az értékadás ugyanis nem ágyazható bele semmibe, és egy sorban nem lehet több értékadást egyszerre csinálni még ha úgy is tűnik mintha azt tettük volna.

Egyelőre tehát csak az értékadást, mint utasítást ismerjük, de rövidesen jönnek olyan finomságok, mint az elágazások, ciklusok utasításai, és akkor aztán végre elkezd úgy dolgozni a CPU ahogy kell.

Zárás

Most hogy ennyi mindent megtudtuk arról hogy mennyire jó a Python a matekból a következő részben végre bevonjuk a felhasználót is a játékba!

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

-slp

2013. január 13., vasárnap

02 - Változók, típusok

Még mielőtt akárminek is nekikezdenék, szeretném jelezni, hogy igazodva a kor igényeihez, ez a bejegyzés 2016. február 20-án újraírásra került. Az eredeti bejegyzésben még a Python 2.7.3-ba beépített típusokat ismertettem, egyébként hiányosan. 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.

Ha el szeretnénk tárolni a program futása során valami adatot a számítógép memóriájában, akkor változókat (variable) kell használnunk. A változó létrehozását deklarálásnak (declare) nevezik. Programozási nyelvtől függően lehet, hogy azt is definiálni kell, hogy milyen típusú adatot tárolnánk a változóban, mert ettől is függ a szükséges memória mérete. A Python szerencsére egy dinamikus programozási nyelv (dynamic programming language), azaz egy változó tetszőleges típusú adatot tárolhat. Viszont a Python erősen típusos nyelv (strongly typed), ami azt jelenti, hogy nem lehet csak úgy összevissza a különböző típusú adatokat egy műveletben használni.

Hétköznapibb példa lehet az, ha a változókat úgy képzeljük el, mint egy halom üres fiókot. Kinyitunk egyet, és belerakunk egy tetszőleges értéket. A fiókokat nevekkel látjuk el, így tudunk majd hivatkozni a bennük tárolt értékekre. A fiókoknak természetesen van méretük is, így akármekkora adatot nem lehet tárolni bennük.

Ebben a bejegyzésben a változók deklarálásáról, és a Python néhány beépített típusáról lesz szó.

Python típusok

Két fajtáját különböztetném meg a Python beépített típusainak. Ezek a primitívek és az objektumok. A primitív típusok egy értéket jelölnek. Ezek például a logikai értékek és a számok. Az objektumok összetett adattípusok, amik általában más, primitív típusokat kombinálnak.

Lássuk a leggyakoribb fajtákat:

A primitívek:

  • bool
    Boolean, vagy logikai érték. Ennek a típusnak pontosan két érték felel meg, a logikai igaz (True) és a hamis (False).
  • int
    Integer, vagy egész szám. Ezek tetszőleges nagyságú pozitív vagy negatív értékek, tizedesjegyek nélkül.
  • float
    Lebegőpontos szám, vagy tizedestört. Az ilyen típusú értékek néhány tizedesjegyig pontosak, és nem tudnak tetszőleges nagy egészrészt tárolni.
  • None
    A semmi. Néha bizony egy művelet végeredménye a nagy büdös semmi. Ennek a típusnak egy érték felel meg, ami stílusosan a None.

Az objektumok:

  • str
    String, vagy karakterlánc. Mindenféle szöveges érték ilyen típusú.
  • list
    Lista. Több különböző típusú adatot lehet benne egymás után felsorolva tárolni.
  • dict
    Dictionary, vagy asszociatív tömb. Ebben is több különböző típusú adatot lehet tárolni, de az adatokat saját egyedi azonosító kulccsal érhetjük el.

Azért hogy ne szabaduljon el ennek a bejegyzésnek a mérete, egyelőre a(z általam tapasztalt) leggyakoribb típusokat soroltam fel. Egy másik bejegyzésben visszatérünk még a tuple, set, bytes vagy a complex típusokra.

Most hogy tisztában vagyunk vele, hogy milyen típusú adatokkal dolgozhatunk ideje változókat is létrehozni, amibe ezek az adatok belekerülhetnek. Ahogy említettem, a dinamikus típusosság miatt az adat definiálja a változó típusát. Ha a változóba a program futása során más típusú adatot teszünk bele, akkor onnantól az lesz az érvényes.

Változók létrehozása

Változót pofon egyszerű létrehozni. Csupán annyit kell tenni, hogy leírunk egy szót, ami a változó neve lesz, és ezt egyelővé tesszük egy értékkel.

Példával sokkal egyszerűbb:

my_variable = 0

Gépeljük be a fenti sort egy új Python fájlba. Ezzel létre is hoztunk egy változót, aminek a my_variable lett a neve, és a 0 értéket tároltuk el benne. Ezt úgy is szokták mondani hogy inicializáltuk a változót.

Ha lefuttatod a fenti sort tartalmazó Python fájlt, akkor látszólag semmi se történik, mert nem jelenik meg semmi se a konzolban. A valóságban viszont létrejött a változó, megkapta az értékét, de semmi olyan utasítás nem volt ami kiírt volna akármit is, elfogyott a tennivaló is, ezért minden memóriát visszaadott a program az oprendszernek és szépen kilépett.

A változók elnevezéseinek meg kell felelniük annak a szabálynak, hogy csak az angol ABC kis- és nagybetűit, számjegyeket, valamint a _ karaktert tartalmazhatják. Ezen kívül megkötés még, hogy a változó neve nem kezdődhet számjeggyel, és nem állhat csak számokból sem.

Konkrét típusú változó létrehozása

Mivel a változó típusa a változóban tárolt érték típusával egyenlő, ezért adott értékekkel konkrét típusúvá tehetünk egy változót. A típus lehet úgynevezett explicit vagy implicit.

Explicit típusok:

  • bool := bool()
  • int := int()
  • float := float()
  • None := None
  • str := str()
  • list := list()
  • dict := dict()

A felsorolást úgy kell értelmezni, hogy ha például egy változóban int (egész szám) adatot akarunk tárolni, akkor ahhoz a változót az int()-el kell egyenlővé tenni:

my_number = int()

Implicit típusok:

  • bool := True vagy False
  • int := 0 vagy tetszőleges egész szám
  • float := 0.0 vagy tetszőleges tört szám
  • None := None
  • str := '' vagy tetszőleges szöveg, 2db aposztróf vagy idézőjel között (angolul string literal)
  • list := [] vagy tetszőleges felsorolás (angolul list literal)
  • dict := {} vagy tetszőleges kulcs-érték párok (angolul dict literal)

Ezt a felsorolást pedig úgy kell értelmezni, hogy ha például egy változóban int (egész szám) adatot akarunk tárolni, akkor a változót a 0 értékkel kell egyenlővé tenni:

my_number = 0

A fenti eseteket azért hívjuk implicitnek, mert a kézzel beírt adat alakja egyértelműen meghatározza a típust is úgy magától.

Változó értékének kiírása

Elég lehangoló hogy minden szó nélkül véget és a programunk, akármit is írunk bele, ezért egy picit előre haladunk, és megmutatom hogy hogyan lehet kiírni a konzolba egy változó értékét. Ehhez egyszerűen a print() függvényt kell alkalmazni.

my_number = 1234
print(my_number)

Ha ezt begépeljük egy Python fájlba, és lefuttatjuk, akkor a képernyőn az 1234 üzenet jelenik meg, majd kilép a program. Egyelőre elég annyit tudni tehát, hogy ha változót akarunk kiírni, akkor a print() zárójelei közé a változó nevét kell begépelni.

Primitívek

A fenti jó pár sor után bizonyára világos, hogy hogyan kell int-et létrehozni. Következzen pár rövid példa az összes típusra

bool

false_value = False
true_vale = True
int_as_false = bool(0)

Mivel kétféle logikai érték van, ezért itt rövid a példa. A False érték felel meg a hamis, és a True az igaz értéknek. A 3. sorban látható egy érdekes dolog, a 0 átalakítása logikai értékké. Ez talán még adja magát, hogy False lesz (ha kiírjuk az int_as_false értékét, akkor a képernyőn a False jelenik meg).

Vegyük ezt a példát inkább

true_or_false = bool('False')
print(true_or_false)

Ha a 'False' str-t bool-á alakítjuk, akkor mit kapunk eredményül? Meglepő lehet, de True-t.

Ennek az az oka, hogy minden tetszőleges értékhez tartozik egy-egy logikai érték is. Az ökölszabály az, hogy a 0 vagy az üres objektumok False értékűek. Minden más True.

true_or_false = bool('')
print(true_or_false)

Így jelenik meg a False a képernyőn.

int

positive = +1234
negative = -2016
print(positive)
print(negative)

Egymás alatt az 1234 és a -2016 sorok jelennek meg a konzolban. Ezen szerintem nincs sok magyarázni való.

float

one = 1.0
print(one)
print(one + 0.1 + 0.1)

Deklaráltuk a one változót, ami egy tört és az 1.0 értéket tárolja. A 2. sorban kiírtuk az értékét. A 3. sor viszont érdekes, ugyanis nem az jelenik meg a konzolban hogy 1.2 hanem hogy 1.2000000000000002. Ez nagyon szokatlan lehet, de ahogy korábban mondtam, a tört számok pontossága nem végtelen. Ahogy a kis törteket összeadjuk, összeadódik a “pontatlanság” is, és ha már kellően nagy ez az érték, akkor megjelenik a tört végén mint hiba. Az esetek nagy részében ez nem okoz gondot, hisz elég ránézni, a 16. tizedesjegynél van először hiba, de megvan az a terület (tudományos, pénzügyi), ahol ez nagyon is nem mindegy. Aggodalomra semmi ok, mert megvannak az eszközök a precíz tört műveletekre is (de ezzel jó ideig nem kell foglalkozni).

None

nothing = None

A None nem egy hosszú történet. Ez jelenti a Python-ban a “semmit”. Olyankor jöhet jól, ha szükségünk van arra, hogy létezzen egy változó, de a programban csak később teszünk valódi adatot ebbe a változóba. Vagy jelezhetünk vele hibát is (ami nem ajánlott, mert létezik rá dedikált módszer, viszont nem lehet elmenni a mellett, hogy a Pythonban beépítve is vannak olyan algoritmusok, amik akár hibát is jelezhetnek így).

Objektumok

Az objektumok, még ha egyelőre csak 3-ról is van szó, nagyon izgalmasak. Egyelőre viszont maradjunk az egyszerű dolgoknál

str

text = 'Hello World!'
text2 = "It's me speaking"
text3 = 'Magyar szöveg Python 3-ból"

Az str típusú értékeket '' (aposztróf) közé kell írni (angolul ez a string literal), ez látható az 1. sorban. Megengedett a "" (idézőjel) használata is. A '' között tetszőleges mennyiségű szöveg állhat, speciális karakterekkel, számokkal, és néhány vezérlőkarakter is megengedett.

Kilépő- és vezérlő karakterek

Vegyük azt az esetet, amikor egy str-ben aposztrófot akarunk írni. Az előző példából a text2 értékét írom át.

text2 = 'It's me speaking'

Látható ennek a kódrészletnek a színezéséből is, hogy az 'It' piros, viszont utána fekete a szöveg, és a sor végén egy árva piros aposztróf áll. Ha ezt a szöveget ilyen formában beírjuk egy fájlba, és futtatjuk, akkor SyntaxError hibát kapunk.

A probléma a miatt keletkezik, hogy egy stringet pontosan két aposztróf vagy idézőjel közé kell írni. Na most mivel a folyó szövegben volt aposztróf, így az zárta a stringet. Ami szöveg utána következik, az már kód, és a sor végén egy árva ' marad, aminek hiányzik a párja, tehát szét van burványolva az egész, nincs meg senkinek se a párja. Ezek azok a szituációk, amikor olyan karakterek vannak a stringben, amik akár forráskódnak is megfelelnek. Ezek elkerüléséhez “ki kell léptetni” (string escape) a speciális karaktereket. Ezt a \ karakterrel lehet megtenni, ami ilyenkor nem kerül nyomtatásra.

A hibás kódot így lehet javítani ezzel:

text2 = 'It\'s me speaking'

A \ a kilétető karakter, ami az utána következő egyetlen karaktert megvédi, így nem szakad meg a string. Fontos, mivel a \ mindig kiléptetést jelet, ezért ha azt akarjuk, hogy a szövegben megjelenjen ez a karakter, akkor ezt a karaktert is ki kell léptetni. Mutatom a példát:

prompt = 'C:\\Users\\'
print(prompt)

Ha ezt lefuttatjuk, akkor a konzolban megjelenik a C:\Users\ szöveg.

Ha tudjuk, hogy aposztróf lesz majd a stringben, akkor érdemes inkább idézőjelek közé írni a szöveget. Ez fordítva is igaz. Így egyszerűen csak olvashatóbb marad a forráskód.

list

A list egy felsorolt adattípus, azaz az értéke egy lista, amiben tetszőleges elemek lehetnek.

Minden programozó eljut arra a pontra, amikor felismeri hogy:

Akarok írni egy programot, és sok változó értéket akarok tárolni, de nem tudom előre mennyit. És annyira természetellenesnek tűnik deklarálni 100 változót, hogy valtozo00, valtozo01, …. . Nincs erre valami jobb megoldás?

Amikor ilyen szituációban találod magad, akkor kell list-et használni. A létrehozása nagyon egyszerű:

numbers = [1, 1, 2, 3, 5, 8, 11]
my_list = [0, [1, "eggs"], [2, "apples"]]

A numbers innentől tömb, amiben a vesszővel elválasztott számok szépen libasorban követik egymást. A my_list egy kicsit bonyolultabb már. Ebben először egy 0-ás számjegy, majd megint egy tömb van, amiben egy 1 értékű int, utána egy str következik. A tömbnek vége is van, és a my_list 3. eleme egy újabb tömb. Ez jól szemlélteti, hogy list-ben akármi, akár újabb list is lehet.

Elemek elérés

Az érdekes kérdés az, hogy oké hogy készítettem két listát, de hogyan tudom kiolvasni a lista 3. elemének az értékét? A válasz az index operátor.

numbers = [1, 1, 2, 3]
third_number = numbers[2]
print(third_number)

A fenti kód 2. sorában történik az indexelés, ami formailag annyi, hogy a változó nevének a végén szögletes zárójelek közé kell írni az elérendő indexet. A tömbök, és úgy általában a felsorolt típusok első elemének az indexe a 0. (0-based indexing). Tehát ahhoz hogy a tömb harmadik elemét elérjem, a 2. indexen levő értékre van szükségem, és ez is látható a 2. sor végén. A third_number változó pedig felveszi ezt az értéket. Tehát a numbers elemszáma nem változik.

dict

Mondjuk hogy van egy list-ünk, és ebből kellene valamilyen egyértelműen azonosítható tulajdonság alapján egy konkrét értéket kiválasztani. Ahhoz hogy ez sikerüljön olyan programot kell írni ami egyesével végignyálazza a tömb összes elemét, és ellenőrzi, hogy annál az elemnél vagyunk-e amit keresünk. Ha minden értéket végig kell vizsgálni, akkor onnantól nem kiválasztásról, hanem keresésről beszélünk, ami időigényes (a kiválasztáshoz képest). Ha ilyen problémával találkozol, akkor valószínűleg dict-et kell használnod.

Ebben a típusban saját magunk által tetszőlegesen definiált kulcsokhoz tudunk értékeket társítani. Legjobb lesz ha a list-es összehasonlítás mellett maradunk, úgy könnyű lesz megérteni.

Készítsünk egy tömböt amiben több személy nevét és születési évét tároljuk:

people = [[1990, 'Alice'], [1991, 'Bob'], [1992, 'Carol']]

A kérdés: ki született 1992-ben?

A válaszhoz, ahogy nekünk embereknek, úgy a számítógépnek is tételesen végig kell olvasnia az összes elemet.
De mondhatjuk azt is, hogy a születési év alapján akarjuk kiválasztani a személyek neveit, tehát jó lenne, ha a születési év egy kulcs, a hozzá tartozó érték pedig a személy neve lenne. Ez leírva így néz ki:

people = {1990: 'Alice', 1991: 'Bob', 1992: 'Carol'}

Eléggé hasonló a list-es példához. Az érték kikérése pedig pontosan ugyan olyan: az index operátort kell használni. Tehát ha az 1990-ben született személy nevére vagyok kíváncsi, akkor:

people = {1990: 'Alice', 1991: 'Bob', 1992: 'Carol'}
oldest = people[1990]
print(oldest)

Ha ezt lefuttatjuk, akkor az Alice felirat jelenik meg a konzolban. Fasza nem?

Típuskonverzió

A nyelv dinamikus működése miatt gond nélkül leírhatjuk azt hogy:

my_variable = 1234
my_variable = False
print(my_variable)

és a képernyőn megjelenik a False üzenet, de az erős típusosság miatt ha azt írjuk be hogy:

apples = 5 + 'alma'
print(apples)

akkor nagy lóbaszó hibaüzenet kapunk csak.

Az ilyen szituációk kezeléséről gondoskodik a típuskonverzió (type conversion vagy casting) művelete. A fenti példában egy számhoz próbáltam egy szöveget hozzáragasztani, de a képernyőn csak annyi jelent meg hogy TypeError: unsupported operand type(s) for +: 'int' and 'str', ami pont azt jelenti, hogy int-et str-el összeadni nem lehet.

'5' nem egyenlő 5-el!

Átkozottul fontos lesz azt fejben tartani, hogy mikor mi kerül a képernyőre kiíratásra. Ugyanis a képernyőn nem látszódik már, hogy egy számot, vagy egy olyan szöveget írunk ki, ami számjegyeket tartalmaz, viszont a Pythonnak ez pont nem mindegy.

Egy str-ben gyakorlatilag akármit eltárolhatunk, amit a képernyőn képesek vagyunk megjeleníteni karakter formájában, de attól, hogy egy string minden egyes karaktere egy számjegy, a Python még nem változtatja át a str-t magától int-é.

Ahhoz tehát, hogy a korábbi, 5 + 'alma' problémát megoldjuk, el kell érni, hogy az összeadás jel két oldalán azonos típusú adat legyen.

Explicit típuskonverzió

Explicit típuskonverzió az, amikor valamilyen jól látható módon jelezzük, hogy változzon meg egy érték típusa valami mássá. Ez a típuskonverzió legnyilvánvalóbb formája, de van néhány (nagyon kevés) olyan eset is, amikor a Python mégis képes magától a típusok módosítására. Ilyen például amikor egész és tört számokat adunk össze.

A konverziót függvények fogják elvégezni, amiket pár bekezdéssel feljebb már felsoroltam, az “Explicit típusok” nevű listában.

Azok a függvények, de úgy általában minden függvénye a Pythonban, írásmódjukban nagyon hasonlítanak az közönséges változókra, de van egy nagy különbség köztük: zárójellel végződnek. De a függvényekről majd később beszélünk …

Egy érték típusának az átalakításához csak írjuk be az értéket (ami természetesen változó is lehet) a zárójelek közé, pont úgy, mint ahogy a print()-el kiírtuk az értéket a képernyőre. A függvény előállít egy új értéket az alapján, amit a zárójelei között kapott, de olyan típussal, amilyen konverziót a függvény elvégez.

A sok magyarázat után itt az ideje hogy csináljunk is valamit. Ideje megoldani a problémát:

apples = str(5) + 'alma'
print(apples)

Az 1. sorban az 5-öt, ami egy int, beraktuk az str() zárójelei közé, így átalakult az 5 '5'-é, majd ezt összeadjuk az 'alma' str-el. Így az összeadás mindkét oldalán azonos típus van, és két str összeadásának az eredménye a bal- és jobb oldali string összeragasztva.

A fenti példa meglehetősen buta, hisz ezzel a lendülettel azt is írhattam volna hogy:

apples = '5' + 'alma'

és ez teljesen jogos. A valóságban igazából a változókban szereplő értékek típusát kell gyakran állítani, mert gyakori, hogy nem mi rendelkezünk róla, hogy a változóban milyen típusú érték van. Ilyen például, ha a felhasználó gépelt be valamit, vagy fájlból olvasunk.

Ennek szellemében, az alábbi eset sokkal-sokkal gyakoribb

some_variable = 5
apples = str(some_variable) + 'alma'

Mikor jön el a konverzió ideje?

Jogos lehet a kérdés, hogy mégis meddig kell megtartani egy változót egy adott típussal, és mikor kell átalakítani egy másikká. Én azt a szabályt alkalmazom, hogy ritkán használt típust minél később, gyakran használtat pedig minél előbb módosítok.

Ha egy változó értékére más típussal van szükségem, de viszonylag ritkán, akkor abban a ritka pillanatban egyszer elvégzem az átalakítást. Ha egy változó értékére más típussal nagyon gyakran van szükség, mondjuk onnantól hogy beolvastam egy fájlból, egészen addig, amíg kilép a program, akkor közvetlenül a fájl beolvasása után elvégzem az átalakítást, és a konvertált értéket használom onnantól végig.

Konstansok

Elég jól átrágtuk magunka ennek a résznek a nehezén, úgyhogy levezetésül pár szó a konstansokról.

A konstansok gyakorlatilag a változók ellentettjei. Amikor leírod hogy:

text = 'Hello World!'
print(text)

Akkor tiszta sor hogy a text az egy változó, és hogy a 'Hello World!' egy string. De ez a str egy konstans is, azért, mert kézzel egy pontos, konkrét értéket gépeltél be a forráskódba.

Sokkal jobban érződik ez, ha nem akarsz balra-jobbra tárolgatni egy stringet, csak ki akarod írni a konzolba. Az így néz ki:

print('Hello World!')

Látszik, azt a 'Hello World!'-öt nem változóból nyertük; be van írva, nem lehet megváltoztatni, az egy konstans.

Zárás

Bele akartam kezdeni a kifejezések témakörébe, de azt hiszem hogy ez a következő epizódra marad. Egyelőre viszont már tudunk változókat deklarálni, és adatokat rakni beléjük, úgyhogy jó úton haladunk, na!

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

-slp

2013. január 9., szerda

01 - Python telepítés

Még mielőtt akárminek is nekikezdenék, szeretném jelezni, hogy igazodva a kor igényeihez, ez a bejegyzés 2016. február 14-én újraírásra került. Az eredeti bejegyzésben még a Python 2.7.3-as verziójának telepítését ismertettem. 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.

Python 2 vagy Python 3?

Gyakran visszatérő kérdés a kezdő programozóktól hogy Python 2-vel vagy 3-al érdemes-e kezdeni. Ma már nem kérdés, hogy a Python 3.x verzió használata az ajánlott. A PEP 373 szerint, a 2-es ág fejlesztése 2020-ban fog végleg befejeződni. Ez már csak 4 év!

A Python beszerzése

A Python interpretert a https://www.python.org/downloads/ címről lehet beszerezni. Rögtön az menüsor alatt, egészen pontosan a sárga Download the latest versions of Python felirat alatti gombokkal lehet a jelenlegi két elterjedt verzió letölteni. A bejegyzés megírásakor a legfrissebb verzió a Python 3.5.1.

Linuxos felhasználók többnyire előnyt élveznek a telepítést illetően, ugyanis általában megtalálható a Python 3 a csomagkezelőben. Debian-alapú rendszereknél (pl.: Ubuntu) apt-vel könnyen telepíthető a megfelelő verzió:

$ sudo apt-get install python3

64-bites verziót akarok!

A letöltés oldalán, a Looking for a specific release? alatti táblázatban a jelenlegi- és korábbi verziók saját oldalaira lehet tovább navigálni. Itt keresd ki a legújabb verziót (aminek a legnagyobb a verziószáma, jelenleg ez a 3.5.1), majd kattints a verzió sorában a Download gombra. A betöltődő oldal alján, a Files táblázatban található az összes elérhető kiadás. 64-biten a Windows x86-64 executable installer-t kell letölteni.

A Python telepítése Windowson

A régen sem túl bonyolult telepítési folyamat mostanra annyira egyszerű lett, hogy ráfér az egész egyetlen screenshotra. A telepítő elindítása után ez az ablak fogad minket:


Python 3.5.1 telepítő ablaka

  1. Figyelj oda hogy az Add Python 3.5 to PATH be legyen pipálva. Így parancssorból bárhonnan indíthatod majd az interpretert. Ha netán már túlvagy ezen, és véletlenül kihagytad a pipát, akkor is működni fog a Python, de lehet hogy egyszer majd valamilyen probléma miatt kézzel neked kell elvégezned a beállítást. Egyszer… majd.
  2. Install Now, és már zajlik is a telepítés.
  3. A telepítés végén pedig Close

Mi települ fel?

Nem jelent meg semmi új ikon az asztalon, akkor mégis mi változott a rendszeren, mi települt fel?

  • A Python értelmező. Ez futtatja majd a .py fájlokat
  • A dokumentáció. Így internet nélkül is kéznél van az amúgy kiváló minőségű leírása a nyelvnek.
  • A pip. Ez egy csomagkezelő, amivel röhejesen egyszerűen lehet mindenféle kódot telepíteni a Pythonunkhoz, ami így csomó új, okos funkcióval bővíti a nyelvet.
  • Az IDLE és a tkinter. Az IDLE egy nagyon egyszerű fejlesztői eszköz, amibe beírhatsz pár sor Python kódot, és azonnal látod is az eredményét. A tkinter pedig egy grafikus felület, amivel nagyon-nagyon egyszerű kattingatós programokat lehet írni. Mellékesen az IDLE is ezt használja.
  • A Python test suite. A forráskód tesztelésére.

Az első program

Miben kell írni a Python programot?

A Python forráskódot plain text (szöveges dokumentum) fájlba kell írni, és .py kiterjesztéssel kell ellátni. Erre bármilyen egyszerű szövegszerkesztő, így a Notepad (Jegyzettömb) is megfelel. Microsoft Word, és az ahhoz hasonló szövegszerkesztők nem használhatóak.

A Jegyzettömb az első pár program elkészítéséhez még elegendő, de idővel érdemes lesz feljebb kapcsolni például Notepad++-ra, vagy profi fejlesztői eszközre, mondjuk PyCharm-ra (ami a személyes kedvencem).

Linuxon a nano bőven megteszi kezdésnek.

Hello World!

Tradicionálisan az első program bármilyen nyelven amit bemutatnak, egyszerűen annyit csinál, hogy kiírja a képernyőre azt a mondatot hogy Hello World! (Helló Világ!)

Indítsd el valamelyik kéznél levő szerkesztődet, és egyszerűen csak gépelj be annyit hogy:

print('Hello World!')

Mentsd el a fájlt, de ne .txt kiterjesztéssel, hanem .py-al.


.py fájl létrehozása

Jegyzettömbben, de úgy általában a szerkesztőkben ki lehet választani a mentés során, hogy milyen legyen a fájltípus. Itt válaszd a Minden fájl lehetőséget. Ezután a Fájlnév-hez olyan nevet adj meg, ami .py-ra végződik (nálam: hello_world.py)

A mentés után keresd meg a fájlt, és indítsd el. Egy előugró fekete ablak úgy egy szempillantásnyi időre megjelenik, majd el is tűnik. Ez azért van, mert a program azonnal véget is és a szöveg kiírása után, ezért kilép. Ahhoz hogy lássuk a program befejezése után is hogy az miket írt ki a képernyőre, a programot parancssorból (konzolból) kell futtatni.

Python program futtatása

Ha egy már meglevő parancssor ablakból indítjuk a kódot, akkor a program kilépése után láthatóak maradnak a program üzenetei, hisz a szülő ablak továbbra is futni fog.

Parancssor használata (Windows)

A parancssort legegyszerűbben a Futtatás ablakból könnyű előhalászni. Ehhez:

  1. Nyomd le a WINKEY + R billentyűkombinációt. (A WINKEY az a billentyű a billentyűzeten amire a Windows logót nyomtatták.). Megjelnik a Futtatás nevő ablak, lent a képernyő bal-alsó sarkában.
  2. Írd be hogy cmd majd nyomj entert.

Ezzel meg is érkeztünk a parancssorba. Már csak annyi van hátra,hogy elnavigáljuk magunka a fájlunkhoz. Itt van pár parancs azoknak, akik még sose jártak a parancssorban:

  • dir
    Ez a parancs kilistázza annak a könyvtárnak a tartalmát amiben épp benne vagyunk.
  • cd könyvtár
    Ezzel a paranccsal lehet megnyitni egy könyvtárat (mappát). A cd után a könyvtár nevét kell írni. Ha szóközt is tartalmaz a neve, akkor ” ” (idézőjel) közé kell írni a mappa nevét.
  • Ha pedig meghajtót akarunk váltani (pl.: A C:-ről a D:-re) akkor egyszerűen csak be kell gépelni a meghajtó betűjelét.

A sor elején mindig látszódik hogy épp melyik könyvtárban tartózkodunk. Ez a munkakönyvtár (working directory). Amikor elindul a parancssor, akkor a saját könyvtárunk a munkakönyvtár. Ez az a mappa ahol a Dokumentumok, Letöltések, Asztal, Képek, Zenék, Videók, … , könyvtárak találhatóak.

Tegyük fel hogy rögtön az asztalra mentettük a hello_world.py fájlt. Így néz ki a parancssor és a parancsok amiket be kell gépelni:

C:\Users\win7\>cd Desktop
C:\Users\win7\Desktop>python hello_world.py
Hello World!

Az 1. sorban beléptünk a Desktop könyvtárba, majd a python hello_world.py paranccsal futtattuk a hello_world.py-t. Egészen pontosan az történt, hogy a python program elkezdte futtatni a hello_world.py fájl tartalmát. Ha a telepítés során nem pipáltátok be, hogy Add Python 3.5 to PATH, akkor előfordulhat, hogy azt írja a parancssor, hogy A megadott nevet (python) a rendszer nem ismeri fel […]. Ekkor meg lehet próbálni futtatni a fájlt úgy, hogy egyszerűen begépelitek a nevét:

C:\Users\win7\Desktop>hello_world.py
Hello World!

A terminál használata (Linux)

Nem veszek rá mérget hogy tényleg szükséges-e egy rendes Linux felhasználónak magyaráznom, hogy hogyan kell mozogni a könyvtárakban, de azért a biztonság kedvéért röviden leírom a történetet.

  • cd könyvtár
    Ugyan úgy történik a könyvtárváltás mint a parancssorban. A cd után annak a mappának a nevét kell írni, amit meg akarunk nyitni. Ha szóközt tartalmaz ez a név, akkor ” ” (idézőjel) közé kell írni a mappa nevét.
  • ls
    Ez a parancs kilistázza az aktuális könyvtár tartalmát.

Disztrótól függ, hogy hogyan lehet elővarázsolni a terminált. Én Lubuntu-t használok, és ott a CTRL + ALT + T a megfejtés.

Ha odaértünk a fájlhoz, akkor úgy ahogy Windowson is, így futtathatjuk a kódot:

$ python hello_world.py
Hello World!

Konzolos program, grafikus program

Elsőre lehet meglepő, hogy miért kell ilyen ocsmány, DOS-os kőkorszaki ablakban nézni hogy mit ír ki a program. Miért nincs rendes ablak, kerettel, meg gombokkal, és miért nem lehet kattingatni?!

Kétféle programot különböztetünk meg egymástól, a parancssori (konzolos) alkalmazásokat (CLI), és a grafikus felületűeket (GUI). Windowson megszokott, hogy minden programnak szép ablaka van, de ezt egyáltalán nem triviális leprogramozni. Ezért egy jó ideig olyan programokat fogunk írni, amiknek nincs semmi ablakuk. Ez nem jelenti hogy ezek elavultak, vagy korlátozott szoftverek lennének!

Csendben megjegyzem, hogy idén (a bejegyzés újraírásakor) 6 éve hogy már programozok, és eddig összesen 3 grafikus felületű programot kellett írnom.

Zárunk

Ha minden úgy ment ahogy odafent írtam, akkor sikeresen feltelepült a Python interpreter, és ki is próbáltuk hogy működik-e minden rendesen. Tudjuk hogy hogy lehet úgy futtatni a kódot hogy a befejezése után ne vesszen el az eredménye, úgyhogy azt hiszem kijelenthetjük, hogy minden megvan hozzá hogy programozóvá váljunk.

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

-slp