python

Modulet

Modulet dhe kuptimi i tyre

Në kapitujt e parë të librit është treguar mënyra e ruajtjes së një kodi në python, që kosistonte në cilën dosje do të ruhej ky kod dhe prapashtesa që duhej të ishte e formës .py. Shpesh na duhet të përdorim pjesë kodi të shkruara më herët, pasi programet e mëdha nuk mund të përfundohen brenda ditës. Për të ripërdorur kodet e ruajtura përdoret sintaksa:

import emri i skedarit

Modulet nuk janë gjë tjetër vecse skedarë të ruajtur me prapashtesën .py. Mund të themi se modulet janë programe. Një ndër modulet e gatshme më të njohura është moduli math, i cili përmban funksione dhe ndryshore matematikore. Për të përdorur funksionet ose ndryshoret e një moduli, fillimisht duhet ta importojmë atë.

>>> import math
>>> math.sqrt(9)
3.0

Për të përdorur funksionin e gatshëm të rrënjës katrore i cili ndodhet brenda modulit math, fillimisht duhet ta importojme këtë modul, ndryshe marrim një gabim sintakse. Në shembullin e mëposhtëm është përdorur një ndryshore ( konstantja pi) nga moduli math.

>>> import math
>>> math.pi
3.141592653589793

Modulet janë një grup funksionesh e ndryshoresh që ndodhen në një skedar.

Nëse gjatë kodit do të na duhet vetëm një funksion ose ndryshore nga një modul i vetëm mund të perdorim këtë sintaksë:

from emri modulit import emri funksionit

Shembull i përdorimit të funksionit të rrënjës katrore nga moduli math:

>>> from math import sqrt
>>> sqrt(9)
3.0

Nëse tentojmë të perdorim një funksion tjetër të modulit math do të hasim një gabim sintakse, pasi nga moduli math është thirrur vetëm funksioni i rrenjes katrore, dmth nuk janë të gatshme të gjitha funksionet apo ndryshoret e këtij moduli.

>>> from math import sqrt
>>> sqrt(9)
3.0
>>> sqrt(4)
2.0
>>> sin(30)

Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    sin(30)
NameError: name 'sin' is not defined

Krijimi i moduleve

Modulet e gatshme të pythonit na lehtësojnë shumë punen, por në raste specifike na lind nevoja të krijojme modulet tona. Për të krijuar një modul mjafton që kodin ta ruajmë me prapashtesen .py. Një ndër gjerat më të rëndësishme në lidhje me këtë pjesë është vendi në të cilin do të ruhet materiali. Për të mos patur probleme gjatë testimit do të ishte mirë të ruhej në vendin ku është regjistruar python (psh. në c:/python27).

Le të krijojmë një modul shembull. Shkruajmë këtë kod në një dritare të re të programit (File > New Window):

>>> print 'Krijimi i moduleve'

E ruajme (Save) direkt në dosjen (folderin) ku është i instaluar programi python. Kujdes të madh duhet treguar me emrin që do të ruhet ky kod, pasi ky është emri i modulit dhe me këtë emër do të importohet. Le ta quajme shembull.py. Tani sapo krijuam një modul me emër shembull.py. Për të importuar modulin perdorim sintaksen import emri modulit duke pasur parasysh të shkruajmë vetëm emrin e modulit pa prapashtesen.

>>> import shembull
Krijimi i moduleve

Nëse provohet sërish të importohet ky modul, nuk ndodh asgjë. Kjo është menduar për të evituar një cikël të pafundëm që mund të ndodhe në rastet kur importojme më shumë se një modul në një moment të caktuar.

Vlera __main__

Nëse gjatë importimit të një moduli do të ekzekutoheshin të gjitha funksionet që mbart ky modul do të ishte shumë e pakëndëshme rrëmuja në kodin tonë. Gjatë programimit shpesh herë na duhet vetëm importimi i modulit dhe jo ekzekutimi i tij. Një mënyrë për të patur kontroll në ekzekutimin direkt të moduleve është përdorimi i ndryshores __name__. Kjo ndryshore merr vlerën __main__ kur moduli ekzekutohet direkt dhe merr si vlerë emrin e vetë modulit kur moduli nuk ekzekutohet direkt por importohet diku tjetër. Sintaksa e plotë është:

if __name__ == "__main__":
bllok kodi

Ky rresht bën të mundur kontrollin mbi ekzekutimin e menjëhershëm të kodit gjatë importimit.

Shembull:

Krijojmë një modul me emrin mdl1.py me këtë rresht kodi:

print 'Pershendetje nga moduli 1!'

Krijojmë dhe një modul tjetër mdl2.py me këto rreshta kodi:

import mdl1
print 'Pershendetje nga moduli 2!'

Le t'i ekzekutojme njeri pas tjetrit modulet. (Run > Run Module, ose nga tastiera shtyp butonin F5). Pas ekzekutimit të modulit të parë marrim këtë pergjigje:

Pershendetje nga moduli 1!

Ndërsa pas ekzekutimit të modulit të dytë:

Pershendetje nga moduli 1!
Pershendetje nga moduli 2!

Siç shohim moduli që importuam ekzekutohet direkt. Për të shmangur këtë gjë do të perdorim vlerën __main__. Në kodin e modulit të parë do të bëjmë ndryshimet e mëposhtme:

if __name__ == "__main__":
    print 'Pershendetje nga moduli 1!'

Nëse ekzekutojmë direkt modulin e parë sërish, do të marrim të njëjtin rezultat si më parë:

Pershendetje nga moduli 1!

Ndërsa kur ekzekutojmë modulin e dytë, në të cilin nuk bëmë asnjë ndryshim, rezultati është vetëm:

Pershendetje nga moduli 2!

Kjo ndodh sepse kur moduli 1 ekzekutohet direkt, python i jep ndryshores __name__ vlerën speciale __main__. Prandaj kushti jonë if është i vërtetë në atë rast dhe fjalia printohet.

Ndërsa kur ekzekutojmë modulin 2, moduli 1 thërritet përmes komandës import. Në këtë rast python i jep si vlerë ndryshores __name__ emrin e vetë modulit ( në këtë rast mdl1). Pra kushti nuk është më i vërtetë dhe fjalia nuk printohet.

Për ta provuar këtë mund të bëjmë këtë ndryshim në modulin 1:

if __name__ == "mdl1":
    print 'Pershendetje nga moduli 1!'

Në këtë rast nëse e ekzekutojmë direkt modulin 1 fjalia nuk do të printohet pasi __name__ ka vlerën speciale __main__, pra kushti if është i rremë:

 

ndërsa nëse ekzekutojmë modulin 2 ku moduli 1 thërritet me import, vlera e __name__ është mdl1 prandaj fjalia do të printohet.

Pershendetje nga moduli 1!
Pershendetje nga moduli 2!

Shembull përmbledhës - Pesha ideale

Në këtë shembull do të permblidhen njohuritë nga kapitujt e mëparshëm duke përfshirë strukturat e kontrollit, ciklet, funksionet, si edhe do të shpjegohen konceptet e reja:

Si shembull do të zgjedhim të krijojmë një program që përcakton peshën ideale të njerëzve të rritur duke u bazuar tek gjinia, gjatësia dhe lloji i kockës. Lloji i kockës ndahet në tri kategori: kockë e ngushtë, mesatare dhe e gjerë. Për të përcaktuar llojin e kockës përdoret metoda e matjes së kyçit të dores me një metër. Tabela e më poshtme përcakton llojin e kockës tek të dyja gjinitë:

Matja e kyçit të dorës tek femrat
Lloji i kockes Më të shkurtra se 155 cm Më gjatësi ndërmjet 155 cm – 163 cm Më të gjata se 163 cm
E ngushtë Më pak se 14 cm Më pak se 15.2 cm Më pak se 15.9 cm
Mesatare Më shumë se 14.6 cm Më shumë se 15.9 cm Më shumë se 16.5 cm
E gjere 14 cm -14.6 cm 14 cm -14.6 cm 14 cm -14.6 cm

 

