# Bevezető előadás

Készítette: Czirkos Zoltán/ Előadó: Ress Sándor · 2025.09.11.

Bevezető előadás. Kifejezések, változók, típusok fogalma. A Python nyelv alapjai. Egyszerű bemenet és kimenet, konverziók. Strukturált vezérlési szerkezetek: if, while.

## 1. Computer Science

### A számítási folyamatok

- A számítógépben: számítási folyamatok
- Ezek adatokat manipulálnak
- A működésüket programok vezérlik

### Milyenek?

- Nem láthatóak, nem foghatóak meg – de igaziak
- Értelmes munkát végeznek, kérdésekre válaszolnak, pénzt mozgatnak bankok között, járműveket vezetnek

## 2. A félév végére…

     Telefonkönyv

     Kit keresünk? Tapsi Hapsi

     Száma: 555-125687

     Új keresés (i/n)? n_

Hogyan lehet olyan programot írni, amely sok adatot tárol és dolgoz fel?

Megváltoztatunk egy cellát a táblázatkezelőben, és újraszámolódik minden, ami kell. Hogyan lehet ezt megcsinálni?

Egyszerű játékok: hogyan működik például egy kukacos játék? Hogyan jegyzi meg, merre halad a kukac?

Amőba játék: mitől tűnik úgy a gép, mintha intelligens lenne? Meg tudod verni a saját amőba játékodat? Meg tudja verni a szobatársad? Meg tudod úgy erősíteni, hogy már ne tudja?! :)

# Algoritmusok

## 4. A tudás fajtái

Amikor a tudást, ismeretanyagokat szeretnénk csoportosítani, azt megtehetjük annak „deklaratív” vagy „imperatív” jellege szerint.

### Deklaratív tudás

- „Mi az, ami igaz?”
- Állításokat tesz

### Imperatív tudás

- „Hogyan kell csinálni?”
- Módszereket ad

### Példa: egy szám négyzetgyöke

> `x` gyöke egy olyan `y`,
> amire `y2=x`,
> és `y≥0`

Deklaratív tudás: egy számról meg tudjuk mondani, hogy egy másik négyzetgyöke-e.

> Tippeljük meg, mennyi: `y'`.
> A tipp javítható: `(y'+x/y')/2`
> Javítgassuk, amíg nem elég jó.

Imperatív tudás: meg tudjuk vele határozni egy tetszőleges szám gyökét.

Az imperatív tudás sokszor hasznosabb. A deklaratív tudás alapján, ha adott egy `y`, akkor meg tudjuk mondani, hogy az egy szintén adott `x`-nek gyöke-e. De többet nem tudunk mondani. Ennél sokkal jobb az, ha kapunk egy `x`-et, és meg tudjuk határozni a hozzá tartozó `y`-t!

Az imperatív programozási paradigma lényege: olyan programot kell írnunk, amelyben lépésről lépésre megmondjuk a számítógépnek, hogy mikor mi a teendő. A hangsúly az imperatív nyelvekben a megoldás módján van. Ebben a félévben ezt a gondolkodásmódot kell megtanulni.

Léteznek deklaratív programozási nyelvek is, amelynél megadjuk, milyenek a helyes megoldások, és a számítógép találja ki a megoldás módját. Ezekkel könnyebb lehet programozni, de a megoldható problémák köre sokkal szűkebb, mint az imperatív nyelvek esetében. Deklaratív programozási nyelv például az adatbázisoknál használt SQL: ebben megadhatjuk, mely adatokra van szükségünk, és a program találja ki, hogyan kell kikeresni azokat az adatbázisból.

## 5. Specifikáció és algoritmus

A programozásban általában kapunk egy feladatot – egy feladatot pontosan leíró specifikációt. Ez legtöbbször deklaratívan adott. Nekünk kell kitalálni a hozzá tartozó imperatív megoldást, azaz egy módszert, amellyel a bemenetből a kimenet előállítható.

### Specifikáció: mit kell csináljon

- Mi lesz a bemenete, mi a kimenete, mi ezek között az összefüggés
- Ez általában deklaratívan adott

Gépek bemenettel
és kimenettel

### Algoritmus: hogyan csinálja

- A megoldás „lépésről lépésre” leírása: imperatív módon
- Ezt nekünk kell kitalálni.
  Nincs rá általános módszer.

### Művészet? Tudomány? Mérnöki feladat?

Nincs olyan általános módszer, amely segítségével egy algoritmus szisztematikusan kidolgozható lenne. Vagyis amellyel egy deklaratívan („mi igaz”) adott problémára imperatív („hogyan kell csinálni”) megoldás lenne adható. Hogy ez vajon művészet, tudomány vagy mérnöki feladat, azt nem lehet 100%-osan eldönteni:

- Egyrészről tudomány, ahogyan azt az angol neve is mutatja: computer science. Az algoritmusok kezelhetőek matematikailag. Helyességük bizonyítható, tulajdonságaik (pl. időigény) számszerűsíthetőek.
- Másrészről művészet, hiszen a kidolgozásuk gyakran ötletelésen, felismeréseken múlik. Az egyik leghíresebb programozásról szóló könyv „A számítógépprogramozás művészete” című sorozat (Donald Knuth: The Art of Computer Programming). A címe mindent elmond.
- Harmadrészt mérnöki feladat, éppen annyira, mint egy autót megtervezni. Figyelni kell arra, hogy a részegységek ne zavarják egymást. Irányítani kell a csapatok munkáját, méghozzá úgy, hogy egymástól függetlenül is tudjanak dolgozni. Vannak szabványok, amelyeket követni kell.

