Python Panoráma 1: Hogyan építsünk interaktív szótárat?13 perc olvasás

BEMUTATKOZÓ

Kezdésként szeretném kicsit körülírni és bemutatni, hogy mi is ez a misztikus “Python Panoráma” nevű sorozat és milyen céllal készült el valójában. Úgy gondolom tagadhatatlan, hogy a világunkat egyre jobban meghatározó olyan fogalmak, megközelítések és technológiák, mint az automatizáció, IoT, BigData és data mining masszívan kezdenek elterjedni a komplex üzleti vagy tudományos problémák megoldására szakosodott emberek eszköztárában.

Ahhoz, hogy valaki megfelelően ütemet tudjon tartani ezekkel a trendekkel elengedhetetlen valamilyen szintű programozási ismeret. Végülis ebből a gondolatból ered ez a sorozat is, amelynek tartalmát részben egy Udemy-n elérhető Python kurzusból merítettem. A kurzusért külön köszönet Ardit Sulce-nak. A Python Panoráma cikksorozat végső célja, hogy a lehető legátfogóbb képet nyújtsa arról, hogy milyen lehetőségeket nyújt egy programozási nyelv használata és milyen alkalmazásai lehetnek a valóéletben.

Ebben a sorozatban a Python a kitüntetett szerepű programozási nyelv, de természetesen más nyelvek használatával is kivitelezhetők a bemutatott módszerek. A Python sok szempontból egy jó választás azoknak, akik adatelemzői területen dolgoznak/szeretnének dolgozni. Egyrészt a Python egy igencsak interaktív, dinamikus és nagyon magas szintű programozási nyelv, amely integrációs képességeinek (C, C++ és Java) köszönhetően egy rendkívül elterjedt programozási nyelv szinte minden területen. Másrészt különösen kiterjedt support könyvtárrendszere van és számtalan third-party package érhető el hozzá online, amelyek segítségével nagymértékben kibővülnek a lehetőségeink. Sokszor ilyen package-ket fogunk felhasználni az alkalmazások elkészítése során.

Összesen 10 alkalmazást fogunk létrehozni a sorozatban. Minden egyes alkalmazás más és más funkciót fog betölteni és természetesen mások lesznek az ezeknél alkalmazott eszközök is. Azonban az első két alkalmazás után észrevehetjük, hogy ezek összekapcsolása lehetséges és ténylegesen növeli azok használhatóságát és egyben értékét is. Tehát amin végig megyünk minden cikk során:

  1. Cél meghatározása
  2. Hogyan lehet megvalósítani és kiterjeszteni?
  3. Milyen üzleti felhasználásra érdemes figyelembe venni és hogyan lehetne annak érdekében továbbfejleszteni?

HOGYAN ÉPÍTSÜNK INTERAKTÍV SZÓTÁRAT?

CÉL

Az első részben azt nézzük meg, hogy lehet a Python és a hozzátartozó könyvtárak használatával viszonylag könnyedén egy alapvető interaktív szótárat felépíteni. Később ezt továbbfejlesztjük, hogy a kisebb problematikus esetek kellemetlenségeit is feloldjuk. Az alapvető célkitűzés az, hogy egy olyan programot írjunk, amellyel a felhasználó képes kapcsolatba lépni és a számára megfelelő adatokat kinyerni. Jelen esetben a program outputja, mivel egy szótárral beszélünk, jellemzően egy szó definíciója vagy definíciói.

Egy ilyen program megírásához szükséges egy fájl amelyben az egyes szavakhoz megtalálhatók a hozzátartozó definíciók. Ez a mi esetünkben egy .json fájlt jelent, ebből fogja kinyerni a programunk az outputot mikor a felhasználó egy szóra rákeres. Ez a  fájl megtalálható itt.

Persze amellett, hogy a program a keresett szóhoz megadja a hozzátartozó definíciót, számos más dologra, kell még figyelnünk. Például, hogy a programunk mit kezdjen akkor, mikor a felhasználó elírja a keresett szót vagy arra és érdemes elgondolkoznunk, hogy milyen elemeket tehetünk még bele a programba, hogy minél használhatóbbá váljon az. Hát akkor vágjunk is bele.

MEGVALÓSÍTÁS

Ahogy azt már említettem a Python azért is egy jó választás, mert rendkívül széles support könyvtárrendszerrel rendelkezik. Ezt már rögtön az első alkalmazásnál is megtapasztalhatjuk, hiszen kezdésként már egyből azt kell megoldanunk, hogy a Python scriptünk adatokat tudjon kinyerni a .json fájlunkból. Ehhez elsőként importálnunk kell a “json” nevű könyvtárat, majd abból be kell olvasnunk az adatokat és elmenteni azokat egy változóban. Legyen ez most a “data” változó. Következő lépésként egy inputot kérünk a felhasználótól (word), hogy milyen szóra keressen rá a scriptünk. Az input megadása után pedig a programunknak össze kell hasonlítania a beírt szót a data-ban elmentett szótár szavaival és kiírnia a hozzátartozó definíciókat.

