2018. szeptember 3., hétfő

Kiválogatás

Generátor

A generátor a kiválogatás tételének egy nagyon egyszerű, nagyon „pythonos” megvalósítása lehet. A generátornak kijelölt függvény végigmegy a kiválogatandó sokaságon, majd a feltételnek megfelelő tételeket a yield kulcsszóval adja vissza. A yield hasonlít a jól ismert returnhöz, azzal az eltéréssel, hogy sok értéket is vissza tud adni egymás után. A hívó a for ciklussal tudja feldolgozni a kapott értékeket. A vezérlés minden iterációnál visszakerül a hívó függvényhez, miközben mindkét függvény, a hívó és a generátor is megőrzi belső állapotát.

A generátorral megvalósított kiválogatási eljárás különlegessége, hogy a kapott adatokat nem kell tárolni. Ettől sokkal rugalmasabb lesz a használata, mert a gyakran használt kiválogatásokat generátorként tárolhatjuk egy modulban, nem törődve azzal, hogy hova kerül majd az eredmény, illetve elkülöníthetjük a kiválogatást a feldolgozástól. Első példánk egy ilyen felhasználást mutat be. (Ennek a módszernek egy nagyon hatékony alkalmazását láthatjuk a pywikibot lapgenerátoraiban.)

A generátort nem csak kiválogatásra használhatjuk, hanem bármilyen sorozat előállítására (iterálására). Második példánk, a Fibonacci-számok generálása a lenti linken olvasható dokumentációból van kimásolva. Általában nagyon hasznos olyan függvény írására, amely két hívás között megőrzi a belső állapotát.

A yield utasítás nem állhat egy try/finally szerkezet try ágában. Nincs azonban megkötés a finally ágban vagy a try/except bármelyik ágában való használatra nézve.

Tartalomjegyzék[megjelenítés]
Első példa: kiválogatásSzerkesztés
Medicin Mihály testnevelés szakos osztályfőnök egy egyszerű állományban, név szerint rendezve tárolja a gyerekek néhány adatát. A wikin való olvashatóság kedvéért most mellőzzük a beolvasást, és egy globális változóban tároljuk a feltételezett adatok egy részét szöveges formátumban (ez persze az osztálynak csak egy része, de a feladat bemutatásához elég). Az itt látható gyerekek változó egy listákból álló lista. Az osztályba 1996-ban és 1997-ben született gyerekek járnak.

Medicin tanár úr még a tanév kezdetén elkészítette az 1996-ban született fiúk generátorfüggvényét, amikor az igazgatóhelyettes a nagyon fontos statisztikákat kérte tőle. Most a védőnő kéri az 1996-ban született fiúk listáját születési dátummal és TAJ-számmal, mert a jövő kedden az informatikaóra alatt ők fognak iskolaundor elleni védőoltásban részesülni. Péntek délután négykor pedig a kerületi diáksportszövetség elnöke telefonál, hogy szombat délelőttre ki kéne állítani egy kispályás focicsapatot 96-ban született fiúkból, mert a szomszéd iskola testnevelő tanára reggel nyolckor átment a versenyszférába háromszor annyi fizetésért, így ők kénytelenek voltak visszalépni a bajnokságból, és a selejtező eredménye alapján Medicin tanár úr iskolája került be a helyükre. Nincs más választása, mint rávetni magát a telefonra, és megpróbálni összerántani egy csapatot.

Lássuk, hogyan oldja meg ezt a két feladatot a generátorfüggvénnyel! Először kinyomtatja a védőnő által kért adatokat. Mivel igényes ember, ezért a szeletelés segítségével hozza egyforma hosszúságúra a neveket, az adatokat pedig vezetővonalakkal választja el (ez a print függvény opcionális paramétere). Ezt követően a fiúk nevét és telefonszámát írja ki magának, a számokat formázott stringként tagolva, hogy tárcsázás közben ki ne essen a szeme. (Ez a C nyelv printf függvényéhez hasonló módon történik.)

Check Tesztelve a 3.1.2 verzióban.

gyerekek=[
    #Név, nem, szül., telefon, TAJ
    ['Bögi Bernát','f','19961119','305554433','111222329'],
    ['Egri Sára','l','19970218','709999555','111449011'],
    ['Heves Károly','f','19960925','701000111','111222317'],
    ['Joó Lujza','l','19970617','306666888','111246975'],
    ['Kovács Ágnes','l','19961230','701113333','111446789'],
    ['Kúti Herbert','f','19970305','703693690','111345876'],
    ['Pesti Imre','f','19970106','304444111','111447900'],
    ['Samu Tibor','f','19961111','206666999','111222325'],
    ['Szabó Ferenc','f','19960831','201111222','111222313'],
    ['Szabó Katalin','l','19970403','302224567','111246864'],
    ['Szegedi Nikolett','l','19970312','704455667','111345975'],
    ['Székely Áron','f','19961014','309999888','111222321'],
    ['Vas Edit','l','19961123','306666666','111445678'],
    ]

def fiúk96():
    for gyerek in gyerekek:
        if gyerek[1]=='f':
            if gyerek[2].startswith('1996'):
                yield(gyerek)

def védőnőnek():
    for gy in fiúk96():
        print((gy[0]+'     ')[:15],gy[2],gy[4],sep='____')

def focicsapat():
    for gy in fiúk96():
        t=gy[3]
        print(gy[0],'06 (%s) %s-%s'%(t[:2],t[2:5],t[-4:]))

védőnőnek()
print('\n'*3)   #Ez négy üres sorral választja el a kettőt, mert egy '\n' van a printben is
focicsapat()
Az eredmény:

Bögi Bernát    ____19961119____111222329
Heves Károly   ____19960925____111222317
Samu Tibor     ____19961111____111222325
Szabó Ferenc   ____19960831____111222313
Székely Áron   ____19961014____111222321




Bögi Bernát 06 (30) 555-4433
Heves Károly 06 (70) 100-0111
Samu Tibor 06 (20) 666-6999
Szabó Ferenc 06 (20) 111-1222
Székely Áron 06 (30) 999-9888
Második példa: a Fibonacci-számokSzerkesztés
def fib():
    a, b = 0, 1
    while 1:
        yield b
        a, b = b, a+b
Ez a példa a generátorok dokumentációjából (PEP 255) származik. A hívó függvény egy sorozatot lát, amelyet a fib() állít elő a számára; a fib() számára azonban a yield csak egy ugyanolyan utasítás, mint mondjuk a print, amely után zökkenőmentesen, a változók értékének megtartásával folytatódhat a futás. Vegyük észre, hogy a fenti kiválogatással ellentétben itt végtelen iteráció jön létre, amely, ha ugyanolyan módon hívnánk, végtelen ciklust eredményezne. A

for f in fib():
    print (f)
ciklus végkimerülésig ontja a Fibonacci-számokat a képernyőre, s csak a ctrl C segítségével léphetünk ki belőle. Kicsit elegánsabban is megoldhatjuk a kivételkezeléssel:

print("Megszakítás Ctrl C-vel!")
for f in fib():
    try:
        print f
    except KeyboardInterrupt:
break

Nincsenek megjegyzések:

Megjegyzés küldése