A programozás során rengeteg olyan problémával találkozunk, amelyek rendszeresen felmerülnek. Vannak jól bevált megoldások, amelyeket érdemes újra és újra felhasználni. Egy jó programozó bármikor tud mondani többféle módszert is arra, hogyan lehet egy névsort ábécébe rendezni, sőt azt is tudja, mikor melyik módszer a gyorsabb. Ezért sokszor, amikor programozunk, már megtanult algoritmusokat kódolunk csak le.

## 6. Algoritmus – definíció

### Algoritmus

Módszer a feladat megoldására.

- Utasítássorozat megengedett lépésekből
- Mechanikusan végrehajtható
- Véges sok lépésből áll
- Mindig egyértelműen adott a következő lépés
- Minden időpontban véges sok memória kell

A papíron összeadás és a prímtényezős felbontás olyan algoritmusok, amelyeket általános iskolában tanítanak. Vegyük észre, hogy mind kimerítik a fenti feltételeket: mechanikusan végrehajthatóak, mindig pontosan definiálják a következő lépést – és valamilyen bonyolult probléma megoldását adják meg úgy, hogy közben egyszerű lépéseket használnak.

     175
    +343
    ────
     518

összeadás

- „az összes számjegyet”
- „add össze”
- „ha eléri a 10-et, van átvitel”
- …

    20│2
    10│2
     5│5
     1│

prímtényezős felbontás

- „amíg nagyobb, mint 1”
- „ha osztható”
- „írd le az osztót”
- …

## 7. Pszeudokód: egy algoritmus leírása

A programozásban a módszerek, algoritmusok szöveges leírását adjuk meg.

Ez egy
algoritmus

> Kérj egy számot a felhasználótól, legyen ez N.
> A értéke legyen 1.
> Ellenőrzés: Ha N=1, ugorj előre a „vége” címkéhez.
> Legyen A értéke mostantól A·N.
> N értékét csökkentsd 1-gyel.
> Ugorj vissza az „ellenőrzés” címkéhez.
> Vége: Írd ki A értékét.

A szöveges leírás (pszeudokód) tartalmazza:

- A megjegyzett számok listáját: ezek a változók.
- Az elvégzett műveleteket: szorzás, csökkentés.
- A lépések sorrendjét meghatározó utasításokat és döntési pontokat: a vezérlést.

Ezzel megadjuk az algoritmust. Vegyük észre, hogy teljesen mechanikusan végrehajtható lépésekről van szó: egyszerű, matematikai jellegű lépéseket végzünk. Szorzást kell elvégezni, egyenlőséget vizsgálni stb.

Próbáld is ki az algoritmust, számítsd ki a 4 faktoriálisát az utasításokat követve! Jegyezd föl papírra az A és az N értékét; ha azt kéri az algoritmust, hogy módosítsd, akkor radírozd ki, és írd a jegyzeteidhez az új számot.

## 8. A programok

### A programkódok

- Számítógép által érthető programozási nyelveken
- A nyelv elemeit meg kell tanulni: szótár: szavak, amelyekkel fogalmazunk, szintaxis: a nyelvtani szabályok

    # legnagyobb közös osztó
    a = int(input("a? "))
    b = int(input("b? "))

    while b != 0:
        t = b
        b = a % b
        a = t

    print("lnko =", a)

Mint mikor angolul vagy németül tanulunk: a számítógép nyelvének elemeit meg kell tanulni.

### Programozási nyelv

- A Python nyelvet fogjuk használni (3.0: Guido van Rossum, 2008.)
- Egyike azon nyelveknek, amit elsőként tanítanak

A Python nyelvet eredetileg Guido van Rossum fejlesztette ki, 1991-ben jelent meg először. Azóta több szabványosított változata lett. A jelenlegi változata a 3.x-s verzió, amelynek első változata 2008-ben jelent meg. (Még néha használják a 2.x-set is, de azt 2020-ban végleg nyugdíjazták.) Ebben a tárgyban, ebben a félévben >=3.6 verziójú Python-t használunk. Ez amúgy 2016-ban jelent meg.

# A programozás alapjai

## 10. Helló, világ

A tradicionális első program forráskódja:

első Python
programunk

    # üdvözlet
    print("Helló, világ!")

    Helló, világ!

A „helló, világ” programoknak nagy hagyománya van. Ez már a '70-es évek óta így van, a legtöbb programozás tankönyv ezzel kezdődik.

### `print()` – kiírás

- `print()`: kiír valamit
- `"szöveg"`: a szöveg (sztring, karaktersorozat) idézőjelben. A gép nem keres benne értelmet
- A `print()`-nek adott szöveget, ún. paramétert zárójelbe (parenthesis) kell tenni

### `# üdvözlet` – megjegyzések

- `#`: megjegyzés (comment)
- A gép nem foglalkozik vele, magunknak írjuk
- Magyarázatot írhatunk benne arról, hogyan működik a programunk

Szerencsére nekünk azzal nem kell foglalkoznunk, pontosan hogyan fogja a gép megjeleníteni a szöveget (megrajzolni a betűket). A `print()` függvényt készen kapjuk, bármelyik programunkban használhatjuk.

## 11. Számológép

    # Számológép
    print("Eredmény:", 2*3)

A `print()` nem csak egy dolgot tud kiírni, hanem akár többet is. A kiírandó dolgokat vesszővel elválasztva adjuk meg, amiket a print szóközzel elválasztva ir ki. És nem csak egyszerű szöveget, hanem számokat is. A fenti példában kiíródik majd az „Eredmény:” szöveg, utána egy szóköz, végül pedig a szorzat.

A kiírt szám jelen esetben ez egy egész számokkal végzett művelet. A program egy nagyon egyszerű számológép: a `2*3` helyére bármilyen matematikai kifejezést beírhatunk, és a program futtatása után megkapjuk az eredményt. A szokásos módon használhatjuk a négy alapműveletet és a zárójelezést is. Természetesen a Python nyelvtani szabályaira figyelni kell, például a szorzás jele a `*`, nem a `·`.