Eddig tehát valahogy, így kell kinézni a kódunknak:

import json

data = json.load(open("data.json"))

word = input("Enter word: ")
output = translate(word)

print(output)

Most pedig definiáljuk, hogy mit is csinál az a misztikus translate függvény. A translate függvény hasonlítja össze a keresett szót a szótárban lévőkkel. Na most, ha megnézzük a data vagy a json fájl tartalmát akkor láthatjuk, hogy a szavak után egy kettőspont és egy python lista áll, amelynek elemei a definíciók.

Ennek tudatában alakítjuk át a translate függvényt és a kiírattatást is. A translate függvénybe egy feltételes blokkot rakunk, amely megvizsgálja, hogy a beírt szó benne van-e a szótárban vagy nincs. Ha benne van akkor visszaadja a szóhoz tartozó listát, ha nincs akkor tájékoztatja a felhasználót, hogy a keresés eredménytelen volt. A kiírattatást pedig úgy módosítjuk, hogy a definíciókat ne egy listaként, hanem egymás alá írva adja vissza, amennyiben a beírt szó megtalálható a szótárban. Ez még egy if block-ot jelent.

import json

data = json.load(open("data.json"))

def translate(w):
    w = w.lower()
    if w in data:
        return data[w]
    else:
        return "The word doesn't exist. Please double check it."

word = input("Enter word: ")
output = translate(word)

if type(output) == list:
    for item in output:
        print(item)
else:
    print(output)

Ezzel nagyjából el is jutottunk az alapvető programunkhoz. Azonban van még rajta mit csiszolni, hogy sokkal okosabb és felhasználóbarátabb legyen. Egy fontos előrelépést jelente ebbe az irányba, ha programunk képes lenne felismerni, ha a felhasználó elírja a szót és adna valamilyen javaslatot, arra milyen szóra szeretett volna rákeresni a felhasználó. Ehhez ismét egy hasznos kis Python könyvtárat fogunk használni. Importáljuk tehát a difflib-ből a get_close_matches könyvtárat.

A get_close_matches függvény képes arra, hogy kiszámolja két szó között hasonlósági arányszámot és ezen arányszámok alapján készít egy listát. Az arányszám egyébként 0 és 1 közötti értéket vehet és értelemszerűen minél magasabb, annál jobban hasonlít a két szó egymásra. Továbbá a függvénynél meglehet adni argumentumok segítségével, hogy maximum hány elemű listát adjon vissza, vagy mekkora az a minimális hasonlósági arány amely alatt egy szó már nem kerül be a listába. Ezekről a függvény help-jében lehet részletesebben olvasni. Ezek alapján akkor egészítsük ki a translate függvényünket a következőképpen.

def translate(w):
    w = w.lower()
    if w in data:
        return data[w]
    elif w.capitalize() in data: # solution for items such as Delhi
        return data[w.capitalize()]
    elif w.upper() in data: # solution for items such as NATO or USA
        return data[w.upper()]
    elif len(get_close_matches(w, data.keys())) > 0:
        yn = input("Did you mean %s instead? Enter Y if yes, or N if no: " % get_close_matches(w, data.keys())[0]) #string formatting used to put a variable inside a text
        if yn.lower() == "y":
            return data[get_close_matches(w, data.keys())[0]]
        elif yn.lower() == "n":
            return "The word doesn't exist. Please double check it."
        else:
            return "We didn't understand your entry."
    else:
        return "The word doesn't exist. Please double check it."

Amit ez a módosított translate függvény csinál az az, hogy az előbb körülírt get_close_matches függvény használatával egy javaslatot ad a felhasználó számára, amelyet a felhasználó vagy elfogad vagy elvet és ennek megfelelően kap vissza outputokat a programtól. Ha mondjuk a felhasználó elírja és “banana” helyett “bananan”-t ír be, akkor a program egy javaslatot tesz a “banana” definícióinak kiírására, hiszen ez a get_close_matches függvény által generált lista legelső eleme ebben az esetben.

Ezt a felhasználó vagy elfogadja, vagy elutasítja az Y/N billentyűk lenyomásával. Amennyiben pedig annyira ismeretlen szót ír be a felhasználó, hogy a get_close_matches függvény nem képes egyetlen szót sem listába foglalni a fentebb említett kritériumok miatt, akkor a program pedig tájékoztatja erről a felhasználót.

Ami még ebben a módosításban megjelenik az az, hogy a felhasználó által beírt input string-eket a függvény kisbetűssé alakítja. Egyrészt azért szükséges ez, mert a szótárban a legtöbb szó kisbetűvel vannak írva, másrészt pedig, hogy ha a felhasználó a javaslat után “y”-t üt be, akkor az ugyanazt eredményezze, mintha “Y”-t ütött volna be. Azoknál a szavaknál, amelyek a szótárban nagybetűvel szerepelnek (pl.: NATO) vagy csak kezdő betűjük (pl.: Paris) a funkció elején található elif blokkok és methodok jelentenek megoldást. Alapvetően ezekkel a módosításokkal rengeteget javítottunk a programunkon és a célunkat is elértük, azonban úgy gondolom képesek vagyunk még okosabbá tenni ezt az alkalmazást.