Matja e kyçit të dorës tek meshkujt
Lloji I kockes Më të gjatë se 163 cm
E ngushtë 14 cm – 16.5 cm
Mesatare 16.5 – 19.1 cm
E gjere Më shumë se 19.1 cm

Për të llogaritur peshën ideale në bazë të llojit të kockës (që normalisht do të përcaktohet nga përdoruesi) do të shtojmë ose do të heqim një 10% perkatësisht për kockë të gjerë dhe për kockë të ngushtë nga rezultati. Formulat që do të perdorim janë të përcaktuara si më poshtë:

Inputi (marrja e informacionit nga përdoruesi)

Thënë thjeshtë programi ynë do të pyesë përdoruesin për gjininë, llojin e kockës, gjatësinë dhe do të japë rezultatin me formulat e sipërpërmendura. Për të marrë input nga përdoruesi në python ka dy funksione: input dhe raw_input.

>>> input('Shkruaj nje nr?: ')
Shkruaj nje nr?: 2
2

Ky funksion merr si input vetëm shprehje të pythonit, pra perfshihen numra, vargje karakteresh etj. Nëse do të duam të marrim një emër nga përdoruesi duhet që ky i fundit ta shkruajë atë si varg, përndryshe ndeshemi me gabim sintakse.

>>> input('Shkruaj nje fjale?: ')
Shkruaj nje fjale?: 'python'
'python'

Kjo është mënyra e duhur për të marrë input nga përdoruesi me anë të këtij funksioni. Siç shihet është pak e komplikuar për përdoruesin, pasi duhet të jetë në dijeni të gjuhës python për të dhënë një input të saktë.

Funksioni tjetër raw_input nuk është kaq stresues për përdoruesin. Ai e kthen vetë inputin në vargje, apo numra. Kështu në rastin e shembullit tonë do të na duhet të perdorim raw_input.

>>> raw_input('Zgjidh gjinine: ')
Zgjidh gjinine: f
'f'

Shohim se ky funksion e perktheu në varg karakteresh gërmën që futem si input.

Struktura try except

Kodit tonë do të duhet t'i bëjmë përmirësime duke shtuar aftesinë për të shmangur gabimet e përdoruesit, si psh. në rastin kur përdoruesi pyetet për gjinine dhe ai gabimisht shkruan gjatësinë. Një nga zgjidhjet në këtë rast është kapja e përjashtimeve, që në python njihet si struktura try except. Rasti tipik i përjashtimeve është pjesëtimi me zero. Në matematikë e dimë se nuk mund të kryejmë një pjesëtim të tillë. Në python marrim një gabim sintakse dhe në këtë mënyrë programi mbyllet prandaj zgjidhja e duhur për këtë rast është që kodi të parashikojë sa të mundet këto inpute që mund të japë perdoruesi.

Sintaksa:

try:
    kod
except emri i llojit të perjashtimit:
    kod që do të kapë gabimet

Në shembullin më poshtë marrim një gabim sintakse që thotë se nuk mund të pjesëtohet me zero.

>>> x = input('Shkruaj nje numer: ')
Shkruaj nje nr: 4
>>> y = input('Shkruaj numrin tjeter: ')
Shkruaj numrin tjeter: 0
>>> print x/y

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    print x/y
ZeroDivisionError: integer division or modulo by zero

Nëse i shtojmë kodit try except do të kishte këtë formë:

>>> try:
        x = input('Shkruaj nje numer: ')
        y = input('Shkruaj numrin tjeter: ')
        print x/y
    except ZeroDivisionError:
        print 'Nuk mund te pjestosh me zero'
Shkruaj nje numer: 1
Shkruaj numrin tjeter: 0
Nuk mund te pjesetosh me zero

Lloji i përjashtimit që kemi zgjedhur është ZeroDivisionError, pasi është pikërisht ky problemi që donim të shmangnim, pjesëtimin e një numri me zero. Përjashtimet janë të llojeve të ndryshme pikërisht për të shmangur gabimet që mund të hasen gjatë programimit. Për të parë llojet e gabimeve që përmban moduli exceptions duhet fillimisht ta importojme atë dhe më pas mund të perdorim funksionin dir.

