1. fejezet
Adat név szerint: a szótár
A listában az elemeket sorszámuk (indexük) alapján érjük el. Sokszor azonban természetesebb egy név szerint keresni: egy diák jegye a diák neve alapján, egy termék ára a termék neve alapján, egy szó jelentése a szó alapján. Erre való a szótár.
A szótár kulcs–érték párokat tárol. Minden kulcshoz pontosan egy érték tartozik, és a kulcsok egyediek. Az értéket a kulcs alapján érjük el: arak["alma"]. Kulcs csak megváltoztathatatlan érték lehet (szöveg, szám, megváltoztathatatlan elemekből álló tuple), érték bármi.
diak = {
"nev": "Kiss Anna",
"kor": 17,
"varos": "Pécs",
}
print(diak["nev"])
print(diak["kor"] + 1)
print(len(diak))
print(diak)
Kövesd lépésenként: a Memóriában a szótár egy kétoszlopos táblázatként jelenik meg, bal oldalon a kulcsokkal, jobb oldalon az értékekkel. A szótár megőrzi a beszúrás sorrendjét, de indexe nincs: a diak[0] nem az első elemet jelenti, hanem a 0 kulcsot keresi.
2. fejezet
Lekérés: [], get() és in
Nem létező kulcsra a szotar[kulcs] KeyError-t ad. Ha nem vagyunk biztosak benne, hogy a kulcs létezik, két biztonságos út van:
kulcs in szotar– megvizsgálja, hogy a kulcs benne van-e (a kulcsok között keres, nem az értékek között);szotar.get(kulcs)– az értéket adja, nem létező kulcsnál pedigNone-t;szotar.get(kulcs, alap)ilyenkor azalapértéket.
arak = {"alma": 450, "körte": 620, "banán": 590}
termek = input("Melyik termék ára érdekel? ")
if termek in arak:
print(f"A(z) {termek} ára {arak[termek]} Ft/kg.")
else:
print("Ilyen termékünk nincs.")
print("Szilva:", arak.get("szilva"))
print("Szilva:", arak.get("szilva", "nincs készleten"))
arak = {"alma": 450, "körte": 620}
print(arak["szilva"])
Mit ír ki?
d = {"a": 1, "b": 2}
print("a" in d, 1 in d, d.get("c", 0))
True True 0True False 0True False None
Az in a kulcsok között keres: az "a" kulcs, az 1 csak érték, ezért False. A get("c", 0) a nem létező kulcsra a megadott alapértéket, a 0-t adja.
3. fejezet
Hozzáadás, módosítás, törlés
| Művelet | Hatás |
|---|---|
d[kulcs] = ertek | ha a kulcs új: hozzáadja; ha már létezik: felülírja az értékét |
del d[kulcs] | törli a párt (nem létező kulcsnál KeyError) |
d.pop(kulcs) | törli és visszaadja az értéket; d.pop(kulcs, alap) nem ad hibát |
d.update(masik) | átveszi a másik szótár összes párját (a meglévőket felülírja) |
d.clear() | minden párt töröl |
keszlet = {}
keszlet["alma"] = 120
keszlet["körte"] = 40
keszlet["alma"] = keszlet["alma"] - 20
keszlet.update({"szilva": 75, "körte": 55})
eladva = keszlet.pop("szilva")
print("Szilvát vittek:", eladva)
print(keszlet)
Az értékadás nem ellenőrzi, hogy a kulcs létezik-e: ha elírod (keszlet["Alma"] = 50), egy új kulcs jön létre, és a régi "alma" változatlan marad. A kulcsoknál a kis- és nagybetű is számít.
Mit ír ki?
d = {}
for betu in "anna":
d[betu] = d.get(betu, 0) + 1
d["a"] = 5
print(d)
{'a': 5, 'n': 2}{'a': 2, 'n': 2}{'n': 2, 'a': 5}
A ciklus után a szótár {'a': 2, 'n': 2}. A d["a"] = 5 létező kulcsra mutat, ezért nem új párt hoz létre, hanem felülírja az értéket – a kulcs a helyén marad, így a sorrend is (a szótár a kulcsok első beszúrásának sorrendjét őrzi).
4. fejezet
Bejárás: keys(), values(), items()
A for k in d a kulcsokon megy végig. Ha az értékek kellenek, a d.values()-n, ha mindkettő, a d.items()-en – ez utóbbi párokat (tuple-öket) ad, amelyeket a ciklus fejében rögtön kicsomagolunk.
jegyek = {"Anna": 5, "Bence": 3, "Csilla": 4}
for nev in jegyek:
print(nev, end=" ")
print()
print(list(jegyek.keys()))
print(list(jegyek.values()), "átlag:", sum(jegyek.values()) / len(jegyek))
for nev, jegy in jegyek.items():
print(f"{nev}: {jegy}")
for nev in sorted(jegyek):
print(nev, jegyek[nev])
Bejárás közben ne adj hozzá és ne törölj kulcsot ugyanabból a szótárból – RuntimeError-t kapsz. Ha törölni kell, gyűjtsd ki előbb egy listába a törlendő kulcsokat, és utána töröld őket. A meglévő kulcsok értékét viszont bejárás közben is szabad módosítani.
5. fejezet
A legfontosabb minta: számlálás szótárral
Hányszor fordul elő egy-egy szó a szövegben? Hány tanuló kapott egyes, kettes, … ötös jegyet? A szótár kulcsai a „kategóriák”, az értékei a darabszámok. Minden elemnél eggyel növeljük a hozzá tartozó számlálót – ha a kulcs még nincs a szótárban, 0-ról indulva:
szoveg = input("Szöveg: ")
gyakorisag = {}
for szo in szoveg.lower().split():
gyakorisag[szo] = gyakorisag.get(szo, 0) + 1
print(gyakorisag)
leggyakoribb = None
for szo, db in gyakorisag.items():
if leggyakoribb is None or db > gyakorisag[leggyakoribb]:
leggyakoribb = szo
print(f"Leggyakoribb: „{leggyakoribb}” ({gyakorisag[leggyakoribb]}×)")
A kulcssor a gyakorisag.get(szo, 0) + 1: ha a szó már szerepelt, a régi számlálóhoz ad egyet; ha nem, a 0 alapértékhez – így az első előfordulásnál 1 lesz. Kövesd lépésenként, és figyeld, ahogy a szótár sorai megjelennek és nőnek. A leggyakoribb szó keresése a 3. modul szélsőérték-mintája, csak most a szótár párjain. A leggyakoribb szó keresésénél a leggyakoribb is None feltétel az első kört ismeri fel: az is azt vizsgálja, hogy a két oldal ugyanaz az objektum-e – a None-ra mindig így kérdezünk rá.
A collections modul Counter osztálya pontosan ezt a számlálást végzi el egy sorban (Counter(szavak).most_common(3)). A kézi változatot azért érdemes ismerni, mert a minta sok más feladatban is visszatér (összegzés kategóriánként, csoportosítás).
6. fejezet
Összetett adatok: szótárban lista, listában szótár
Az érték bármi lehet – lista vagy újabb szótár is. Így írhatók le a valódi, többszintű adatok. Az elérés láncolt indexeléssel történik, kívülről befelé.
naplo = {
"Anna": {"matematika": [5, 4, 5], "magyar": [4, 4]},
"Bence": {"matematika": [3, 2], "magyar": [5, 4, 5]},
}
print(naplo["Anna"]["matematika"])
print(naplo["Anna"]["matematika"][-1])
naplo["Bence"]["matematika"].append(4)
for nev, tantargyak in naplo.items():
for targy, jegyek in tantargyak.items():
atlag = sum(jegyek) / len(jegyek)
print(f"{nev:7} {targy:11} {jegyek} átlag: {atlag:.2f}")
A lépésenkénti nézetben jól látszik a szerkezet: a naplo szótár értékei újabb szótárakra mutatnak, azok értékei pedig listákra.
Listában szótárak: rekordok
Táblázatszerű adatokat (sorok, mindegyikben ugyanazok a mezők) gyakran szótárak listájaként tárolunk – minden szótár egy „rekord”:
termekek = [
{"nev": "laptop", "ar": 250000, "keszlet": 5},
{"nev": "egér", "ar": 5000, "keszlet": 0},
{"nev": "monitor", "ar": 65000, "keszlet": 12},
]
osszertek = 0
for t in termekek:
if t["keszlet"] == 0:
print(f"Elfogyott: {t['nev']}")
osszertek += t["ar"] * t["keszlet"]
print(f"A raktár értéke: {osszertek} Ft")
Az f-stringben a szótárkulcs idézőjele legyen más, mint az f-string idézőjele: f"{t['nev']}". (Python 3.12 óta az azonos idézőjel is működik, de a régebbi verziók – és sok olvasó – számára ez zavaró.)
Másolás többszintű adatnál
A copy() a szótárnál is sekély másolatot készít: új külső szótár jön létre, de az értékként tárolt listák közösek maradnak. Kövesd lépésenként, és figyeld a Memóriában a nyilakat:
jegyek = {"Anna": [5, 4], "Bence": [3]}
masolat = jegyek.copy()
masolat["Cili"] = [5] # új kulcs: csak a másolatban
masolat["Anna"].append(2) # a közös listát módosítja!
print(jegyek)
print(masolat)
Az új kulcs csak a másolatba került, Anna új jegye viszont mindkét szótárban megjelent, mert a két "Anna" kulcs ugyanarra a listára mutat. Ha a belső listákat is le kell másolni, arra a copy modul deepcopy() függvénye való (mély másolat).
7. fejezet
Gyakorló feladatok
Telefonkönyv
A program elején adott egy telefonkönyv szótárként. Kérj be egy nevet, és írd ki a hozzá tartozó számot – vagy azt, hogy nincs ilyen név.
Név: Bence
Bence száma: 30/234-5678
Ismeretlen névnél: Nincs ilyen név a telefonkönyvben.
telefonkonyv = {"Anna": "20/123-4567", "Bence": "30/234-5678", "Csilla": "70/345-6789"}
telefonkonyv = {"Anna": "20/123-4567", "Bence": "30/234-5678", "Csilla": "70/345-6789"}
nev = input("Név: ")
if nev in telefonkonyv:
print(f"{nev} száma: {telefonkonyv[nev]}")
else:
print("Nincs ilyen név a telefonkönyvben.")
Tipp
if nev in telefonkonyv: – az in a kulcsok között keres.
Betűgyakoriság
Kérj be egy szöveget, és számold meg szótárral, melyik betű hányszor fordul elő (a szóközt hagyd ki, kis- és nagybetűt ne különböztesd meg). Az eredményt rendezve (sorted()) írd ki, soronként betű: db alakban.
Szöveg: alma a fa alatt
a: 5
f: 1
l: 2
m: 1
t: 2
szoveg = input("Szöveg: ").lower()
gyakorisag = {}
for betu in szoveg:
if betu != " ":
gyakorisag[betu] = gyakorisag.get(betu, 0) + 1
for betu in sorted(gyakorisag):
print(f"{betu}: {gyakorisag[betu]}")
Tipp
Számlálás szótárral: gy[betu] = gy.get(betu, 0) + 1. Rendezve: for betu in sorted(gy):.
Kosár összege
Adott egy árlista. Olvass be termékneveket üres sorig (ugyanaz többször is szerepelhet). Az ismeretlen termékre írd ki: Nincs ilyen termék: dinnye, és hagyd ki. A végén írd ki a kosár végösszegét.
Termék: alma Termék: alma Termék: kenyér Termék: dinnye Nincs ilyen termék: dinnye Termék: tej Termék: Fizetendő: 2069 Ft
arak = {"alma": 450, "kenyér": 690, "tej": 479, "sajt": 1290}
arak = {"alma": 450, "kenyér": 690, "tej": 479, "sajt": 1290}
osszeg = 0
termek = input("Termék: ")
while termek != "":
if termek in arak:
osszeg += arak[termek]
else:
print("Nincs ilyen termék:", termek)
termek = input("Termék: ")
print(f"Fizetendő: {osszeg} Ft")
Tipp
Végjelig olvasás üres szöveggel; a cikluson belül if termek in arak: döntsön az összeadásról.
Szótár megfordítása
Írj megfordit(szotar) függvényt, amely egy új szótárat ad vissza, amelyben a kulcsok és az értékek helyet cserélnek (feltételezheted, hogy minden érték különböző). Az eredeti szótár ne változzon.
megfordit({"egy": 1, "kettő": 2}) → {1: 'egy', 2: 'kettő'}
def megfordit(szotar):
pass
print(megfordit({"egy": 1, "kettő": 2}))
def megfordit(szotar):
uj = {}
for kulcs, ertek in szotar.items():
uj[ertek] = kulcs
return uj
print(megfordit({"egy": 1, "kettő": 2}))
Tipp
Új, üres szótárból indulj, járd be az eredetit items()-szel, és minden párt fordítva tegyél bele: uj[ertek] = kulcs.
Jegyeloszlás
Olvass be egy sornyi érdemjegyet (1–5). Számold meg szótárral, melyik jegyből hány van, és írd ki 5-östől 1-esig az összes jegyet (azokat is, amelyekből egy sincs), majd a leggyakoribb jegyet. Holtversenyben a jobb jegy nyerjen.
Jegyek: 5 4 5 3 4 5 2
5: 3 db
4: 2 db
3: 1 db
2: 1 db
1: 0 db
Leggyakoribb: 5
db = {}
for d in input("Jegyek: ").split():
jegy = int(d)
db[jegy] = db.get(jegy, 0) + 1
leggyakoribb = 5
for jegy in range(5, 0, -1):
print(f"{jegy}: {db.get(jegy, 0)} db")
if db.get(jegy, 0) > db.get(leggyakoribb, 0):
leggyakoribb = jegy
print("Leggyakoribb:", leggyakoribb)
Tipp
A hiányzó jegyeknél a db.get(jegy, 0) ad 0-t. Ha 5-től lefelé haladsz, és csak akkor cserélsz, ha szigorúan nagyobb darabszámot találsz, holtversenyben automatikusan a jobb jegy marad.
Osztálynapló átlagai
Írj atlagok(naplo) függvényt. A naplo egy szótár, amelyben a tanulók nevéhez a jegyeik listája tartozik. A függvény adjon vissza egy új szótárat a tanulók nevével és a jegyeik átlagával, két tizedesjegyre kerekítve (round(x, 2)). Akinek nincs jegye, annak az átlaga None legyen.
atlagok({"Anna": [5, 4, 5], "Bence": [3, 2], "Csaba": []})
→ {'Anna': 4.67, 'Bence': 2.5, 'Csaba': None}
def atlagok(naplo):
pass
print(atlagok({"Anna": [5, 4, 5], "Bence": [3, 2], "Csaba": []}))
def atlagok(naplo):
eredmeny = {}
for nev, jegyek in naplo.items():
if jegyek:
eredmeny[nev] = round(sum(jegyek) / len(jegyek), 2)
else:
eredmeny[nev] = None
return eredmeny
print(atlagok({"Anna": [5, 4, 5], "Bence": [3, 2], "Csaba": []}))
Tipp
Járd be a naplót items()-szel; az üres lista hamis, így if jegyek: eldönti, van-e jegy.
8. fejezet
Összefoglalás
| Eszköz | Lényeg |
|---|---|
{"kulcs": ertek} | szótár; a kulcsok egyediek, megváltoztathatatlanok |
d[k], d.get(k, alap) | lekérés; nem létező kulcsnál KeyError / az alapérték |
k in d | a kulcsok között keres |
d[k] = v, del d[k], pop, update | hozzáadás vagy felülírás, törlés |
keys(), values(), items() | bejárás: for k, v in d.items(): |
d[k] = d.get(k, 0) + 1 | számlálás szótárral |
Gyakorold tovább: készíts egy egyszerű szókártya-játékot: egy magyar–angol szótárból a program véletlen sorrendben kérdezze ki a szavakat (random.shuffle a kulcsok listáján), számolja a jó válaszokat, a hibásakat pedig a végén ismételtesse meg.