Uvod u Python
Uvod
Python je interpretirani programski jezik visokog nivoa čiji je razvoj započeo krajem 80-ih godina 20. veka, kada je holandski programer Gvido Van Rosum odlučio da sprovede u delo zanimljivu ideju o jednostavnom programskom jeziku znatnih mogućnosti, u kome će (za razliku od tadašnjih popularnih jezika), akcenat biti na čitljivom i preglednom programskom kodu koji će programeri lako razumeti i rado međusobno razmenjivati (a usput se 'provukla' i ideja da bi Python vremenom mogao da postane dopuna ili 'zamena' za shell skripte u operativnim sistemima).
Jezik se zvanično pojavio početkom 1991, i može se reći da je u prvim godinama brzina izvršavanja skripti bila 'ponešto' problematična, ali, početne ideje su postepeno urodile plodom i Python je tokom vremena postao prihvaćen u industriji i stekao je veliku popularnost (pogotovo od cca. sredine 2000-ih, kada su računari postali dovoljno snažni da 'legitimno' pokreću kompleksnije Python skripte).
U današnje vreme, Python nalazi primenu u razvoju web aplikacija kao i u naučnim istraživanjima, a poslednjih godina veoma je popularan u oblasti mašinskog učenja.
Kada je u pitanju početak bavljenja Python-om, najlepše od svega je to što kreiranje i pokretanje skripti ne zahteva ništa drugo osim editora teksta i male instalacije koja se lako može preuzeti sa interneta.
Instalacija okruženja
Kao što smo već spomenuli, Python je interpretirani jezik, što znači da se programi napisani u Python-u ne kompajliraju i ne pokreću direktno iz operativnog sistema, već, preko interpretatora - konzolne aplikacije koja učitava, tumači i (u slučaju da u kodu nema grešaka), pokreće skripte, a takođe je u stanju da prima i izvršava pojedinačne naredbe (slično tome kako shell programi interpretiraju naredbe). *
Sa adrese python.org/downloads možete preuzeti instalacionu verziju Python-a (uz napomenu da treba da preuzmete verziju koju vaš operativni sistem podržava).
Program koji preuzmete (i pokrenete :)), instaliraće interpretator sa svim neophodnim bibliotekama, i takođe će dodati putanju do interpretatora (to jest, putanju do datoteke python.exe u direktorijumu koji ste izabrali za instalaciju) - među putanje koje sistem pretražuje pri pozivanju programa iz konzole.
(U suprotnom, uvek biste morali da pozivate Python preko pune putanje, nalik na C:\Program Files\Python\python.exe i sl.)
Skripte koje ćete pisati treba smeštati u direktorijum koji je specifično namenjen 'Python skriptama', i u tom smislu predlažemo da kreirate folder sa putanjom koja nije na C: particiji, već, na nekoj drugoj putanji (npr. d:\python_skripte ili e:\python_skripte i sl (praktičan primer putanje za druge operativne sisteme, naveden je u gornjoj napomeni)).
Bitno je (za početak) da manje programe čuvate u zasebnim datotekama sa prepoznatljivim imenima, dok će kasnije (kada budete kreirali projekte koji koriste više datoteka), biti potrebno da za svaki veći projekat kreirate i zaseban direktorijum (tj. 'folder').
Pokrenite konzolu (otvorite startni meni, ukucajte "cmd"), i unesite sledeće dve komande:
c:\ d:
d:\ cd python_skripte
Pokrenite editor i sačuvajte skriptu sa nazivom 01_prvenac.py u folder koji ste izabrali za čuvanje skripti.
Sada smo spremni da napišemo prvu skriptu, ali, pre toga, nekoliko reči o formatiranju programskog koda .....
Pravila za formatiranje koda (indentacija)
U programskom jeziku C (i ostalim jezicima koji koriste C-oliku sintaksu), razdvajanje pojedinačnih naredbi obavlja se preko separatora naredbi ; (tačka-zarez), za uokviravanje blokova koda koriste se vitičaste zagrade, a pojava (dodatnih) whitespace znakova ispred naredbi (i inače, oko promenljivih, naredbi dodele i poziva funkcija) - jednostavno se zanemaruje.
U Python-u, pojava whitespace znakova na početku naredbi, ne samo da se ne zanemaruje, već se upravo preko pravilne indentacije (to jest, "uvlačenjem" delova koda), definiše hijerarhija pripadnosti naredbi određenim blokovima programskog koda.
U tehničkom smislu, indentacija označava "broj tabova" - na početku svakog reda (pri čemu se doslovno može koristiti znak "TAB", a mogu se koristiti i uzastopni razmaci).
Recimo, sledeća while petlja u Python-u, koja ispisuje brojeve od 1 do 5 ....
i = 0 # nema uvlačenja (na početku reda)
while i < 5: # nema uvlačenja
i += 1 # 1 x TAB
print(i) # 1 x TAB
.... praktično je ekvivalent sledeće petlje u C-u ....
i = 0;
while (i < 5) {
i += 1;
printf("%d\n", i);
}
.... dok je naizgled vrlo slična petlja u Python-u ....
i = 0 # nema uvlačenja
while i < 5: # nema uvlačenja
i += 1 # 1 x TAB
print(i) # nema uvlačenja (?!)
# U poslednjem redu nema uvlačenja.
# Međutim, red je trebalo da bude
# uvučen (i upravo zato i nastaje
# problem pri tumačenju koda)!
.... ekvivalent "nešto drugačije" petlje iz programskog jezika C ....
i = 0;
while (i < 5) {
i += 1;
}
printf("%d\n", i);
.... koja svakako "liči" na petlju sa slike #3, ali, zapravo je sasvim drugačija po smislu!
Poslednje dve petlje ispisuju samo vrednost 5, pri čemu je u C-u očigledno "zašto je tako" dok u Python-u nije - i upravo zato je potrebno voditi računa o indentaciji u Python-u.
Pravilno uvlačenje postiže se tako što se u svakom bloku koriste isti (početni) razmaci za sve naredbe na istom "nivou uvlačenja" (to jest, na istom nivou hijerarhije):
i = 0; # nema uvlačenja
while i < 5: # nema uvlačenja
i += 1 # 1 x TAB (ili 4 razmaka)
if i % 2 == 0:
print(f"Broj {i} je paran broj") # 2 x TAB (ili 8 razmaka)
else:
print(f"Broj {i} je neparan broj")
Uvlačenje koda, u okviru jednog bloka, moguće je obaviti:
- upotrebom znakova "TAB"
- uzastopnim razmacima, tako da se u svakoj situaciji - umesto jednog znaka TAB - koristi isti broj razmaka
.... i svejedno je koji će pristup biti korišćen (tabovi ili razmaci) - pod uslovom da se znakovi ne kombinuju!
Ako se odlučite za razmake umesto tabova, broj razmaka koji se koristi umesto jednog znaka "TAB" može biti proizvoljan, ali, preporučujemo 4 razmaka (ili 2) - onako kako verovatno već koristite tabulaciju i u drugim programskim jezicima (na gornjoj slici, 1 TAB ima širinu 4 razmaka).
Sada se (konačno 🙂) vraćamo na datoteku 01_prvenac.py i prelazimo na kodiranje ....
Osnovne komande
Nagovestili smo već da su preglednost i jednostavnost programskog koda glavne osobina Pythona, u šta ćemo se uveriti, kako kroz prvih nekoliko primera, tako i kroz kasnije primere ....
print - naredba izlaza
Za sam početak, kao i u ostalim situacijama kada započinjemo upoznavanje sa novim programskim jezikom, prvi program biće skripta koja pozdravlja korisnika:
# datoteka 01_prvenac.py:
print("Dobar dan!")
Nema 'uvoza' biblioteka, nema vitičastih zagrada koje ograničavaju blokove koda i nema operatora ; koji u većini drugih programskih jezika terminiše pojedinačne naredbe.
Za pokretanje skripte koju smo napisali, možemo uneti u konzolu sledeću komandu ....
d:\python_skripte\ python 01_prvenac.py
.... i "to je to" - program ispisuje pozdravnu poruku:
Dobar dan!
Inicijalizacija promenljivih i osnovni operatori
Za razliku od mnogih programskih jezika u kojima je deklaracija promenljivih obavezna (ili makar "postoji", kao na primer u JavaScript-u), Python ne raspolaže naredbom za eksplicitnu deklaraciju promenljivih.
Promenljive praktično nastaju preko naredbi dodele, pri čemu se tipovi podataka ne navode (što smo na neki način implicirali kada smo naveli da ne postoji naredba za deklaraciju), i stoga je jasno je da se radi o tzv. dinamičkoj tipizaciji podataka (sa kojom smo se sretali i u JavaScript-u i PHP-u).
Shodno navedenom, prost program koji sabira dva broja i ispisuje rezultat, vrlo lako se može zapisati na sledeći način:
# 02_promenljive_sabiranje_ispis.py:
a = 10
b = 15
c = a + b
print(c)
U prvom programu videli smo da naredba print može ispisivati niske (koje su uokvirene navodnicima), u prethodnom primeru smo videli da naredba print može ispisivati i vrednosti promenljivih, međutim, ako je potrebno da se običan tekst spoji sa vrednostima promenljivih, prvo se vrednosti promenljivih moraju pretvoriti u niske tj. "običan tekst" (recimo, preko funkcije str, koja za uneti brojčani podatak vraća odgovarajuću nisku), posle čega se niske mogu spojiti preko operatora + i (na kraju) ispisati.
a = 10
b = 15
c = a + b
print("Zbir brojeva " + str(a) + " i " + str(b) + " je " + str(c))
Da pojasnimo zašto je potrebno postupati tako kako smo naveli ....
Kada se naredbi print preda jedan argument (kao što smo ranije videli), interpretator će obaviti ispis u skladu sa tipom podatka * (tj. obaviće sve što treba da se vrednost prikaže na odgovarajući način).
Kada se string konstante (tj. niske uokvirene navodnicima, koje se zadaju u toku pisanja programa), kombinuju sa niskama koje su zapisane preko promenljivih - i dalje nema potrebe za preduzimanjem dodatnih koraka, jer se i taj proces obavlja automatski ....
ime = "Milan"
skola = "Sveti Sava"
print(ime + " ide u školu " + skola + ".")
.... ali, ako bismo pokušali (u primeru sa slike #11 (i inače)), da neposredno predamo vrednost promenljive koja nije niska, došlo bi do greške.
Kada operator +, koji se koristi unutar naredbe print, naiđe na dva argumenta različitog tipa - nije u stanju da se "opredeli" za jedan od dva moguća načina funkcionisanja (a isto je i kada se operator + koristi van naredbe print).
Komanda print(5 + 5) ispisuje "10", * dok komanda print("5" + "5") ispisuje "55", ** međutim, kada se argumenti različitog tipa kombinuju, interpretator ne zna kako treba da postupi (krajnje opravdano), i upravo je upotreba funkcije str (preko koje se broj pretvara u nisku) - jedan od načina da se problem reši.
Problem se (inače) može rešiti i preko tzv. formatiranih niski:
a = 10
b = 15
c = a + b
print(f"Zbir brojeva {a} i {b} je {c}.")
Slovo f, kao prefiks niske, navodi interpretator na postupak u kome se pojava promenljivih (i izraza) unutar vitičastih zagrada, tretira kao poziv za konvertovanje brojčanih vrednosti u niske (uz prethodno računanje vrednosti izraza).
Naredba ulaza - input
Učitavanje podataka u Python-u, tipično se obavlja preko funkcije input:
a = input()
b = input()
c = a + b
print(c)
Prikazana skripta je vrlo jednostavna, ali, može se desiti da vas rezultat izvršavanja iznenadi.
Ako pri pokretanju programa unesemo sledeće 'podatke': 12 i 15, program će ispisati 1215 (to jest, neće ispisati 27)!
Naravno, radi se o tome da naredba input vraća niske (a interpretator neće "nagađati" tip podatka koji je programer zamislio (pri čemu je vrlo moguće da je očekivani tip ulaznog podatka, upravo - niska)), pa, ako uneti podaci treba da budu formatirani kao brojčane vrednosti - to se mora i 'naglasiti':
a = int(input())
b = int(input())
c = a + b
print(c)
U drugom slučaju, konzolni ulaz je pretvoren u celobrojne vrednosti, i sada je rezultat (praktično) - sabiranje brojeva.
Kontrola toka - grananja i petlje
Osnovno if grananje i while petlja u Python-u, funkcionišu na 'očekivani način' (pretpostavićemo da očekujete da bi petlje i grananja u Python-u trebalo da funkcionišu slično kao petlje i grananja u C-u), ali, zato su druge konstrukcije: ili implementirane na (ponešto) drugačiji način (for), ili uopšte ne postoje (switch i do-while).
Međutim, bez brige: for petlje u Python-u su jednostavne za razumevanje (i prilično zanimljive same po sebi), a switch i do-while se mogu simulirati prilično lako ....
Grananja u programu - if - else
Za upoznavanje sa naredbama grananja, napisaćemo dobro poznati program koji proverava da li je broj veći, manji, ili jednak nuli (a obratićemo pažnju i na to kako je programski kod formatiran).
U idejnom smislu, grananja u Python-u su istovetna kao grananja u C-u, ali, budući da se vitičaste zagrade ne koriste za izdvajanje blokova, potrebno je voditi računa o formatiranju koda još pedantnije i doslednije u odnosu na kodove u C-olikim jezicima:
a = int(input())
if a > 0:
print("Broj je pozitivan")
else:
if a < 0:
print("Broj je negativan")
else:
print("Broj je nula")
# 0 x TAB - osnovni nivo
# 1 x TAB - True ili False grana prvog if-a
# 2 x TAB - True ili False grana if-a koji
# se nalazi u Else grani prvog
# if-a
Posle uslova (i posle rezervisane reči else), pišu se dve tačke, a složeno grananje (kao u gornjem primeru), svakako je situacija u kojoj se posebno mora voditi računa o indentaciji.
U prethodnom primeru smo mogli videti i to da se za jednostavne uslove ne moraju koristiti zagrade, međutim, ukoliko je uslov složen (i/ili dvosmislen) ....
if a >= 12 and (b >= 12 or b <= 3):
# Gornji uslov, bez zagrada ....
# if a >= 12 and b >= 12 or b <= 3:
# .... praktično bi postao:
# if (a >= 12 and b >= 12) or b <= 3:
.... zagrade se moraju koristiti.
Simulirani switch
Budući da u Python-u ne postoji regularna razgranata struktura switch, "simulacija" se tipično svodi na if-else grananje i ("obilno") korišćenje rezervisane reči elif (koja, kao što možete pretpostaviti, praktično predstavlja uzastopnu pojavu rezervisanih reči else i if, čime se uvodi "novi nivo grananja", ali - bez toga da programski kod počne "da beži u desnu stranu").
Da pojasnimo (preko primera): ako program treba da ispiše dan u nedelji koji odgovara unetom rednom broju, a pri tom se koristi uobičajena if-else konstrukcija koja ispituje prvih sedam brojeva (tj. ne koristi se elif) ....
if d == 1:
print("ponedeljak")
else:
if d == 2:
print("utorak")
else:
if d == 3:
print("sreda")
else:
if d == 4:
print("četvrtak")
else:
if d == 5:
print("petak")
else:
if d == 6:
print("subota")
else:
if d == 7:
print("nedelja")
else:
print("Broj ne predstavlja dan u nedelji")
.... programski kod nije ni izdaleka elegantan.
"Simulirani switch", implementiran preko rezervisane reči elif, koja praktično označava "sledeći nivo grananja" (a u još praktičnijem smislu, nešto nalik na case iz programskog jezika C) ....
if d == 1: # case 1:
print("ponedeljak")
elif d == 2: # case 2:
print("utorak")
elif d == 3: # case 3:
print("sreda")
elif d == 4: # case 4:
print("četvrtak")
elif d == 5: # case 5:
print("petak")
elif d == 6: # case 6:
print("subota")
elif d == 7: # case 7:
print("nedelja")
else: # default:
print("Broj ne predstavlja dan u nedelji")
.... predstavlja znatno elegantniju jezičku konstrukciju.
Petlja while
Pošto smo se u uvodnim odeljcima detaljno upoznali sa indentacijom (i maločas se podsetili na važnost pravilnog uvlačenja koda), kao primer funkcionisanja while petlje poslužiće dobro poznati kod za generisanje Fibonačijevih brojeva (niz u kome se prva dva elementa zadaju, a svaki sledeći element, od trećeg nadalje, dobija se sabiranjem prethodna dva):
a = 1 # prvi element niza
b = 1 # drugi element niza
n = 10 # ukupan broj elemenata
i = 3 # pomoćni iterator
print(a)
print(b)
while i <= n:
b = a + b
a = b - a
print(b)
i += 1
Simulacija petlje do-while
U većem broju drugih programskih jezika (pogotovo onih koji su zasnovani na C-u), postoji i do-while petlja:
int i = 1; // korak
int g = 3; // granica
int u = 10; // uvećanje
int s = 0; // suma
do {
s += u;
++i;
}
while (i <= g);
// Praktično: kolika god da je vrednost
// promenljive g, posle izvršavanja petlje,
// promenljiva s (suma), ne može imati
// vrednost manju od u (10).
U pitanju je specifičan oblik programske petlje, koja se od osnovne while petlje razlikuje po tome što se u ciklus petlje (obavezno) ulazi bar jednom.
U Python-u je situacija ponešto drugačija: * za razliku od 'obične' while petlje, konstrukcija do-while ne postoji, već se samo može simulirati, a simulacija najčešće podrazumeva beskonačnu petlju - sa uslovom za prekid (koristićemo primer iz prethodnog bloka).
i = 1 # korak
g = 3 # granica
u = 10 # uvećanje
s = 0 # suma
while True:
s += u
i += 1
if i <= g: break # ** videti napomenu
Petlja for
Kada su u pitanju for petlje u Python-u, postoje dva naizgled različita formata zapisa, ali, u oba slučaja - radi se o istom principu izvršavanja.
Petlja može 'prolaziti' kroz iterabilne strukture (tj. može pristupati redom svim elementima) ....
for element in lista:
naredbe ....
.... a moguće je takođe organizovati for petlju na "naizgled uobičajen" način, uz korišćenje brojača:
for i in range(1, 10):
naredbe ....
Obe (naizgled različite) metode, omogućavaju da se izvede sve ono što se može izvesti preko for petlje u C-u, ali (najjednostavnije rečeno), pošto nijedan od dva načina zapisivanja nije 'previše sličan' C-olikoj sintaksi za for petlje, za početak se nećemo detaljnije osvrnuti na for petlju #2, koja donekle podseća na for petlje u C-u (i srodnim jezicima), već, upravo na varijantu #1, koja "baš ne liči" na petlje u C-u (a uskoro će postati jasno i zašto smo izabrali takav redosled).
Prolazak kroz sve elemente iterabilnih struktura
Pošto smo već naveli opšti obrazac za for petlju koja "prolazi kroz sve elemente iterabilne strukture", za primer ćemo kreirati (upravo) jednu takvu strukturu, na sledeći način:
dani_u_nedelji = [
"ponedeljak",
"utorak",
"sreda",
"četvrtak",
"petak",
"subota",
"nedelja"
]
For petlja koja prolazi kroz sve elemente gornjeg "niza" (tj. liste), ima sledeći oblik ....
for dan in dani_u_nedelji:
print(dan)
.... pri čemu se kao rezultat pokretanja prikazane petlje dobija sledeći ispis: "ponedeljak", "utorak", "sreda", "četvrtak", "petak", "subota", "nedelja" (kada se program pokrene, niske se zapravo ispisuju u zasebnim redovima, 'jedne ispod drugih', ali, nećemo bez potrebe zauzimati dodatni prostor).
Drugi zapis for petlje podrazumeva (kao što smo već videli), navođenje raspona vrednosti, ali, za tako nešto je potrebno koristiti funkciju koja generiše - raspon vrednosti. :)
range() - raspon vrednosti
Funkcija range vraća listu celobrojnih vrednosti * koje se generišu shodno unetim argumentima, koji predstavljaju:
- početnu vrednost
- granicu **
- korekciju (tj. uvećanje ili umanjenje, u svakom koraku)
Neki od argumenata se mogu izostaviti (u situacijama kada se odgovarajući rezultat može dobiti preko podrazumevanih vrednosti), ali, naravno, mora se predati bar jedan argument.
Pogledajmo nekoliko primera.
Primer #1: Ukoliko se preda (samo) jedan argument ....
range(g) # [ 0, 1, 2 .... g-1 ]
range(5) # [ 0, 1, 2, 3, 4 ]
.... predati argument predstavlja graničnu vrednost; početna vrednost je 0, poslednji element liste ima vrednost prvi_argument - 1, a korekcija je + 1 (svaki sledeći element je za 1 veći od prethodnog).
Primer #2: - Ukoliko se predaju dva argumenta ....
range(2, 7) # [ 2, 3, 4, 5, 6 ]
.... prvi argument označava početnu vrednost, drugi argument predstavlja granicu, a poslednji element liste ima vrednost drugi_argument - 1 (korekcija je i dalje + 1).
Primer #3: Ako se predaju (sva) tri argumenta ....
range(2, 17, 3) # [ 2, 5, 8, 11, 14 ]
.... prvi argument predstavlja početnu vrednost, drugi argument predstavlja granicu, i praktično definiše poslednju (manju ili veću) * vrednost koja se može dobiti shodno vrednosti trećeg argumenta - koji predstavlja korekciju (u gornjem primeru, korekcija je + 3)).
Da pojasnimo dodatno (preko gornjeg primera): budući da je treći argument pozitivan broj, * poslednja celobrojna vrednost koja se može dobiti s obzirom na početnu vrednost 2 i korekciju 3, nije 17, nije ni 16 - već 14:
- vrednost 17 ne može biti poslednja vrednost u listi, budući da je poslednja vrednost (po pravilu) manja * od zadate granice
- vrednost 16 se praktično "preskače", budući da korekcija nije 1 (već 3)
for x in range()
Pošto funkcija range vraća listu celobrojnih vrednosti, sada je potpuno jasno da obe for petlje (koje smo prikazali na početku), koriste isti princip prolaska kroz iterabilne strukture (i upravo je to razlog zašto nismo prvo prikazali primer for petlje 'koja donekle podseća na for petlje iz C-a').
Dakle, ako je u određenom zadatku potrebno proći kroz raspon brojeva: za kreiranje liste koja (u praktičnom smislu) predstavlja traženi raspon, može se koristiti funkcija range.
Ako se preda samo jedan argument (vraćamo se na listu u kojoj su zapisani dani u nedelji) ....
for i in range(3):
print(dani_u_nedelji[i])
# range(3) = [ 0 , 1 , 2 ]
.... program će ispisati prva tri dana "ponedeljak", "utorak", "sreda" (jedan ispod drugog).
Ako se predaju dva argumenta, za desnu granicu važe ista pravila kao malopre, a prvi argument predstavlja početnu vrednost pri indeksiranju:
for i in range(2, 5):
print(dani_u_nedelji[i])
# range(2, 5) = [ 2 , 3 , 4 ]
Shodno ranije navedenim pravilima, program sada ispisuje: "sreda", "četvrtak", "petak".
Liste (nizovi)
Liste u Python-u (koje se često kolokvijalno nazivaju i nizovima, iako nisu implementirane kao statički nizovi), predstavljaju iterabilne kolekcije podataka preko kojih je moguće skladištiti više uzastopno zapisanih podataka, unutar jedne promenljive.
Liste (tj. 'nizovi'), mogu se inicijalizovati neposredno, preko naredbe dodele ....
niz = [ "januar" , "februar" , "mart" , "april" , "maj" ]
.... pri čemu se pojedinačnim elementima može pristupati isto onako kako se (npr. u C-u) pristupa elementima statičkih nizova - preko indeksa u velikim zagradama:
print(niz[1])
# februar
Prolazak kroz sve elemente liste (tj. 'niza'), već smo videli:
for element in niz:
print(element)
Dodavanje elemenata (na kraj liste), obavlja se preko komande append:
niz.append(novi_element)
niz.append(12)
niz.append("arhitektura")
Uklanjanje elemenata (sa kraja liste), može se obaviti preko komande pop:
# [ 1 , 2 , 3 , 4 , 5 ]
niz.pop()
# [ 1 , 2 , 3 , 4 ]
U Python-u postoji i jednostavan način za sortiranje nizova:
# [ 2 , 1 , 4 , 5 , 3 ]
niz.sort()
# [ 1 , 2 , 3 , 4 , 5 ]
Funkcije u Python-u
Python dolazi sa standardnom bibliotekom koja sadrži brojne funkcije za obavljanje svakodnevnih zadataka, a pored toga, jezik (očekivano) takođe omogućava programerima da sami definišu sopstvene funkcije (što nas za početak zanima više od ugrađenih funkcija).
Definisanje korisničkih funkcija
Kao i u drugim jezicima, preporučljivo je da se određeni delovi koda - koji se često ponavljaju - smeste u funkcije (praktično, zasebne potprograme).
Definisanje korisničkih funkcija obavlja se preko rezervisane reči def (slično kao što u JavaScript-u definiciji funkcije prethodi rezervisana reč function), nakon čega sledi naziv funkcije i parametri u zagradi.
Dobar početni primer funkcije koju ćemo 'definisati sami', može biti jednostavna funkcija koja ispisuje veći od dva uneta broja:
def maks(a, b):
if a >= b:
return a
else:
return b
Definisana funkcija može se koristiti na već poznate načine:
m = maks(12, 15)
print(m)
# Ili, još jednostavnije:
print(maks(12, 15))
Najčešće korišćene ugrađene funkcije
Kao što smo već nagovestili, uz instalaciju Python-a dolazi i veći broj 'ugrađenih' funkcija (koje su sadržane u osnovnoj biblioteci i mogu se neposredno koristiti, bez uvoženja različitih programskih modula i sl).
Sa nekim ugrađenim funkcijama susretaćete se samo po potrebi, ali, ima i onih koje ćete koristiti gotovo svakodnevno, i stoga smo izdvojili neke od najbitnijih.
len - broj elemenata niza ili dužina niske
Za proveru dužine niske koristi se funkcija len:
d = len("Preraspodela")
print(d)
(Program sa gornje slike ispisuje vrednost 12.)
Ista funkcija može se koristiti i za očitavanje broja elemenata niza:
d = len([ 1, 2, 8, 12, 21, 22 ])
print(d)
(Program sa gornje slike ispisuje vrednost 6.)
replace - zamena delova niske
Funkcija replace koristi se za zamenu delova niski - drugim niskama.
Kao prvi argument navodi se podniska koju je potrebno pronaći (u niski s), a drugi argument je niska kojom treba zameniti pojavu (ili pojave) prve podniske.
Sledeća skripta:
s = "Monti Kengur"
s = s.replace("Kengur", "Pajton")
print(s)
.... ispisaće nisku "Monti Pajton" (pošto je prethodno podniska "Kengur" zamenjena niskom "Pajton").
matematičke funkcije - abs, round, floor, ceil
Za korišćenje matematičkih funkcija u Python-u potrebno je prvo uključiti u program (tj. "importovati"), modul math, posle čega se mogu koristiti funkcije iz modula:
import math
a = abs(-17) # apsolutna vrednost
print(a)
# 17
a = math.floor(1.54) # prva celobrojna vrednost,
print(a) # manja od unetog broja
# 1
a = math.ceil(1.54) # prva celobrojna vrednost,
print(a) # veća od unetog broja
# 2
rand - generisanje nasumične vrednosti
Za generisanje nasumične celobrojne vrednosti, koristi se ugrađena funkcija randint:
a = randint(1, 6)
print(a)
Parametri (tj. argumenti), predstavljaju granične vrednosti.
type - ispis tipa podatka
Za kraj pregleda često korišćenih ugrađenih funkcija, ostavili smo funkciju type, koja vraća tip podatka unetog argumenta:
print(type(12))
print(type(1.54))
print(type(True))
print(type("Proba"))
Pokretanje programskog koda sa prethodne slike proizvodi sledeći ispis:
<class 'int'>
<class 'float'>
<class 'bool'>
<class 'str'>
U praktičnom smislu, informacije dobijene korišćenjem funkcije type mogu se koristiti u svrhu provere (na primer, može se proveriti da li je određena funkcija vratila listu (u određenom primeru u kome je lista bila očekivani rezultat), ili je funkcija vratila sistemsku vrednost None (što je praktično "signal" da nismo dobili željeni rezultat, zbog čega je potrebno preduzeti mere predostrožnosti u daljem toku izvršavanja programa)).
Klase i objekti u Python-u
Pre nego što privedemo kraju uvodni članak, upoznaćemo se i sa osnovnim mehanizmima za kreiranje klasa i objekata (nakon čega ćemo ukratko prodiskutovati o 'filozofskim' aspektima upotrebe 'donekle pojednostavljenih' skriptnih jezika kao što je Python).
Po pitanju klasa i objekata, Python je ponešto "relaksiran" u odnosu na Javu, C++ ili C# (ali i ponešto striktniji od JavaScript-a), i može se reći da stvari uglavnom funkcionišu na dobro poznat način - s tim da ima i pojedinosti koje zavređuju dodatnu pažnju (pogotovo pri početnom upoznavanju sa jezikom).
Definisanje klase
Da bismo se upoznali sa načinom definisanja klasa u Python-u, kreiraćemo jednostavnu klasu koja (praktično) predstavlja kolekciju podataka i koristi nekoliko osnovnih 'pristupnih mehanizama', međutim, na ovom mestu se pre svega susrećemo sa prilično 'idiosinkratičnim' načinom definisanja klasa u Python-u.
Ukratko: Python ne omogućava preciznu deklaraciju polja, već se polja definišu 'usput', u okviru konstruktora.
Pre nego što se upoznamo sa konstruktorima u Python-u (u sledećem odeljku članka), podsetićemo se na to, da - ukoliko ipak 'pokušamo' da navedemo polja klase izvan konstruktora ....
class Osoba:
ime = ""
prezime = ""
email = ""
.... praktično dolazi do toga da Python navedena polja tretira kao statičke elemente klase (o čemu smo već pisali u članku o Objektno orijentisanom programiranju).
Da bismo dodatno ilustrovali potencijalne 'stranputice' pri definisanju klasa, razmotrićemo sledeći programski kod:
# Statičkim poljima može se pristupiti
# preko reference na klasu (Osoba)
Osoba.ime = "Petar"
Osoba.prezime = "Petrović"
Osoba.email = "petarpetrovic@domen.rs"
# Naredbe print ispisaće vrednosti
# koje smo prethodno naveli:
print(Osoba.ime) # Petar
print(Osoba.prezime) # Petrović
print(Osoba.email) # pera@gmail.com
# Ukoliko instanciramo klasu ....
osoba1 = Osoba()
osoba2 = Osoba()
# .... postavlja se pitanje šta će se desiti
# ukoliko se obratimo polju koje je naizgled
# statički element klase ....
osoba1.ime = "Jovan"
osoba2.ime = "Dejan"
# Međutim, sledeće naredbe se MOGU izvršiti,
# budući da su u pitanju polja istog naziva -
# koja NEMAJU veze jedna sa drugima
# (ispis je u komentarima):
print(osoba1.ime) # Jovan
print(osoba2.ime) # Dejan
print(Osoba.ime) # Petar
# Da bismo bolje razumeli šta se zapravo desilo,
# pozvaćemo i sledeće naredbe:
osoba1.brzina_vetra = "Oksimoron"
osoba2.brzina_vetra = "Aglomeracija"
# Naredbe ispisa se (ponovo) mogu izvršitim
# (ispis je ponovo u komentarima):
print(osoba1.brzina_vetra) # Oksimoron
print(osoba2.brzina_vetra) # Aglomeracija
Dakle: Python (najprostije rečeno) omogućava da se polja dodaju na vrlo neformalan način (usput/'ad hoc'), što praktično znači da (doslovno) postoji polje ime koje pripada klasi, ALI .... objekti osoba1 i osoba2 imaju svoja sopstvena polja sa nazivom ime (i ta polja nemaju veze sa poljem ime koje pripada klasi Osoba, niti imaju veze jedno sa drugim).
Konstruktor
Za definisanje konstruktora (i - najpraktičnije - za definisanje polja klase), koristi se funkcija posebnog imena __init__:
class Osoba:
# Ovoga puta, polja ime, prezime i email
# NEĆEMO navoditi izvan konstruktora!
def __init__(self, ime, prezime, email):
self.ime = ime
self.prezime = prezime
self.email = email
Pošto Python (kao što smo već nagovestili), 'ne zahteva' da deklarišemo polja klase (niti omogućava da deklarišemo polja klase), * najuobičajeniji način "neformalnog deklarisanja" polja podrazumeva da se polja "obznane" (i inicijalizuju) preko konstruktora, a nakon definisanja konstruktora, objekat se može instancirati na elegantniji način (koji je uobičajen i u drugim jezicima):
osoba1 = Osoba("Petar", "Petrović", "petarpetrovic@domen.rs")
Pored konstruktora, unutar klase mogu se (naravno) definisati i druge/opšte metode.
Definisanje metoda klase
Za definisanje metoda u okviru klase, koristi se rezervisana reč def: *
class Osoba:
def __init__(self, ime, prezime, email):
self.ime = ime
self.prezime = prezime
self.email = email
def ispis(self):
print("Ime: " + ime + "\n")
print("Prezime: " + prezime + "\n")
print("E-mail: " + email + "\n")
Sada je moguće pozivati metodu ispis (za objekat koji smo prethodno instancirali) ....
osoba1.ispis()
.... pri čemu se dobija očekivani rezultat:
Ime: Petar
Prezime: Petrović
E-mail: petarpetrovic@domen.rs
Primer upotrebe Python-a
Za kraj uvodnog članka, pokazaćemo - preko sasvim jednostavne skripte - šta je prava "poenta" skriptnog jezika kao što je Python.
# ----------------------------------------- #
f = open("linkovi.txt", "r")
s = ""
linkovi = f.read().split("\n")
f.close()
# ----------------------------------------- #
for link in linkovi:
red = link.split(";")
if len(red) != 2: continue
href = red[0].strip()
tekst = red[1].strip()
s += f"<a href='{href}'>{tekst}</a>\n"
# ----------------------------------------- #
print(s)
f = open("linkovi_2.txt", "w")
f.write(s)
f.close()
# ----------------------------------------- #
Korišćenjem veoma malog broja 'linija koda' (manje od 15), napisali smo program koji:
- učitava tekstualnu datoteku
- deli sadržaj datoteke na redove
- prolazi kroz sve redove i u svakom redu pronalazi URL sajta i naziv sajta
- kreira HTML link (preko podataka koji su pronađeni u prethodnom koraku)
- ispisuje formatirane linkove na ekranu
- beleži formatirane linkove u datoteku
Praktičan rezultat izvršavanja skripte je sledeći: od običnog teksta - pri čemu ulazni tekst namerno nije formatiran na optimalan način * ....
www.proba.com;proba
www.test.com; test
www.sajt.com ; sajt
.... nastaju HTML linkovi:
<a href='www.proba.com'>proba</a>
<a href='www.test.com'>test</a>
<a href='www.sajt.com'>sajt</a>
Kratka analiza
Prethodnu skriptu prikazali smo iz dva razloga: da pokažemo da se uz Python može uraditi "mnogo toga sa malo linija koda", ali, pre svega - da potaknemo mlađe čitaoce na razmišljanje.
Python je veoma "zgodan" za slične zahvate (a svakako može poslužiti i za neke od ozbiljnijih poduhvata), međutim, uvek se postavlja pitanje u vezi sa tim da li mlađi programeri treba odmah da se priklone sažetom pristupu kakav nudi Python (ili neki drugi skriptni jezik)?!
Ako pitate nas, odgovor je - nikako. :)
Python, Node.Js, Lua i druge slične tehnologije, mogu biti sjajni alati za iskusne programere koji "dobro znaju šta rade" - i pri tom žele da određene zadatke obave na što jednostavniji način.
Za osobe koje tek uče programiranje, Python i slični jezici mnogo toga olakšavaju (rekli bismo, u prevelikoj meri), a to nije dobar način da se nauči programiranje.
Sledeći koraci ....
Posle početnog upoznavanja sa osnovnim operacijama u programskom jeziku Python, verovatno razmišljate o tome šta bi sve, u nastavku, moglo da se "radi i gradi" uz ovakav jezik.
Odgovor je "sve i svašta", a mi za početak pripremamo članak u kome ćemo pokazati kako se preko Python-a može (brzo i lako) kreirati jednostavan - ali sasvim solidan i funkcionalan - "kompajler" za markup jezik.
Nakon toga, bavićemo se back-end tehnologijama (kao što su FastAPI, Flask i sl), a biće i drugih tema ....