>>> import exceptions
>>> dir(exceptions)
['ArithmeticError', 'AssertionError', 'AttributeError',
'BaseException', 'BufferError', 'BytesWarning',
'DeprecationWarning','EOFError', 'EnvironmentError',
'Exception', 'FloatingPointError', 'FutureWarning',
'GeneratorExit', 'IOError', 'ImportError',
'ImportWarning', 'IndentationError', 'IndexError',
'KeyError', 'KeyboardInterrupt', 'LookupError',
'MemoryError', 'NameError', 'NotImplementedError',
'OSError', 'OverflowError', 'PendingDeprecationWarning',
'ReferenceError', 'RuntimeError', 'RuntimeWarning',
'StandardError', 'StopIteration', 'SyntaxError',
'SyntaxWarning', 'SystemError', 'SystemExit',
'TabError', 'TypeError', 'UnboundLocalError',
'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError',
'UnicodeTranslateError', 'UnicodeWarning',
'UserWarning', 'ValueError', 'Warning',
'WindowsError', 'ZeroDivisionError', '__doc__',
'__name__', '__package__']

Në fund të librit do të gjeni tabelën e plotë me shpjegimet përkatëse të përjashtimeve. ValueError është një përjashtim që do të na duhet gjatë kodit për shembullin tonë, pasi ky perjashtim përdoret në rastet kur vendoset një input me vlerë të papërshtatshme për rastin. Mund të përdoren më shumë sesa një përjashtim menjëherë, ndërsa nëse nuk vendosim asnjë lloj përjashtimi atëherë i kemi perfshire të gjitha përjashtimet të çfarëdolloj qofshin ato. Ne mund të krijojme edhe përjashtimet tona. Në kapitullin e programimit të orientuar në objekte, në temen e trashëgimisë do të krijojmë një perjashtim për këtë shembull.

Rasti ynë pyet përdoruesin disa herë: për gjininë, gjatësinë dhe llojin e kockës. Nëse gjatë testimit ndodh një gabim në input, ne duam që programi jo vetëm të kapë përjashtimet por edhe të vazhdojë, pra mos të mbyllet programi. Për këtë rast mund të perdorim ciklin while. Sintaksa për këto raste është:

while True:
    try:
        kod
    except lloji i perjashtimit:
        kod që kap perjashtimet
    else:
        break

Për shembullin tonë të peshës ideale do të kishim këtë kod:

while True:
    try:
        gjat = raw_input('Shkruani gjatesine ne cm  ')
        gjat = int(gjat)
    except ValueError:
        print 'Ajo qe shkruat nuk ishte numer'
    else:
        break

Else në fund nënkupton që nëse gjithçka shkon në rregull, pra nuk ekzekutohet perjashtimi ValueError, atëherë ndërprit ciklin me fjalën break, përndryshe, dmth në rastin kur kemi gabime në input nga perdoruesi dhe ekzekutohet perjashtimi, atëherë përsërit ciklin while. int() është një funksion i gatshëm i python që kthen një varg karakteresh në një numër të plotë.

Tani jemi gati të shkruajmë kodin për shembullin e peshës ideale. Fillimisht do të pyesim përdoruesin për gjininë, gjatësinë dhe llojin e kockës.

def pesha():
    while True:
        gjinia = raw_input('Zgjidh gjinine femer(f) ose mashkull(m) ')
        if gjinia == 'f' or gjinia == 'm':
            break
        else:
            print "Inputi nuk ishte i sakte"
    while True:
        try:
            gjat = raw_input('Shkruaj gjatesine tende ne centimetra ')
            gjat = int(gjat)
        except ValueError:
            print 'Inputi nuk ishte numer'
        else:
            break
    while True:
        kocka = raw_input('Zgjidh llojin e kockes: e ngushte(1), mesatare(2), e gjere(3) ')
        if kocka == '1' or kocka == '2' or kocka == '3':
            break
        else:
            print "Inputi nuk ishte i sakte"

