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?! :)
Honlap, adminisztrációs portál
Az információ hiteles forrása: https://infopy.eet.bme.hu/
Konzultáció: kérdések, nagy házi stb.
Saját laborvezetők! A portálon lehet üzenetet írni.
Oktatás: kétféle óra
- Előadás: ez most itt
- Labor: géptermi órák – önálló munka, programozás
- Labor átjelentkezés: első két héten, fogadó oktató beleegyezésével
- Labormunka feltöltése
Az előadásokra épülnek a laborok. Ezt figyelembe véve készült a tematika is. Ezért lesz az jellemző a félévben, hogy a laborokon vett feladatok régebbi, egy-két héttel előbbi előadásanyaghoz kötődnek. A laborokra készülve, az előadásanyagot megértve érdemes menni, különben haszontalan az ott töltött idő.
A labor órákhoz fognak kötődni a kis ZH-k és a nagy házi feladat is. A laborokon az egyik oktatótok feladata lesz a kis ZH-k javítása, a másik a nagy házi feladat konzultálása és értékelése – de természetesen bármelyik laborvezetőt megkereshetitek a kérdéseitekkel!
Számonkérések a félév közben
- Részvétel: jelenlét előadáson és laboron
- KZH: kisebb feladatok, 20–25 soros programok írása
- NZH: kb. 4–5× KZH
- NHF: egyénileg írt program dokumentációval
- Szorgalmik: megajánlott jegy szerezhető
Vizsgaidőszakban
- Vizsga a teljes anyagból; jegy a vizsgadolgozat és NHF alapján
- Megajánlott jegy, nem kell vizsgázni, ha jó ZH-k + szorgalmik
- Laborra hozhattok saját gépet, de a laborgépeket megbontani nem szabad. (nem dughatod a laptopodra a laborban lévő monitort, egeret, billentyűzetet stb.)
- WiFi kapcsolatot intézd el ld. bme intranet
- Saját gépen zárthelyit zárthelyit nem lehet írni
- A számonkéréseken a feladatokat az IDLE segítségével kell elkészíteni, más fejlesztőrendszer nem használható
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 olyany
,
amirey2=x
,
ésy≥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.
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
é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.
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
- „az összes számjegyet”
- „add össze”
- „ha eléri a 10-et, van átvitel”
- …
20│2 10│2 5│5 1│
- „amíg nagyobb, mint 1”
- „ha osztható”
- „írd le az osztót”
- …
A programozásban a módszerek, algoritmusok szöveges leírását adjuk meg.
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.
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 tradicionális első program forráskódja:
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.
# 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 ·
.
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í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 |
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
kifejezés | érték |
---|---|
1+2 | 3 |
5+2*3 | 11 |
6*(3+4) | 42 |
kifejezés | érték |
---|---|
1<2 | igaz |
2≥3 | hamis |
"a" < "b" | igaz |
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.
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.
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 jelex = 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.
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.
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.
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
.
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" → 123float(x)
: sztring → valós szám, pl. "3.14" → 3.14str(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.
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
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.
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.
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...)
Feladat: írjunk programot, amelyik kiírja a számokat 1-től 10-ig.
:-(
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!
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
ciklus
while feltétel: utasítás
- Ciklusmag, ciklustörzs (loop body)
- Az ismételt utasítás(ok). Itt a
print(x)
és azx = 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.
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.
Számok kiírása 1-től 10-ig:
i = 1
while i <= 10:
print(i)
i = i+1
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.
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
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
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:
- 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.
- 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 azx
-es ciklus előtt hozzuk létre, közvetlenül annakwhile
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. - 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.
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
|
elágazás | Feltételhez között végrehajtás. 0-szor vagy 1-szer. | if feltétel:
|
ciklus | Ismétlés. 0-tól ∞-ig akárhányszor. | while feltétel:
|
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.
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 aszá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.
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