TOVÁBBFEJLESZTÉS ÉS ÜZLETI FELHASZNÁLHATÓSÁG

Nézzük is akkor meg, hogy még milyen elemekkel fejleszthetjük tovább a meglévő interaktív szótárunkat. Elsőként jó lenne, ha valahogy meg tudnánk oldani azt, hogy ha a felhasználó elír valamit és a programunk javaslatot ad ki viszont a felhasználónk azt nem fogadja el, akkor a programunk képes legyen tovább operálni és ne lépjen ki egy kedves kis tájékoztatással, hogy “Hát ez nem sikerült”. Ehelyett inkább adjunk még egy lehetőséget a felhasználónak, hogy újra beírhassa a keresett szót.

Egy másik érdekes előrelépés lenne, ha segíteni tudnánk a felhasználót azzal, hogy ha félreírt egy szót viszont azt nem veszi észre és a program például nem azt a szót javasolja, mint amire a felhasználó gondolt, akkor további lehetőségeket ajánlanánk a hasonlósági arányszám felhasználásával. Végül pedig még inkább felhasználóbarátabbá tehetjük a programunkat azzal, ha az egészet egy úgymond menü köré építjük, amellyel biztosítjuk a felhasználónak, hogy a program különböző állapotai közben könnyedén tudja bezárni a programot.

A végső kódnak pedig valahogy így kell kinéznie:

import json
from difflib import get_close_matches

data=json.load(open("data.json"))

def suggestion(w,k=0):
        sug = get_close_matches(w,data.keys())[k]
        yn = input("Did you mean %s instead? If yes press Y, else press N!\nEnter Y/N or X to exit the program: " % sug)
        while yn.lower() not in ("y","n","x"):
            print("We do not understand your entry. Try again!")
            yn = input("Enter Y/N or X to exit the program: ")
        if yn.lower() == "y":
            return data[sug]
        elif yn.lower() == "n":
            re = input("Please reenter the word: ")
            if re == w and k+1<len(get_close_matches(w,data.keys())): k=k+1 return suggestion(re,k) else: k=0 return translate(re) elif yn.lower() == "x": exit() def translate(w): w=w.lower() if w in data: return data[w] elif w.capitalize() in data: # solution for items such as Delhi return data[w.capitalize()] elif w.upper() in data: # solution for items such as NATO or USA return data[w.upper()] elif len(get_close_matches(w,data.keys()))>0: # solution for misstype
        return suggestion(w)
    else:
        re = input("The word doesn't exist. Please double check it and try again!\nEnter a word: ")
        return translate(re)
while True:
    print("Hello! This is an interactive dictionary. To search for a word press F, to close the program enter 'exit!'.")
    menu = input("Enter F/X: ")

    while menu.lower() not in ("f","x"):
        print("We do not understand your entry. Try again!")
        menu = input("Enter F/X: ")

    if menu.lower() == "f":
        word= input("Enter a word: ")

        output = translate(word)
        if type(output) == list: # Understandable ouput
            for i,j in zip(range(1,len(output)+1),output):
                print("%s. def.:" % i, j)
        else:
            print(output)

    elif menu.lower() == "x":
        print("Goodbye!")
        exit()  

Ebből a Python alkalmazásból igazából szinte végtelen lehetséges felhasználás adódik. Ugyanis tulajdonképpen egy nagyon kezdetleges keresőmotort raktunk össze. Ha rendelkezünk egy megfelelő adatbázissal, akkor rengeteg felhasználásra gondolhatunk. Én például egy smarthome automatizációs projekthez szeretném hasznosítani a jövőben, ahol egy GUI-vel kiegészítve egy Dashboard segítségével kérhetünk le információkat a lakásunkkal kapcsolatban. De például egy zenéket vagy könyveket tartalmazó adatbázishoz is hozzárendelhetünk egy hasonló python applikációt.
A részhez tartozó fájlok letölthetők innen.

Köszönöm, hogy végigolvastad a posztomat és ha tetszett, akkor mindenképpen nézz bele a következő részekbe is.

Gulácsy Dominik

About Dominik Gulácsy

Sophomore at Corvinus University of Budapest studying International Business who is motivated to use relevant academic knowledge to solve problems through optimisation. Dedicated to fully support the development of new business solutions in close collaboration with team members by IoT and data science applications. Gained experience in SQL and VBA but looking forward to learning more. A keen supporter of the circular economy.

View all posts by Dominik Gulácsy →

Leave a Reply

Your email address will not be published. Required fields are marked *