## 12. A típusok fogalma

Hogy beszélni tudjunk róla, hogyan dolgoznak fel a programok adatokat, meg kell ismernünk a típus fogalmát.

### Típus

Az értékkészlet és a műveletek együttese.

- A változóknak is van típusa – ez adja meg az értékkészletet és a végezhető műveleteket is.
- A típusok szinte minden programozási nyelvben megtalálhatóak.

Típusok: példák
típus | értékkészlet | műveletek
--- | --- | ---
egész | -1, 2, 5, … | összeadás, kivonás, összehasonlítás
valós | 1.5, 7, 3.14, … | összeadás, kivonás, összehasonlítás
logikai | igaz, hamis | és, vagy, tagadás
karakter | betűk, írásjelek, … | összehasonlítás, következő, előző
szöveg | karaktersorozatok | összefűzés, keresés

## 13. Kifejezések

A kifejezések a programjaink legalapvetőbb építőkövei: műveleteket végeznek el. Ezeket ismerjük a matematikából is: összeadás, kivonást stb., de a programozásban sokkal többféle lesz.

### Kifejezések és típusok

műveletek
kifejezés | érték
--- | ---
1+2 | 3
5+2*3 | 11
6*(3+4) | 42

vegyes kifejezések
kifejezés | érték
--- | ---
1<2 | igaz
2≥3 | hamis
"a" < "b" | igaz