Gjithçka është brenda një funksioni që e kemi quajtur pesha(). Tri cikle while përdoren për gjininë, gjatesinë dhe llojin e kockës. Tek përzgjedhja e gjinisë dhe llojit të kockës nuk kemi përdorur strukturen try except. Kjo për faktin se python nuk ka një perjashtim të gatshëm për rastin tonë. Një strukture të tillë do ta krijojme vetë në kapitullin e objekteve dhe klasave.

Tani do të shkruajmë kodin i cili përdor si vlera ndryshoresh inputet që marrim nga perdoruesi. Formulat janë të gatshme siç i thamë në fillim të këtij shembulli.

if gjinia=='f':
    rezultH = 45.5 + 2.2 * (gjat / 2.54 - 60)
    rezultD = 45.5 + 2.3 * (gjat/ 2.54 - 60)
    rezultM = 53.1 + 1.36 * (gjat / 2.54 - 60)
    rezultR = 49 + 1.7 * (gjat / 2.54 - 60)
elif gjinia=='m':
    rezultH = 48 + 2.7 * (gjat / 2.54 - 60)
    rezultD = 50 + 2.3 * (gjat / 2.54 - 60)
    rezultM = 56.2 + 1.41 * (gjat / 2.54 - 60)
    rezultR = 52 + 1.9 * (gjat / 2.54 - 60)

Nga këto rreshta kodi shohim se kemi përdorur inputet për gjinine dhe gjatësinë. Emri i ndryshores që kemi përdorur për gjatësine është gjat. Këto pjesë kodi kontrollojnë nëse inputi është 'f' ose 'm', dhe sipas rastit vazhdohet me formulat e llogaritjes së rezultatit duke përdorur edhe inputin tjetër gjatësinë.

Inputi i tretë që kërkohet është lloji i kockës i cili ka tre zgjedhje: e ngushtë, mesatare, e gjerë. Në fillim të shembullit përmendëm se për të krijuar lidhjen midis rezultatit dhe llojit të kockës duhet të shtojmë ose të heqim 10% në varësi të llojit të kockes: të gjere ose të ngushtë. Nëse kemi një kockë mesatare atëherë mbajmë rezultatin që na japin formulat.

if kocka == '1':
       rezultH = 0.9 * rezultH
       rezultD = 0.9 * rezultD
       rezultM = 0.9 * rezultM
       rezultR = 0.9 * rezultR
elif kocka == '3':
       rezultH = 1.1 * rezultH
       rezultD = 1.1 * rezultD
       rezultM = 1.1 * rezultM
       rezultR = 1.1 * rezultR

Nëse inputi është 1 sipas asaj që ne kemi përcaktuar kemi të bëjmë me një kockë të ngushtë, atëherë rezultatit përfundimar rezult duhet t'i zbresim 10%. Pas një faktorizimi të thjeshtë arrijmë në formulën rezult = 0.9 * rezult siç shpjegohet më poshtë:

rezult = 1 * rezult - 0.1 * rezult
ose
rezult = (1 - 0.1) * rezult
ose
rezult = 0.9 * rezult

Nëse inputi është 3 kemi të bëjmë me rastin e kockës së gjerë dhe duhet t'i shtojmë 10% rezultatit përfundimtar ku pas faktorizimit marrim formulën rezult = 1.1 * rezult. Deri tani kemi shkruar gjithçka përveç shfaqjes në ekran të rezultateve. Kjo bëhet thjesht:

print 'Sipas Hamwi pesha ideale është', rezultH,'kg'
print 'Sipas Devine pesha ideale është', rezultD,'kg'
print 'Sipas Miller pesha ideale është', rezultM,'kg'
print 'Sipas Robinson pesha ideale është', rezultR, 'kg'

Siç shpjeguam më lart tek modulet, nëse duam që programi jonë të mos ekzekutohet direkt kur thirret në një modul tjetër përmes import, nuk mund ta thërrasim direkt funksionin pesha por duhet të shtojmë:

if __name__ == "__main__":
    pesha()

Formulat që llogarisin rezultatin janë numra dhjetorë kështu do të kemi një rezultat me shumë shifra pas presjes. Për të rrumbullakosur numrat dhjetor, python ka një funksion round(x,[n]) ku x është vlera e numrit dhjetor që do të rrumbullakoset, ndërsa n numri i shifrave pas presjes. Kodi me këtë funksion do të ishte:

print 'Sipas Hamwi pesha ideale është', round(rezultH, 1), 'kg'
print 'Sipas Devine pesha ideale është', round(rezultD, 1), 'kg'
print 'Sipas Miller pesha ideale është', round(rezultM, 1), 'kg'
print 'Sipas Robinson pesha ideale është', round(rezultR, 1), 'kg'

Një tjetër gjë që mund të përmirësojmë tek programi është kufiri minimal që duhet të këtë gjatësia. Formulat që janë përzgjedhur nuk janë për fëmijët dhe adoleshentet por vetëm për të rriturit. Për këtë arsye gjatësia nuk mund të jetë më e vogël se 140 cm. Një gjë e tillë mund të arrihet me një përjashtim të shkruar nga ne, por në këtë rast do të perdorim strukturën if else. Ndryshimet në kod do të ishin:

    while True:
        try:
            while True:
                gjat = raw_input('Shkruaj gjatesine tende ne centimetra ')
                gjat = int(gjat)
                if gjat <= 140:
                    print 'Gjatesia duhet me e madhe se 140'
                else:
                    break
        except ValueError:
            print 'Inputi nuk ishte numer'
        else:
            break

Mënyrë tjetër zgjidhjeje është të shkruajmë një përjashtim tonin, por meqë nuk kemi mësuar ende klasat, struktura e shkruar për këtë rast do të jetë tek kapitulli i programimit të orientuar në objekte.

Kodi i plotë:

def pesha():
    # Marrim te dhenat nga perdoruesi me ane te tre cikleve while
    while True:
        gjinia = raw_input('Zgjidh gjinine femer(f) ose mashkull(m) ')
        if gjinia == 'f' or gjinia == 'm':
            break
        else:
            print "Inputi nuk ishte i sakte"
    while True:
        try:
            while True:
                gjat=raw_input('Shkruaj gjatesine tende ne centimetra ')
                gjat = int(gjat)
                if gjat <= 140:
                    print 'Gjatesia duhet me e madhe se 140'
                else:
                    break
        except ValueError:
            print 'Inputi nuk ishte numer'
        else:
            break
    while True:
        kocka = raw_input('Zgjidh llojin e kockes: e ngushte(1), mesatare(2), e gjere(3) ')
        if kocka == '1' or kocka == '2' or kocka == '3':
            break
        else:
            print "Inputi nuk ishte i sakte"

    # Llogarisim rezultatin sipas formulave per meshkujt dhe femrat
    if gjinia=='f':
        rezultH = 45.5+2.2*(gjat/2.54-60)
        rezultD = 45.5+2.3*(gjat/2.54-60)
        rezultM = 53.1+1.36*(gjat/2.54-60)
        rezultR = 49+1.7*(gjat/2.54-60)
    elif gjinia=='m':
        rezultH = 48+2.7*(gjat/2.54-60)
        rezultD = 50+2.3*(gjat/2.54-60)
        rezultM = 56.2+1.41*(gjat/2.54-60)
        rezultR = 52+1.9*(gjat/2.54-60)

    # Bejme ndryshimet e nevojshme sipas llojit te kockes
    if kocka =='1':
        rezultH = 0.9 * rezultH
        rezultD = 0.9 * rezultD
        rezultM = 0.9 * rezultM
        rezultR = 0.9 * rezultR
    elif kocka=='3':
        rezultH = 1.1 * rezultH
        rezultD = 1.1 * rezultD
        rezultM = 1.1 * rezultM
        rezultR = 1.1 * rezultR

    # E mbyllim funksionin duke shfaqur rezultatet
    print 'Sipas Hamwi pesha ideale eshte',round(rezultH,1),'kg'
    print 'Sipas Devine pesha ideale eshte',round(rezultD,1),'kg'
    print 'Sipas Miller pesha ideale eshte',round(rezultM,1),'kg'
    print 'Sipas Robinson pesha ideale eshte',round(rezultR,1),'kg'

# Therrasim funksionin vetem kur moduli ekzekutohet direkt
if __name__ == "__main__":
    pesha()