hibás kifejezések
kifejezés | hiba
--- | ---
3*(1+ | vége?
1-HAMIS | típus!
1+"alma" | típus!

A műveletek adott típusokon végezhetőek el, és az eredménynek is van valamilyen típusa. Ezek azonban nem feltétlenül ugyanazok. Például egy szám+szám művelet eredménye is szám, de egy szám<szám összehasonlítás logikai, igaz/hamis típusú eredményt ad. Lehetséges az is, hogy egy művelet két operandusának típusa sem egyezik meg: időpont+időtartam→időpont. Pl. 12:15+30 perc=12:45.

### A kifejezésekről

- Meg kell feleljenek a nyelvtani szabályoknak
- Fontos a típus, hogy értelme legyen egy kifejezésnek!
  - Ha X szám, X+3 értelmes.
  - Ha X szöveg, X+3 értelmetlen.

A kifejezés értelmességéhez, helyességéhez szükséges az is, hogy az egyes műveleti jelek (operátorok) mellett megfelelő típusú operandusok legyenek. Az `1-HAMIS` kifejezés hiába tűnik helyesnek nyelvtanilag (a mínusz jel mindkét oldalán egy érték van), mégis értelmetlen, mert egy egész számból nem lehet kivonni egy logikai értéket. Ugyanígy értelmetlen az 1+"alma" kifejezés is.

## 14. A változók és használatuk

### Mi az a változó?

Egy eltárolt, megjegyzett érték, amelynek nevet adunk.

- Egy változó egy dolgot jegyez meg, ezért minden megjegyzett dologhoz külön változó kell.
- A programnak időbeliséget adnak: miattuk számít a műveletek sorrendje!

    X értéke legyen 5.     értékadás (írás)

    Leírom X-et.           kiértékelés (olvasás): „5”

    X értéke legyen X+1.   kifejezés kiértékelése, aztán értékadás

    Leírom X-et.           ez „6” lesz

### Mit lehet csinálni egy változóval?

A változókban tároljuk a programunk által megjegyzett adatokat, részeredményeket.

Kiértékelés
  Egy változóban tárolt adatot előveszünk, „olvassuk”.
Értékadás
  Egy változóban új adatot jegyzünk meg, „írjuk”. A régi értéke ilyenkor elveszik!

A program futása során, egyes időpontokban más lehet az értékük: ugyanaz a művelet más eredményt adhat egy másik pillanatban. Emiatt fontossá válik a műveletek sorrendje. Fontos gondolat, hogy ez az értékadás miatt van. Ha nem létezne értékadás, akkor ez nem lenne így. Például az alábbi képletben teljesen mindegy, hogy melyik tényező értékét számítjuk ki előbb: `(3+4)×(6-9)×(12-4-6+5)`. Haladhatunk balról jobbra, jobbról balra, vagy akár kezdhetjük a középső `6-9`-cel is. Ezzel szemben a fenti programkódban láthatóan számít az, hogy a növelés előtt vagy után írjuk le az X változó értékét.

## 15. Változók a Python nyelvben

### Definíció (létrehozás)

    x = 2         # x egész

    s = "almafa"  # s szöveg

Változót úgy hozunk létre, hogy értéket adunk neki.

- A változóinknak nevet adunk, ezeknek betűvel kell kezdődniük. Lehet ékezetes is, de nem szokás.
- Ezzel megmondjuk a gépnek a változó típusát is: amilyen értéket adtunk neki.
- A fenti példában `x` egész típusú változó, `s` pedig szöveg (string) lesz.

### Használat

    x = 3      # x legyen 3

    x = x + 1  # x nőjön eggyel

Értékadás: x elfelejti régi értékét, és mostantól ezt tárolja.

- `=` az értékadás művelet jele
- `x = x+1`: nem egyenlet, hanem értékadás
- „x legyen egyenlő x pillanatnyi értéke +1-gyel”

Valójában itt az `x` változóval két műveletet is végzünk: egyrészt kiolvassuk (megnézzük a régi értékét), aztán pedig írjuk (módosítjuk) is.

### Kiírás

    x = 2 * 3

    print("Értéke:", x)

    Értéke: 6

- A `print()` változót is kaphat.
- Valójában nem tudja, változót kapott-e, hanem csak a kiolvasott értéket kapja meg.

### Beolvasás

    nev = input("Hogy hívnak? ")

    print("Szia,", nev)

    Hogy hívnak? _

- `input()`: szöveg beolvasása.
- A paraméter a kérdés (elmaradhat).
- A beolvasott szöveget értékadással tesszük a változóba.

## 16. A Python nyelv dinamikusan típusos

Vannak statikusan és dinamikusan típusos programozási nyelvek. A Python nyelv dinamikusan típusos.

Ez azt jelenti, hogy a változóknak nem kell előre megadni a típusát, sőt egy adott nevű változó típusa is változhat a program futása közben.

    x = 12
    print("Értéke:", x)  # Értéke: 12

    x = "alma"
    print("Értéke:", x)  # Értéke: alma

Általában viszont egy változóval ilyet nem szoktunk csinálni. A változónak a programban meghatározott szerepe, célja van, ami alapján nevet is adtunk neki. A szerepéből pedig következik a típusa is; egy ember neve sosem lesz egész szám, a kör sugara pedig nem lesz szöveg. Emiatt valószínűleg nem logikus az a program, ahol egy egész típusú változó egyszercsak szöveggé változik.

A statikusan típusos nyelvekben a fentiek ellenkezője igaz. Ott a programkódban meg kell adnunk előre minden egyes változó típusát, és az a típus nem változhat a program futása alatt.

## 17. Sztringek összefűzése

Feladat: írjunk programot, amelyik nevén üdvözli a felhasználót!

    Hogy hívnak? Pistike

    Szia, Pistike!

Ne legyen szóköz a név és a felkiáltójel között!

Ez az első interaktív programunk, amely nem csak kiír valamit, hanem kérdez is a felhasználótól – sőt az eredmény a felhasználó által adott bemenő adattól függ.

Az eddigiek alapján ehhez szükségünk lesz egy változóra. Előbb beolvassuk a nevet egy `input()` segítségével, utána pedig kiírjuk az üzenetet a `print()`-tel.

    nev = input("Hogy hívnak? ")
    print("Szia, " + nev + "!")     # egy paramétere van!

`+` operátor sztringek között: összefűzés, konkatenálás (concatenation).

Ha a `print("Szia,", nev, "!")` sort írnánk, akkor `Szia, Pistike !` lenne az eredmény, vagyis a felkiáltójel előtt zavaróan egy szóköz lenne még. Ezt a megoldásban úgy kerüljük el, hogy egyetlen egy sztringet állítunk elő, amelyben összefűzzük a `+` operátorral (művelettel) a három sztringet, a `Szia` köszönést, a nevet és a felkiáltójelet. Az összefűzésnél nem kerül szóköz a darabok közé, pl. `"alma" + "fa"` értéke `almafa` lesz. Így a felkiáltójel előtt nem lesz szóköz, a vessző után viszont mi tettünk.

### Egy sorban?

Csak apró betűs megjegyzésként: valójában a változóra sincsen szükség. Írhatnánk akár ezt az egy sort is:

    print("Szia, " + input("Hogy hívnak? ") + "!")

Ez azonban nem szép stílus, mert nehezebb kibogozni a kódot nézve, hogy mit csinál a program. De működni fog. Hiába van „előbb” a `print()`, mégis az fog később végrehajtódni. A `print()` paramétere az összefűzés eredménye; tehát azt előbb elő kell állítania a gépnek, csak utána kaphatja meg az egyetlen egy sztringet a `print()`. Tehát lehet így írni, de ezt jobb nem erőltetni. Ez a program helyesnek ugyan mondható, de jónak nem.

## 18. Az operátorok polimorfizmusa

Az operandusok típusától függően eltérő lehet a működés.

Számok esetén összeadás, sztringek esetén összefűzés történik.

    print(1 + 2)
    print("alma" + "fa")

    3
    almafa

### Típusokkal kapcsolatos hibák

    print("alma" + 123)     # hibát dob

    Traceback (most recent call last):
      File "proba.py", line 5, in <module>
        print("alma" + 123)
    TypeError: must be str, not int

Egy sztring és egy szám nem adható össze, ezért hibát dob a program: `TypeError`.

## 19. Konverziók: int(), float() és str()

    a = input("a? ")
    b = input("b? ")

    print("a+b =", a + b)

    a? 2
    b? 3
    a+b = mi lesz itt?

Mi az oka annak, hogy `23` íródott ki? Az, hogy az `input()` által visszaadott érték sztring típusú. Így sztring lesz `a`-ban és `b`-ben is, még akkor is, ha a felhasználó számjegyeket gépelt be. Márpedig sztringeket úgy kell összefűzni, hogy egymás után írjuk a bennük tárolt karaktereket; így lesz `"23"` (huszonhárom, vagyis valójában kettő-három) az eredmény, nem pedig `5`. Ha a felhasználó almát és fát gépel be, akkor nem is tűnik furcsának az eredmény, `"almafa"`.

Mi a teendő, ha mégis a két szám összegét szeretnénk kiírni, 2+3 = 5?

    a = input("a? ")
    b = input("b? ")

    print("a+b =", int(a) + int(b))

A beolvasott sztringeket számmá kell konvertálni.

### Konverziók

- `int(s)`: sztring → egész szám, pl. "123" → 123
- `float(x)`: sztring → valós szám, pl. "3.14" → 3.14
- `str(x)`: szám → sztring, pl. 123 → "123"

A konverziók függvényekkel végezhetők el. Például az `int()` függvény paramétere egy sztring, és visszaadja azt a számot, amit talál benne (tízes számrendszerben). Így a fenti kódban az `a` és a `b` változóban tárolt sztringeket értelmezve szám keletkezik, és az összeadás már számokon dolgozik.

Valójában a fenti programot inkább így szoktuk megírni:

    a = int(input("a?"))
    b = int(input("b?"))

    print("a+b =", a+b)

Ez azért jobb, mert a beolvasás helyén már látszik, hogy számokat vár a program.

Ha olyan konverziót szeretnénk elvégezni, ami lehetetlen (pl. `int("almafa")`), akkor `ValueError` típusú hibát fogunk kapni. Később majd lesz róla szó, hogy ezeket a hibákat hogyan lehet kezelni.

### Vigyázat!

Figyelni kell arra, hogy a konverzió nem a változót módosítja, hanem egy új értéket hoz létre. Tehát önmagában leírni az `str(x)`-et vagy egy `int(s)`-t haszontalan:

    s = input()

    int(s)          # nem csinál semmit, értelmetlen

    print(s + "!")  # működik, mert s egy sztring

A konverzió értékét fel kell használni egy kifejezésben, vagy eltárolni másik változóban.

## 20. A kör kerülete és területe

Feladat: írjunk programot, amely megkérdezi a felhasználót, mekkora egy kör sugara, majd kiírja a kör kerületét és területét!

A megoldás algoritmusa: követjük az események sorrendjét:

- Megkérdezzük a felhasználót, mekkora a kör.
- Megvárjuk, amíg válaszol (és megjegyezzük a választ).
- Kiírjuk a kerületet és a területet.

(Vagy épp másképp is megközelíthetjük: ahhoz, hogy kiírjuk az eredményt, előbb a bemenő adatokra van szükségünk. Anélkül úgysem menne. Az adatok beolvasása előtt pedig feltesszük a kérdést, mert később már nem lenne értelme.)

A kör sugarát a `sugar` nevű változóban tároljuk. Azért kell eltárolni, mert a billentyűzetről beolvasott értékre a programban több helyen is hivatkozunk: egyrészt akkor, amikor jelezzük, hogy hova kell beolvasni; másrészt a kerület kiszámításakor; harmadrészt a terület kiszámításakor.

A beolvasott sztringet számmá kell alakítanunk. Mivel a sugár lehet valós szám is, ezért ezt a `float()` konverzióval fogjuk megtenni.

    import math

    print("Mennyi a kör sugara?")
    sugar = float(input())

    print("Kerület =", 2 * sugar * math.pi)
    print("Terület =", sugar**2 * math.pi)

    Mennyi a kör sugara?
    4.5
    Kerület = 28.274333882308138
    Terület = 63.61725123519331

Fontos, hogy mindig érthető nevet adjunk a változónak, amely utal a szerepére. Ez megkönnyíti a programkód olvasását. Itt jó lenne még az `r` név is, de az `xx` vagy az `a1` már nem igazán. A kiszámított kerületet és területet is tehettük volna egy második és harmadik változóba (pl. `K` és `T` néven), de azokat nem akartuk többször használni.

`import math`

Lássuk, mi az újdonság még a programban! Az egyik az `import math` sor. Ezzel a matematikai modult tudjuk beemelni a programunkba. Ez rengeteg függvényt tartalmaz, pl. `math.sqrt()` a négyzetgyök, `math.sin()` segítségével pedig szög szinuszát tudjuk kiszámítani. De tartalmaz konstansokat is: `math.e` a természetes logaritmus alapszáma (2,718), amire pedig itt szükségünk volt, az a `math.pi`, a π értéke (3,1416).

Másik pedig a hatványozás operátor. Ezt Pythonban a `**` operátorral érjük el: `alap ** kitevő`. Ha valakinek jobban tetszik, ez írható függvényként is: `math.pow(alap, kitevő)`. De akár a négyzetgyök helyett is írhatunk feledik hatványt: `math.sqrt(2)` ugyanannyi, mint `2 ** 0.5`, mindkettő értéke 1,414.

`pi = 3.1416`
a programban
tizedespont,
nem vessző!

Apropó valós számok: a Python programunkba a valós számokat nem tizedesvesszővel, hanem tizedesponttal kell írnunk. A vessző függvényparaméterek elválasztására való!

    print(3, 1416)  # két külön szám, 3 és 1416

    print(3.1416)   # egy szám, a π közelítő értéke

# A vezérlési szerkezetek

## 22. Az imperatív programok működése

### Elemi lépések, műveletek a számítógépen

- Kiírunk valamit a képernyőre
- Adatot kérünk a felhasználótól
- Kiszámítunk valamit
- …

    PROGRAM
        KIÍR: "Helló, világ!" egyetlen elemi lépés
    PROGRAM VÉGE

A legegyszerűbb program egyetlen elemi lépésből áll, egyetlen tevékenységből. Az egy lépésből megoldható feladatoknál persze szinte mindegyik bonyolultabb. Ha több lépésünk van, meg kell mondanunk, milyen sorrendben szeretnénk azokat a lépéseket elvégezni.

### Mit csinál a program?

- A program kifejezésekkel kiszámol értékeket
- Ezeket eltárolhatja változókba vagy kiírhatja a kimenetére
- A számítások sorrendjét a vezérlési szerkezetek adják meg

    3211 │ 13
     247 │ 13
      19 │ 19
       1 │

Például egy prímtényezős felbontás algoritmusában nem mondhatjuk azt, hogy „oszd el a számot a legkisebb prímszámmal”. Legalábbis amíg nem mondtuk meg azt, nem raktuk össze kiértékelésekből és értékadásokból, hogy hogyan lehet megkeresni a legkisebb prímszámot, ami osztja a bal oldalit.

## 23. Szekvencia: egymás utáni lépések

### Folyamatábra

### Program

       print("Oldalhossz?")
       a = int(input())
       t = a*a
       print("Terület =", t)

### Működés

    a:
    t:

A programok vezérlési szerkezetét grafikusan is megadhatjuk. A folyamatábra (flow chart) és a struktogram ennek két elterjedt módja. A folyamatábrán a nyilak mutatják a lépések sorrendjét.

Mire használjuk itt a változót? Arra, hogy megjegyezzük a felhasználótól származó értéket – és később a négyzetét.

## 24. Elágazás: feltételes végrehajtás

Feladat: Írjunk programot, amely kér egy számot a felhasználótól.
Mondja meg, hogy páros-e vagy nem.

A programsorok végrehajtása feltételhez (igazságértékhez) köthető.

### Folyamatábra

### Program

       szam = int(input())
       if szam % 2 == 0:
           print("páros")       ha igen
       else:
           print("páratlan")    ha nem

### Működés

    szam:

==
egyenlő-e
%
maradék

A szám/2 maradékának vizsgálata után a program végrehajtása az elágazás igaz vagy hamis ágában folytatódik. Így a kettő közül mindig csak az egyik felirat íródik ki.

### Szintaxis és fogalmak

    if feltétel:   utána kettőspont
        utasítás
    else:          opcionális
        utasítás

Elágazás (conditional)
  Az egész vezérlési szerkezet, amelyben egy bizonyos programrészlet végrehajtását feltételhez köthetjük.
Feltétel (condition, predicate)
  A logikai kifejezés, amelynek igaz/hamis voltától függ, hogy végrehajtódik-e az adott programrészlet. Ez egy ún. igazságértékre alapozott választás.
Igaz ág, következmény (consequent)
  Az a programrészlet, amely akkor hajtódik végre, ha a feltétel igaz volt.
Hamis ág, „else” ág (alternative)
  Ez akkor hajtódik végre, ha a feltétel hamis volt.

Figyeljünk meg két dolgot a fenti kód szintaktikáján, azaz a Python nyelvtani szabályain! Egyik az, hogy az elágazás feltétele után kettőspontot kell tenni. Másik pedig az, hogy azokat az utasításokat, amelyek a feltétel igaz ágában és hamis ágában vannak, bentebb kell szedni, azaz indentálni kell. Hogy ezt hogyan tesszük, az ízlés kérdése: lehet két szóköz vagy négy szóköz, esetleg tabulátort is használhatunk. Ami nagyon fontos: legyünk konzisztensek, legyen az egész programunk mindenhol egyformán indentálva! Ha nagyon elrontjuk, akkor `IndentationError` típusú hibajelzés a jutalmunk a géptől.

Ebben a tárgyban mi mindenhol szóközöket fogunk használni az indentáláshoz. A Python közösség egy útmutatóban ugyanezt javasolja, és legtöbben ezt használják: PEP 8 – Style Guide for Python Code. (Aki nagyon szembe megy a világgal, arról leginkább azt szokták gondolni, hogy nem ért a programozáshoz...)

## 25. Számok 1-től 10-ig

Feladat: írjunk programot, amelyik kiírja a számokat 1-től 10-ig.

sorminta
:-(

    KIÍR: 1
    KIÍR: 2
    KIÍR: 3
    …
    KIÍR: 8
    KIÍR: 9
    KIÍR: 10

### Probléma

- Egyrészt: kipontozás? Ez nem szép megoldás.
- Másrészt: mi van akkor, ha a felhasználó kellene megmondja, meddig kellenek a számok? A program forráskódja nem függhet a bemenetétől!

A programozásban inkább ne!

## 26. Ciklus: működés

Ciklus (loop): programrész ismétlése, amíg egy feltétel fennáll.

### Folyamatábra

### Program

       print("Meddig írjam ki?")
       n = int(input())

       x = 1
       while x <= n:
           print(x, end=" ")
           x = x+1

       print(".")

### Működés

    n:
    x:

### Fogalmak

elöltesztelő
ciklus

    while feltétel:
        utasítás

Ciklusmag, ciklustörzs (loop body)
  Az ismételt utasítás(ok). Itt a `print(x)` és az `x = x+1`. Ha a ciklustörzsben több utasítás is van, az egy szekvencia, ami Pythonban egyszerűen úgy jelenik meg, hogy egymás alá több utasítást tettünk. Ezért fontos az egységes indentálás: amíg bentebb van a következő sor, addig a ciklus részének fogja azt a gép tekinteni. Az utolsó, pontot kiíró sor már nem része a ciklusnak.
Ciklusfeltétel (loop condition)
  A kifejezés igaz/hamis értéke alapján eldől, hogy végrehajtódik-e a ciklus törzse. Itt az `x <= meddig`.
Elöltesztelő ciklus (pre-test loop)
  A feltételt a ciklustörzsbe lépés előtt ellenőrizzük.
Iteráció (iteration)
  A ciklustörzs egy végrehajtása a program futása közben.
Ciklusváltozó, iterátor (iterator)
  A ciklust vezérlő változó, ha van ilyen (ebben a példában az `X`).

Itt mire jó a változó? Azzal tudjuk elérni azt, hogy a ciklus törzsében lévő kiírás utasítás mindig más számot írjon a képernyőre! Azzal számoljuk, hogy éppen hol tartunk.

A `print()` utasításnál láthatunk egy újdonságot is: az `end=" "` elnevezett paraméter segítségével azt adjuk meg a `print()`-nek, hogy a kiírt dolgok után ne egy újsort kezdjen, hanem mást írjon ki. Jelen esetben egy szóközt tettünk, így az egymás utáni számok közé, bár külön `print()` írta ki őket, szóköz kerül.

A neves paraméterek megadásánál az `=` két oldalára nem szokás szóközt tenni, tehát `end=" "`-t írunk, nem pedig `end = " "`-t. Így a szemünk meg tudja ezt különböztetni az értékadástól. Ezek apró szabályok, amiket nem lehet egyszerre mind megjegyezni, de könnyen hozzá lehet szokni. A tárgy anyagában egész félévben követni fogjuk ezeket a szabályokat.

## 27. Ciklusok: további tudnivalók

### Ciklusfeltételek

- A ciklus bennmaradási feltétele logikai kifejezés
- Újra és újra kiértékelődik minden iterációban
- Ha teljesül, végrehajtódik a törzs, ha nem, a ciklus után folytatódik a program

### Hányszor hajtódnak végre?

- Ahányszor a feltétel teljesül
- Ez lehet 0 is: a törzs egyszer sem hajtódik végre
- A feltétel előbb-utóbb hamissá kell váljon, különben végtelen ciklus (infinite loop) keletkezik

A feltétel hamissá kell váljon előbb-utóbb: praktikusan ez azt is jelenti, hogy a ciklusváltozónak, ha van, az egyes iterációk között változnia kell. Különben ugyanaz marad az értéke, és a ciklus feltételének igazságértéke sem fog változni! Ha nincs olyan utasítás a ciklusban, amely a ciklusváltozó értékét változtatja, az gyanús.

## 28. Ciklusszervezés: olvashatóság!

Számok kiírása 1-től 10-ig:

jól megírt

    i = 1
    while i <= 10:
        print(i)
        i = i+1

rossz, követhetetlen

    i = 0   # :(
    while i <= 9:   # :(
        i = i+1
        print(i)    # :(

Ha áttekinthetően szeretnénk ciklust írni, akkor érdemes az első sémát megtartani. Az ismérvek:

- A ciklus előtt közvetlenül a ciklusváltozó inicializálása szerepel. Ez lesz az első iterációban az értéke, tehát ez az első feldolgozott elem. Ezt ne máshova tegyük, ne messzebbre: közvetlenül elé.
- A ciklustörzsben elöl a teendők szerepelnek. Mivel ez elöl van, ezért a ciklusváltozó értéke az első iterációban éppen a cikluson kívül beállított érték, vagyis az első elem! (Különben a ciklusváltozót olyan értékre kellene inicializálni, amit aztán nem dolgozunk fel, ahogyan az a jobb oldalon is látszik.)
- A ciklustörzs végén az utasítás, amely lép a következő elemre. Ez változtatja a ciklusváltozót. Utána már nem írunk semmit, hiszen akkor egy iteráción belül némely utasítások még a régi, némelyek pedig már az új értékére vonatkoznának.

Ez még jobban látszik egymásba ágyazott ciklusok esetében. Ha ott rossz helyen szerepelnek a kezdeti értékek, akkor váratlan helyeken kezdenek el feleslegesnek látszó értékadások feltűnni. A megoldás erre ugyanaz, mint a fenti esetben: a ciklusok elé kell tenni a hozzájuk tartozó kezdeti értékeket.
Ne így...

    x = 1          # mit keres ez itt :(
    y = 1
    while y <= 5:
        while x <= 5:
            print(x*y, end="\t")
            x = x+1
        print()
        x = 1      # mit keres ez itt :(
        y = y+1

Hanem inkább így!

    y = 1
    while y <= 5:
        x = 1      # itt a helye! :)
        while x <= 5:
            print(x*y, end="\t")
            x = x+1
        print()
        y = y+1

## 29. Szorzótábla

    y = 1
    while y <= 10:
        x = 1
        while x <= 5:
            print(x * y, end="\t")
            x = x+1
        print()     # új sor
        y = y+1

    1       2       3       4       5
    2       4       6       8       10
    3       6       9       12      15
    4       8       12      16      20
    5       10      15      20      25
    ...

Példa: a szorzótábla kirajzolása két ciklussal. Kívül a sorok ciklusa (`y`, tíz iteráció), és azon belül soronként öt szám (`x`, öt iteráció soronként) és egy új sor kezdése. Az `x` változó csak a belső ciklushoz van, így azt érdemes ott létrehozni, mert csak ott használjuk.

Figyeljük meg:

1. A kód tördelése. Az egyes vezérlési szerkezetek belsejében lévő utasítások beljebb kezdődnek. Ez nemcsak hogy kötelező a Pythonban, de a megértést is segíti: látjuk a szorzáson egyből, hogy az cikluson belüli ciklusban van.
2. A változódefiníciók helye. A Python megengedi azt, hogy bárhol változót hozzunk létre. Jelen esetben az `x` nevű változót az `x`-es ciklus előtt hozzuk létre, közvetlenül annak `while` kulcsszava fölött. Nem máshol! Ahhoz a ciklushoz tartozik, ahhoz legyen közel. Ez is a program érthetőségét növeli.
3. A tabulátor karakter. Az egyes kiírt számok közé `"\t"`-t, tabulátor karaktert teszünk. Ez mindig ugrik az ablakban a következő 8-cal osztható sorszámú oszlopra, így a számok egymás alá tudnak kerülni. Így persze sajnos a számok nem helyiérték szerint szerepelnek egymás alatt, de később lesz szó róla, hogyan lehet ezt szebben megoldani.

\
visszaper
(backslash)

A \ visszaper (backslash) karakter a sztringekben speciális karaktereket jelöl meg. A fenti kódban is a `\t` jelentése nem az, hogy ki kell írni egy visszapert, utána pedig egy t betűt; hanem a két karakter együtt egyetlen egy tabulátort jelképez. Léteznek más vezérlőkódok is. Például a `\n`, amellyel egy sztring közepére is írhatunk sortörést:

    print("Hello,\nvilág!")

    Helló,
    világ!

Arra is jó a \, hogy idézőjelet tegyünk egy sztringbe. Innen tudja majd a gép, hogy a következő idézőjel nem a sztring befejezése, hanem csak egy olyan idézőjel, ami része a szövegnek:

    print("London Anglia fővárosa.")
    print("\"London\" egy hat betűs szó.")

    London Anglia fővárosa.
    "London" egy hat betűs szó.

Persze ezt úgy is megoldhattuk volna, hogy magát a sztringet aposztrófok közé tesszük: a Python azt is elfogadja. Az aposztrófok közé tett sztringben az idézőjelnek semmilyen különleges szerepe nincs:

    print('London Anglia fővárosa.')
    print('"London" egy hat betűs szó.')

    London Anglia fővárosa.
    "London" egy hat betűs szó.

Az aposztróf és az idézőjel karaktereket angolul gyakran single quote-nak és double quote-nak is nevezik.

## 30. Vezérlési szerkezetek: összefoglalás

### Strukturált programok (structured programs)

- Amelyek szekvenciából, elágazásból és ciklusból épülnek fel
- Matematikailag bizonyított: minden számítógéppel megoldható feladat megoldható így!

szerkezet | használat | Python
--- | --- | ---
szekvencia | Egymás utáni utasítások. | `utasítás1 utasítás2 utasítás3`
elágazás | Feltételhez között végrehajtás. 0-szor vagy 1-szer. | `if feltétel: utasítás`
ciklus | Ismétlés. 0-tól ∞-ig akárhányszor. | `while feltétel: utasítás`

### Programvezérlés (control flow)

Az utasítások végrehajtásának sorrendje.

- Alapvetően egymás után, de ez megváltoztatható vezérlési szerkezetekkel (control structure).
- Speciális programbeli utasítások tartoznak hozzájuk: ezek a vezérlésátadó utasítások (control flow statement).

A vezérlési szerkezetek lényege az, hogy valamilyen döntés (egy feltétel teljesülése) alapján máshol folytatódik általuk a program végrehajtása – nem a sorban következő utasításnál. A Python egyébként nem is enged mást, csak ezeket a vezérlési szerkezeteket. Nem ugrálhatunk ide-oda a programunkban, nem írhatunk ún. spagetti kódot.

A spagetti kóddal az a baj, hogy az ugrásoknál sose tudni, mire valók, mi a céljuk. Elágazást szeretnénk, elvégezni egy műveletet vagy átugrani, kihagyni? Vagy azért ugrunk valahova, mert meg szeretnénk ismételni valamit? Folyton keresgélni kell a kódban, hogy előre vagy hátrafelé ugrunk, beleugrunk egy műveletsor belsejébe, kiugrunk belőle, megszakítva azt.

A vezérlési szerkezeteknek az is az értelme, hogy jelezni tudjuk, miért ugrunk, mire használjuk az ugrást. Amikor visszaugrunk egy pontra a programban, általában azért tesszük, hogy megismételjünk egy műveletet, műveletsort. Ha előrefelé, azt pedig azért, hogy kihagyjunk egy műveletet, hogy feltételhez kössük annak végrehajtását. Különböztessük meg ezeket, rendeljünk ezekhez különálló vezérlésátadó utasításokat! Ha így teszünk, sokkal érthetőbb lesz a programunk.

## 31. A Python nyelv elemei

Név | Példa | Használat
--- | --- | ---
kulcsszó (keyword) | `while, if` | a nyelv része, valamilyen speciális jelentése van
azonosító (identifier) | `x, terulet` | valami neve, pl. változóé
operátor (operator) | `* + / **` | számítási művelet
megjegyzés (comment) | `# magyarázat` | programozóknak szóló, megértést könnyítő szöveg
szám (numeric) | `12, 6.0e23` | egész és valós számok
sztring (string) | `"helló, világ"` | szöveg

Érdemes ezen nyelvi elemek neveit magyarul és angolul is ismerni; a szakirodalomban és a gép hibaüzeneteiben rengeteget találkozunk velük.

A számokat és a sztringeket összefoglaló néven literálisoknak nevezzük (literal). Ezek azok a részek a forráskódban, amiket szó szerint kell érteni. Egy változónál ez nem igaz, mert a változóval igazából a benne tárolt értéket hivatkozzuk meg valójában.

### A nyelvtan leírása

Érdemes tudni róla, hogy a programozási nyelvek nyelvtani szabályait formálisan is rögzíteni szokták. Egyik nyelv, amivel nyelvtani szabályok leírhatók, az ún. EBNF, Extended Backus-Naur Form. Ennek jelölései a következők:

Jelölés | Jelentés | Példa
--- | --- | ---
::= | definíció | névelő ::= "egy"
" " | szöveg
| | „vagy” | számjegy ::= "0" | "1" | …
| összefűzés (nincs jelölve külön) | negatív ::= "-" szám
[ ] | elhagyható | pozitív ::= ['+'] szám
* | ismétlés (akár 0) | sztring ::= ' " ' karakter* ' " '
+ | ismétlés (1 vagy több) | szó ::= betű+

Példaként a pozitív egész szám nyelvtani szabályainak leírása EBNF-ben:

    szám ::= nemnulla számjegy*
    számjegy ::= "0" | nemnulla
    nemnulla ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

- Akárhány számjegyből állhat, nem kezdődhet nullával; mert a legelső számjegyet a `nemnulla` szabály definiálja, a többit a `számjegy`.
- Helyes: 98, 54079, 43, 1, 112.
- Helytelen: 1ax, abcd, s98, 012.

A Python nyelv dokumentációja is tartalmaz EBNF szabályokat. De ebből dolgoznak azok is, akik a fordítóprogramot írják: ha matematikai precizitással adottak a nyelvtani szabályok, akkor a nyelv minden mondatát könnyű értelmezni.

## 32. Összefoglalás

Az előadáson megismertek alapján tudni kell:

- Változókat definiálni és használni
- Különböző típusok között konvertálni
- Különböző típusokon értelmezett műveleteket és speciális kifejezéseket, mint pl. 6.0e23, vagy az escape szekvenciák, pl. "\n"
- Egyszerű programokat írni, amelyek bekért adatokon műveleteket végeznek, mint pl. a kör területének számítása
- Feltételes elágazást és egymásba ágyazott ciklusokat használni