Osnove programiranja - programski jezik Python
Ovo su beleške sa vežbi.
- Beleške predstavljaju pojašnjenja i rešenja zadataka na predmetu Osnove Programiranja.
- Tekstove zadataka i materijale sa predavanja možete pronaći na enastav-i.
1 Upoznavanje sa python okruženjem
1.1 Komunikacija sa Python-om
U Python-u su 2 i 2 4.
4
Želimo da ispišemo nešto u konzolu?
Zdravo svima!
Želimo da napišemo funkciju?
# coding: utf-8
def say_hello():
print("Ćao!")
Želimo da pozovemo funkciju?
Ćao!
1.2 Pokratanje Python programa
Kada želimo da pokrenemo program koji se nalazi na putanji /home/vas_username/Desktop/ime_fajla.py :
python3 /home/vas_username/Desktop/ime_fajla.py
1.3 Terminal
- Pri otvaranju terminala uvek se nalazimo u home direktorijumu
korisnika koji je ulogovan na sistem.
Želim da vidim gde se trenutno nalazim
Želimo da idemo u neki direktorijum
cd putanja/do/vaseg/direktorijuma
Vraćanje u home direktorijum.
Šta imam u direktorijumu?
Želim da znam koje postoje opcije neke komande
man naziv_komande
# man ls
1.4 primer chaos.py
Imamo primer jednog Python programa:
# File: chaos.py
# A simple program illustrating chaotic behavior.
def main():
print("This program illustrates a chaotic function")
x = eval(str(input("Enter a number between 0 and 1: ")))
for i in range(10):
x = 3.9 * x * (1 - x)
print(x)
main()
Neki standardni idiomi petlji:
# nije mi bitno koliko puta se izvršava petlja
for _ in range(3):
print("Hello!")
# ista stvar samo sa while
i = 0
while i < 3:
i += 1
print("Hello!")
... ... Hello!
Hello!
Hello!
... >>> ... ... ... Hello!
Hello!
Hello!
Koji je čitljiviji način?
Promeniti ispis chaos.py tako da ispisuje u tabeli sa 2 kolone.
def chaos():
print("This program illustrates a chaotic function")
first = eval(str(input("Enter first number between 0 and 1: ")))
second = eval(str(input("Enter second second between 0 and 1: ")))
for i in range(10):
x = 3.9 * first * (1 - first)
y = 3.9 * second * (1 - second)
print(str(x) + 4 * " " + "|" + 4 * " " + str(y))
This program illustrates a chaotic function
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
0.6240000000000001 | 0.819
2 Python programi
2.1 convert.py
Program sa uvodnom porukom:
# convert.py
# A program to convert Celsius temps to Fahrenheit
# by: Susan Computewell
def fahrenheit():
print("Dobrodošli u program koji konvertuje Farenhajte u Celzijuse")
celsius = eval(str(input("What is the Celsius temperature? ")))
fahrenheit = 9/5 * celsius + 32
print("The temperature is " + str(fahrenheit) + " degrees Fahrenheit.")
Pozivanje funkcije:
Dobrodošli u program koji konvertuje Farenhajte u Celzijuse
What is the Celsius temperature? 12
The temperature is 53.6 degrees Fahrenheit.
convert.py takav da ispisuje konverziju u tabeli od 10 do 100 stepeni Celzijusa.
def fahrenheit_table():
print("celzius" + "\t" + "|" + "\t" + "farenhajt")
print(30 * "-")
for c in range(0, 100, 10):
f = 9/5 * c + 32
print(str(c) + "\t" + "|" + "\t" + str(f))
Poziv:
celzius | farenhajt
------------------------------
0 | 32.0
10 | 50.0
20 | 68.0
30 | 86.0
40 | 104.0
50 | 122.0
60 | 140.0
70 | 158.0
80 | 176.0
90 | 194.0
2.2 Eval funkcija Python interpretera
eval(...) je funkcija kojom praktično kažete:
"Python-e, ovaj tekst koji ti dajem izvrši kao program."
broj = eval('10')
broj
n_torka = eval('1, 2, 3')
n_torka
lista = eval('[11, 22, 33]')
lista
10
>>> (1, 2, 3)
>>> [11, 22, 33]
2.3 avg.py
Program koji izračunava srednje vrednosti:
# avg2.py
# A simple program to average two exam scores
# Illustrates use of multiple input
def my_avg():
print("This program computes the average of two exam scores.")
score1, score2, score3 = eval(
str(input("Enter three scores separated by a comma: ")))
average = (score1 + score2 + score3) / 3
print("The average of the scores is: " + str(average))
Poziv funkcije:
This program computes the average of two exam scores.
The average of the scores is: 11
2.4 futval.py
Program za računanje investicija
# futval.py
# A program to compute the value of an investment
# carried 10 years into the future
def futval():
print("This program calculates the future value")
print("of a 10-year investment.")
principal = eval(input("Enter the initial principal: "))
inflation = eval(input("Enter actual inflation: "))
for i in range(10):
principal = principal/(1 + inflation)
print("The value in 10 years is: " + str(principal))
futval()
... ... >>> ... ... ... ... ... ... ... ... >>> This program calculates the future value
of a 10-year investment.
The value in 10 years is: 7.253815028640569
3 Brojevi
3.2 Math lib
Sva naprednija matematika se nalazi u biblioteci math . Da bismo je koristili
moramo je importovati.
- Trigonometrija radi u Radijanima
import math
math.sin(90)
math.cos(90)
math.sqrt(4)
>>> 0.8939966636005579
-0.4480736161291701
2.0
3.3 range funkcija
- Vraća lenju sekvencu - objekat
range čiji se pojedinačni elementi izračunavaju naknadno po potrebi.
O lenjoj evaluaciji možete čitati ovde.
... 0
1
2
for i in range(10, 20, 2):
i
... 10
12
14
16
18
for i in range(10, -10, -3):
i
... 10
7
4
1
-2
-5
-8
3.4 Prosta primena brojeva
Program koji izračunava cenu pice po kvadratnom centimetru za dati poluprečnik
i cenu cele pice:
# import alias
import math as m
def cena_po_centimetru(r, cena):
"""Izracunava cenu pice po kvadratnom centimetru.
Arguments:
r -- poluprecnik cele pice u centimetrima
cena -- cena cele pice u dinarima"""
# kovertujem argumente iz stringa u realne brojeve
r = float(r)
cena = float(cena)
print("Cena pice po kvadratnom centimetru je: " +
str(r ** 2 * m.pi / cena) + " din.")
Obratite pažnju na docstring kojim opisujemo šta radi funkcija. Više o tome
možete naći ovde.
Pozivanje funkcije:
r = eval(input("Unesite poluprecnik pice u centimetrima: "))
cena = eval(input("Unesite cenu cele pice u dinarima: "))
cena_po_centimetru(r, cena)
... >>> Cena pice po kvadratnom centimetru je: 12.723450247 din.
3.5 Izračunavanje molekularne mase ugljovodonika:
def carbohydrate_mm(carbo, hydro):
m_C = 12.011
m_H = 1.0079
return "Molekularna masa takvog jedinjenja je: " \
+ str(carbo * m_C + hydro * m_H) + "."
br_C = eval(input("Unesite broj ugljenika: "))
br_H = eval(input("Unesite broj vodonika: "))
print(carbohydrate_mm(br_C, br_H))
... ... ... >>> >>> >>> >>> Molekularna masa takvog jedinjenja je: 178.4006.
3.6 Udaljenost munje
def flash_distance(happened, heard):
sound_speed = 340
distance = (heard - happened) * sound_speed
is_dead = True if distance == 0 else False
output = "Udaljenost posmatraca od munje je: " + str(distance)
# ako je udaljenost munje od posmatraca 0, pretpostavimo da se posmatrac
# nije bas proveo najbolje
if is_dead:
return output + "\n I tu je kraj."
else:
return output
munja_se_desila = eval(input("Unesite kada se desila munja: "))
covek_je_cuo_munju = eval(input("Unesite kada je covek cuo munju: "))
print(flash_distance(munja_se_desila, covek_je_cuo_munju))
... ... ... ... ... ... ... ... ... ... >>> >>> >>> >>> Udaljenost posmatraca od munje je: 37740
3.7 Zbir prvih n prirodnih brojeva
- Način koji troši vreme.
sum realizuje sve brojeve iz range kako bi ih sabrala.
To troši vreme.
unos = eval(input("Unesite n: "))
print(sum(range(unos + 1)))
>>> 10
Bolji način. Kolikigod broj da prosledimo funkciji first_n ona će se izvršiti
momentalno, nema nikakakvog prolaženja - iteracije.
def first_n(n):
return int((n * (n + 1))/2)
print("Po formuli: " + str(first_n(10000000)))
... >>> Po formuli: 50000005000000
3.8 Unos sa tastature n brojeva i njihov zbir
broj_brojeva = eval(input("Unesite broj brojeva koje zelite da unesete: "))
suma = 0
for b in range(broj_brojeva):
suma += eval(input("Unesite " + str(b + 1) + ". broj: "))
print("Zbir je: " + str(suma))
Unesite broj brojeva koje zelite da unesete: 5
Unesite 1. broj: 12
Unesite 2. broj: 34
Unesite 3. broj: 123
Unesite 4. broj: 12
Unesite 5. broj: 45
Zbir je: 226
Način sa evaluacijom u tuple:
def n_inputs():
br_brojeva = eval(input("Unesite broj brojeva koje želite da sabirate: "))
unos = eval(input("Unesite te brojeve razdvojene zarezon: "))
if len(unos) != br_brojeva:
print("Uneli ste " + str(len(unos)) + " brojeva umesto " + \
str(br_brojeva) + " koliko ste rekli da cete uneti.")
else:
print("Zbir brojeva je: " + str(sum(unos)))
n_inputs()
Unesite broj brojeva koje želite da sabirate: 3
Unesite te brojeve razdvojene zarezon: 3424,321421,3213
Zbir brojeva je: 328058
----------------------------------------
Unesite broj brojeva koje želite da sabirate: 4
Unesite te brojeve razdvojene zarezon: 1,2,34,565,67
Uneli ste 5 brojeva umesto 4 koliko ste rekli da cete uneti.
4 Rukovanje stringovima
Stringovi i liste se u Pythonu predstavljaju na sličan način, često ono što važi za liste važi i za Stringove.
5 Fajlovi
Upisati korisničke kredencijale u fajl
Korišćeni koncepti:
with izraz. Služi nam ovde kako ne bismo morali eksplicitno da pišemo fajl.close() .
Ova konstrukcija ume sama da otpusti resurs kada je to potrebno — kada se with blok završi.
try...except konstrukcija.
Znači sledeće: pokušaj da uradiš sve što je navedeno u try bloku,
ako se pri tome desi neka greška tu stani i uradi ono što je u except bloku.
Ovde je korišćena kako bismo ispisali na konzolu da je došlo do greške pri čitanju fajla, ako se to desi.
# coding: utf-8
import os
def save_credentials(uname, passw):
try:
with open("credentials.supa_od_kornjače", 'a') as creds:
creds.write(uname + "|$# ovo je delimiter #$|" + passw + os.linesep)
print("Uspesno ste upisali u fajl vaše kredencijale, %s." % uname)
except:
print("Doslo je do greske pri upisu.")
uname = input("Unesite vas username: ")
passwd = input("Unesite vas password: ")
save_credentials(uname, passwd)
>>> >>> >>> ... ... ... ... ... ... ... >>> Uspesno ste upisali u fajl vaše kredencijale, Petar.
[Obratiti pažnju!]
Fajlovi se u fajl sistemu identifikuju preko URI-ja tj. lokacija u fajl sistemu.
U kontekstu fajl sistem ime fajla kao pojam NE POSTOJI, postoji samo njegova putanja čiji kraj mi (ljudi) između sebe
zovemo "ime fajla".
Kada navedemo samo ime fajla (kao u primeru iznad credentials.supa_od_kornjače ) onda zapravo upućujemo fajl sistem da
traži u repozitorijumu u kojem se trenutno izvršava program. Dakle:
ime.extension == putanja/do/direktorijuma/gde/se/izvrsava/program/ime.extension
putanja/do/direktorijuma/gde/se/izvrsava/program/ se još zove i current directory i u terminalu u kome pokrećete program
se može dobiti sa:
Čitanje podataka iz fajla
# coding: utf-8
def read_credentials(file_name):
delimiter = "|$# ovo je delimiter #$|"
with open(file_name, 'r') as f:
for l in f.readlines():
print("korisničko ime: " + l.split(delimiter)[0])
print("lozinka: " + l.split(delimiter)[1])
read_credentials("credentials.supa_od_kornjače")
>>> ... ... ... ... ... ... >>> korisničko ime: sda
lozinka: dsad
korisničko ime: pera
lozinka: petrovicNjegos
5.1 Program koji kombinuje sadržaj dva fajla i snima ga u treći
import os
def kombinuj(korisnci_f, artikli_f , statistika_f):
delimiter = "|"
with open(korisnci_f, 'r') as korisnici, \
open(artikli_f, 'r') as artikli, \
open(statistika_f, 'w') as statistika:
korisnici_lines = korisnici.readlines()
artikli_lines = artikli.readlines()
# koliko ima korisnika toliko ima i evidencija o njihovim artiklima
l = len(korisnici_lines)
for i in range(l):
ime = korisnici_lines[i].split(delimiter)[0]
# nalazim ukupnu cenu artikala iz odgovarajuce linije
cene_kao_stringovi = artikli_lines[i].split(delimiter)
ukupna_cena = 0
for c in cene_kao_stringovi:
ukupna_cena += int(c)
# racunam prosecnu cenu
prosecna_cena = ukupna_cena / len(cene_kao_stringovi)
# upisujem u statistiku u fajl
statistika.write(ime + delimiter + str(ukupna_cena) +
delimiter + str(prosecna_cena) + os.linesep)
kombinuj("korisnici.txt", "racuni.txt", "statistika.txt")
5.1.1 Isti program, malo pametnije
Korišćeni koncepti:
zip funkcija. Ovde nam služi da istovremeno iteriramo kroz linije u oba fajla. Veoma je korisna i često se koristi
u Python-u.
U Python 3 zip funkcija vraća lenji objekat (slično kao range , to je razmatrano ovde):
# U python 3
zip([1, 2, 3], ["zec", "macke", "psa"], ["skace", "predu", "laju"])
<zip object at 0x7f6de7201308>
# realizujem zip-ovanu listu tako što joj pristupam u for-u
for (broj, zivotinja, predikat) in zip([1, 2, 3], \
["zec", "macke", "psa"], \
["skace", "predu", "laju"]):
print(broj, zivotinja, predikat)
... ... ... ... 1 zec skace
2 macke predu
3 psa laju
U Python 2 zip funkcija vraća već izvršenu(evaluiranu) listu (pa je tu jasnije šta zaista radi zip ):
# U python 2
zip([1,2,3], ["zec", "macke", "psa"], ["skace", "predu", "laju"])
[(1, 'zec', 'skace'), (2, 'macke', 'predu'), (3, 'psa', 'laju')]
- List comprehensions da pretvorimo
string -ove u int -ove kako bismo mogli da ih saberemo sa sum .
List comprehensions je veoma moćan i često korišćen koncept u Python-u.
Za Python važi - tamo gde može list comprehensions nikada ne koristiti imperativne for petlje.
import os
def kombinuj(korisnci_f, artikli_f , statistika_f):
delimiter = "|"
with open(korisnci_f, 'r') as korisnici, \
open(artikli_f, 'r') as artikli, \
open(statistika_f, 'w') as statistika:
for (l_korisnik, l_artikli) in zip(korisnici.readlines(),
artikli.readlines()):
ime = l_korisnik.split(delimiter)[0]
# ova konstrukcija se zove list comprehensions
cene = [int(c) for c in l_artikli.split(delimiter)]
# nalazim ukupnu cenu artikala iz odgovarajuce linije
ukupna_cena = sum(cene)
# racunam prosecnu cenu
prosecna_cena = ukupna_cena / len(cene)
# upisujem statistiku u fajl
# prikaz na tri decimale
statistika.write(ime + delimiter + '%.3f'%ukupna_cena +
delimiter + '%.3f'%prosecna_cena + os.linesep)
kombinuj("korisnici.txt", "racuni.txt", "statistika2.txt")
5.1.2 Dodatak o try...except konstrukciji za_radoznale
Želimo da otvorimo fajl sa putanje. Putanja se prosleđuje kao parametar funkcije
tako da korisnik može proslediti neku nepostojeću putanju. Ako se to desi potrebno
je obavestiti korisnika da fajl na putanji ne postoji i otvoriti podrazumevani fajl.
def otvaranje_fajla(file_name):
try:
# pokušavam da otvorim fajl čije je ime prosleđeno kao argument
with open(file_name, 'r') as f:
return f.readlines()
except FileNotFoundError:
# ako je Python "bacio" FileNotFoundError onda uradi ovo ovde
print("""Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...""")
with open("korisnici.txt", 'r') as f:
return f.readlines()
# ova putanje ne postoji
otvaranje_fajla("C:\\Documents\Pictures\more.jpg")
Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...
['pera|peric\n', 'jova|jovic\n', 'steva|stevic\n']
except blok koji nema navedenu klasu greške će uhvatiti sve greške
def otvaranje_fajla(file_name):
try:
# pokušavam da otvorim fajl čije je ime prosleđeno kao argument
with open(file_name, 'r') as f:
return f.readlines()
except:
# ako je Python "bacio" bilo kakvu grešku
print("""Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...""")
with open("korisnici.txt", 'r') as f:
return f.readlines()
Ovaj program je ekvivalentan sa onim predhodnim.
U except izrazu je takođe moguć as izraz:
def otvaranje_fajla(file_name):
try:
# pokušavam da otvorim fajl čije je ime prosleđeno kao argument
with open(file_name, 'r') as f:
return f.readlines()
except FileNotFoundError as e:
# ako je Python "bacio" FileNotFoundError onda uradi ovo ovde
print("""Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...""")
print("Greška koju ste dobili je: " + e.strerror)
with open("korisnici.txt", 'r') as f:
return f.readlines()
otvaranje_fajla("C:\\Documents\Pictures\more.jpg")
Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...
Greška koju ste dobili je: No such file or directory
['pera|peric\n', 'jova|jovic\n', 'steva|stevic\n']
Moguće je navoditi više except blokova, tada će biti uhvaćena
prva greška koja odgovara grešci koja se desila.
def otvaranje_fajla(file_name):
try:
# pokušavam da otvorim fajl čije je ime prosleđeno kao argument
with open(file_name, 'r') as f:
return f.readlines()
except FileNotFoundError as e:
# ako je Python "bacio" FileNotFoundError onda uradi ovo ovde
print("""Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...""")
print("Greška koju ste dobili je: " + e.strerror)
with open("korisnici.txt", 'r') as f:
return f.readlines()
except IOError:
print("Desio se neki error")
otvaranje_fajla("nepostojeća putanja")
Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...
Greška koju ste dobili je: No such file or directory
['pera|peric\n', 'jova|jovic\n', 'steva|stevic\n']
# coding: utf-8
import os
def otvaranje_fajla(file_name):
try:
# pokušavam da otvorim fajl čije je ime prosleđeno kao argument
with open(file_name, 'r') as f:
return f.readlines()
except IOError as e:
# iako se zapravo desio FileNotFoundError ipak će se ući u ovaj blok
# jer je FileNotFoundError vrsta IOError-a a
# ovaj except blok je naveden pre onog sa FileNotFoundError-om
print("Desio se neki error sa porukom: " + e.strerror + os.linesep +
"i brojem: " + str(e.errno))
except FileNotFoundError as e:
print("""Fajl koji želite da otvorite ne postoji.
Otvoriću podrazumevani...""")
print("Greška koju ste dobili je: " + e.strerror)
with open("korisnici.txt", 'r') as f:
return f.readlines()
otvaranje_fajla("nepostojeća putanja")
Desio se neki error sa porukom: No such file or directory
i brojem: 2
6 Funkcije
Funkcije su izrazi (expressions) koji enkapsuliraju radnju nad nekim podacima.
Zato svaka funkcija treba da ima:
Nakon definicije funkcije se mogu pozvati.
Funkcija se poziva tako što se navede njeno ime sa sintaksom poziva (to praktično znači ime_funkcije() , () je sintaksa poziva u Python-u).
# 2 i 3 su argumenti
ime_funkcije(2, 3)
5
6.1 Čiste funkcije
Ako Python izraze želimo da posmatramo kao
matematičke izraze onda moramo obezbediti da važi matematički
princip zamene simbola.
Šta to praktično znači?
Ovako izgleda niz nekih matematičkih izraza:
x = 1
y = 2
def f1(x):
return 5 * x + 1
def f2(x):
return x**2 + 2
# Koliko je z?
z = f1(x) + f2(y)
Ovo se rešava tako što prosto zamenjujemo simbole:
Dalje imamo:
z = (5 * 1 + 1) + (2**2 + 2)
Pa je rezultat:
12
Da bismo Python izraze posmatrali kao matematičke izraze moramo
obezbediti da sve funkcije budu čiste i bez sporednih efekata.
Funkcije su čiste (pure functions) ako za njih važe oba naredna
uslova?
- Uvek daju isti rezultat za iste argumente.
- Nemaju sporednih efekata (side effects)
Šta znači da funkcije nemaju sporednih efekata?
- Ne menjaju globalne variable niti bilo koje druge koje nisu u
njenom vidljivom opsegu (tj. nisu definisane unutar njenog
def
bloka, u Python-u)
Ako su naše funkcije čiste onda UVEK možemo da kažemo šta će one
uraditi u našem sistemu.
Tako što prosto zamenimo pozive funkcija sa njihovim rezultatom.
Kada izraz poziva funkcije možemo uvek da zamenimo njenim
rezultatom onda za funkciju kažemo da je referencijalno
transparentna.
6.2 Primeri funkcija
Funkcija koja učitava fajl i njegova sadržaj vraća kao listu.
# coding: utf-8
def citanje_iz_fajla(file_name, delimiter):
"""Učitava kredencijale korisnika.
Args:
file_name: Ime fajla u kome se nalaze kredencijali.
delimiter: Delimiter koji je korišćen u fajlu.
Returns:
Vraća listu koja sadrži parove (kao liste) korisničkog imena i lozinke.
"""
with open(file_name, 'r') as f:
return [l.strip().split(delimiter) for l in f.readlines()]
print(citanje_iz_fajla
("credentials.supa_od_kornjače", "|$# ovo je delimiter #$|"))
[['uno', 'dos'], ['kilo', 'kilo'], ['joki', 'kijo'], ['mile', 'milic']]
Funkcija koja vrši registraciju korisnika
# coding: utf-8
import os
def upisi_fajl(uname, pas, file_name, delimiter):
"""Vrši registraciju korisnika tako što upisuje njihove kredencijale u fajl.
Args:
uname: Korisnično ime
pas: Lozinka
file_name: Ime fajla u koji se upisuju kredencijali korisnika
delimiter: Delimiter koji je korišćen u tom fajlu
Retruns:
Vraća listu koja sadrži parove (kao liste) korisničkog imena i lozinke.
"""
with open(file_name, 'a') as f:
f.write(uname + delimiter + pas + os.linesep)
with open(file_name, 'r') as f:
return [l.strip().split(delimiter) for l in f.readlines()]
upisi_fajl("ana", "ananananic",
"credentials.supa_od_kornjače", "|$# ovo je delimiter #$|")
[['uno', 'dos'], ['kilo', 'kilo'], ['joki', 'kijo'], ['mile', 'milic'], ['ana', 'ananananic']]
7 Grananje — upravljanje tokom programa
Kontrola toka programa ili grananje se odnosi na mehanizam kojim usmeravamo
tok izvršavanja programa u odnosu na postavljene uslove.
Osnovna konstrukcija grananja u Python-u je if ... [elif]* ... else :
if uslov:
posao_ako_je_uslov_ispunjen
else:
posao_ako_uslov_nije_ispunjen
Uslova u opštem slučaju može biti više:
if uslov_1:
posao_ako_je_uslov_1_ispunjen
elif uslov_2:
posao_ako_je_uslov_1_neispunjen_a_uslov_2_ispunjen
...
elif uslov_n:
posao_ako_su_uslov_1_do_uslov_n-1_neispunjeni_a_uslov_n_ispunjen
else:
posao_ako_ni_jedan_navedeni_uslov_nije_ispunjen
Program koji uzračunava zaradu radnika u odnosu na radne sate.
# coding: utf-8
import os
def racunanje_zarada(ime_f, cena_sata):
koeficijent_uvecanja = 1.5
with open(ime_f, 'r') as f:
for l in f.readlines():
ime_radnika = l.split('|')[0]
radni_sati = l.split('|')[1:]
# konvertujem tekst u brojeve
zbir = 0
for sat in radni_sati:
zbir += int(sat)
osnovna_plata = cena_sata * zbir
# provera da li je broj radnih sati veći od 40
# ovo je grananje
if zbir > 40:
print("ime: " + ime_radnika + os.linesep +
"zarada: " + str(osnovna_plata * koeficijent_uvecanja))
else:
print("ime: " + ime_radnika + os.linesep + "zarada: "
+ str(osnovna_plata))
racunanje_zarada("radnici.txt", 1000)
ime: pera
zarada: 61500.0
ime: jova
zarada: 38000
ime: steva
zarada: 40000
Isti zadatak ali uz malo pametnije računanje zbira radnih sati. Korišćen je
koncept list comprehensions.
# coding: utf-8
import os
def racunanje_zarada(ime_f, cena_sata):
koeficijent_uvecanja = 1.5
with open(ime_f, 'r') as f:
for l in f.readlines():
ime_radnika = l.split('|')[0]
radni_sati = l.split('|')[1:]
zbir = sum([int(s) for s in radni_sati])
osnovna_plata = cena_sata * zbir
# provera da li je broj radnih sati veći od 40
# ovo je grananje
if zbir > 40:
print("ime: " + ime_radnika + os.linesep +
"zarada: " + str(osnovna_plata * koeficijent_uvecanja))
else:
print("ime: " + ime_radnika + os.linesep + "zarada: "
+ str(osnovna_plata))
racunanje_zarada("radnici.txt", 1000)
ime: pera
zarada: 61500.0
ime: jova
zarada: 38000
ime: steva
zarada: 40000
Program koji ocenjuje učenike po tabeli ocena.
def ocenjivanje(bodovi):
if bodovi > 0 and bodovi < 55:
return 5
elif bodovi >= 55 and bodovi < 65:
return 6
elif bodovi >= 65 and bodovi < 75:
return 7
elif bodovi >= 75 and bodovi < 85:
return 8
elif bodovi >= 85 and bodovi < 95:
return 9
elif bodovi >= 95 and bodovi <= 100:
return 10
else:
return "Nepoznata ocena"
ocenjivanje(77)
ocenjivanje(95)
ocenjivanje(96)
ocenjivanje(56)
ocenjivanje(101)
8
10
10
6
'Nepoznata ocena'
Program koji računa body mass index i određuje stepen uhranjenosti po tabeli.
# coding: utf-8
def indeks_telesne_mase(masa, visina):
bmi = masa / visina**2
if bmi <= 18.5:
return "Pothranjenost"
elif bmi > 18.5 and bmi <= 25:
return "Idealna telesna težina"
elif bmi > 25 and bmi <= 30:
return "Preterana telesna težina"
elif bmi > 30:
return "Gojaznost"
print(indeks_telesne_mase(55,1.8))
print(indeks_telesne_mase(75,1.8))
print(indeks_telesne_mase(82,1.8))
print(indeks_telesne_mase(120,1.8))
Pothranjenost
Idealna telesna težina
Preterana telesna težina
Gojaznost
Program koji računa kaznu za prekoračenje brzine.
# coding: utf-8
def kazna(brzina, ogranicenje):
glavnica = 5000
dodatak_po_jedinici_prekoracenja = 500
dodatak_za_iznad_120 = 5000
prekoracenje = brzina - ogranicenje
za_uplatu = 0
# ako je prekoracio naplati mu za svaku jedinicu prekoracenja jos
# dodatnih 500 dinara
if brzina < 120 and prekoracenje > 0:
za_uplatu = glavnica
za_uplatu += prekoracenje * dodatak_po_jedinici_prekoracenja
# ako je brzina veća od 120 km/h naplati 5000 dinara za svaku jedinicu
# prekoračenja
if brzina > 120:
prekoracenje_preko_120 = brzina - 120
za_uplatu += prekoracenje_preko_120 * dodatak_za_iznad_120
if za_uplatu > 0:
return "Vaša kazna iznosi: " + str(za_uplatu) + "."
else:
return "Niste prekoračili brzinu."
print(kazna(80,60))
print(kazna(50,60))
print(kazna(130,60))
Vaša kazna iznosi: 15000.
Niste prekoračili brzinu.
Vaša kazna iznosi: 50000.
Program koji računa zaradu dadilje.
Korišćeni koncepti:
- funkcija
round(...) . Zaokružuje razlomljen broj na ceo.
def vreme_u_minute(vreme):
"""Pretvara vreme u formatu hh:mm u minute."""
h, m = [int(i) for i in vreme.split(":")]
return h*60 + m
def minuti_u_sate(minuti):
"""Pretvara minute u sate."""
return minuti / 60
def dadilja(pocetak, kraj):
p = vreme_u_minute(pocetak)
k = vreme_u_minute(kraj)
devet = vreme_u_minute("21:00")
do_devet = devet - p
posle_devet = k - devet
za_isplatu = minuti_u_sate(do_devet) * 150 + \
minuti_u_sate(posle_devet) * 100
return "Zarada dadilje je: " + str(round(za_isplatu)) + " din."
print(dadilja('18:35','22:50'))
Zarada dadilje je: 546 din.
Program koji računa da li je godina prestupna.
def is_prestupna(godina):
# proveravam da li je poslenja godina u veku
# da bi bila poslednja u veku to znači da mora biti deljiva sa 100
# a ako je deljiva sa 100 onda je deljiva i sa 400
if godina % 400 == 0:
return True
# ako nije poslednja godina u veku onda je prestupna ako
# je dejiva sa 4
elif godina % 100 != 0 and godina % 4 == 0:
return True
else:
return False
Funkcija vraća True ako je godina prestupa, u suprotnom vraća False .
is_prestupna(1983)
is_prestupna(1984)
is_prestupna(1800)
is_prestupna(1900)
is_prestupna(2000)
False
True
False
False
True
Program koji računa da li je datum validan.
Korišćeni koncepti:
Set — Python reprezentacija matematičkih skupova. Zapisuje se {} notacijom.
Funkcija set(kolekcija) pretvara druge Python kolekcije u set.
Primer jednog seta:
Neke operacije nad setovima:
lista_kolekcija = [1, 2, 3, 4]
tuple_kolekcija = (3, 4, 5, 6, 7)
A = set(lista_kolekcija)
B = set(tuple_kolekcija)
# A bez B
A - B
# B bez A
B - A
# Unija A i B
B.union(A)
# presek A i B
B.intersection(A)
# presek B i A
A.intersection(B)
A.intersection(B) == B.intersection(A)
>>> >>> >>> >>> >>> ... {1, 2}
>>> ... {5, 6, 7}
>>> ... {1, 2, 3, 4, 5, 6, 7}
>>> ... {3, 4}
>>> ... {3, 4}
>>> True
Operator in — operator pripadanja (membership operator).
Radi za kolekcije i vraća True kada se element nalazi u kolekciji,
a u suprotnom Flase .
1 in [2, 3, 4, 5, 1, 2, 12]
1 in (2, 3, 4, 5, 1, 2, 12)
1 in {2, 3, 4, 5, 1, 2, 12}
12 in range(11, 23)
True
True
True
>>> True
Operator in se u uslovima može koristiti kao zamena za or lanac.
a = 3
a == 1 or a == 2 or a == 3
a in (1, 2, 3)
(a == 1 or a == 2 or a == 3) == (a in (1, 2, 3))
>>> True
>>> True
>>> True
Provera validnosti datuma:
# coding: utf-8
def is_valid(datum):
dan, mesec, godina = [int(i.strip()) for i in datum.split("/")]
meseci_od_30 = [4, 6, 9, 11]
# meseci od 31 su svi između 1 i 12 koji ne spadaju
# u one koji imaju 30 dana i nisu februar
meseci_od_31 = set(range(1, 13)) - set(meseci_od_30) - set([2])
# ako je u pitanju februar
if mesec == 2 and dan > 0:
# prestupnim godinama ima 29 dana
if is_prestupna(godina) and dan <= 29:
return True
# kada nije prestupna godina ima 28 dana
elif dan <= 28:
return True
else:
return False
elif mesec in meseci_od_30 and dan > 0 and dan <= 30:
return True
elif mesec in meseci_od_31 and dan > 0 and dan <= 31:
return True
else:
return False
is_valid("24/5/1962")
is_valid("31/9/2000")
is_valid("29/2/2000")
is_valid("29/2/2001")
is_valid("30/2/2000")
True
False
True
False
False
Program koji računa redni broj dana u godini.
U ovom zadatku je korišćena funkcija za računanje prestupne godine koju smo
ranije definisali.
def redni_broj_dana(datum):
dd, mm, gggg = [int(i.strip()) for i in datum.split("/")]
dan_u_godini = 31 * (mm - 1) + dd
if mm > 2:
dan_u_godini -= (4 * mm + 23) / 10
if is_prestupna(gggg):
dan_u_godini += 1
return round(dan_u_godini)
redni_broj_dana("1/1/2000")
redni_broj_dana("14/3/2000")
redni_broj_dana("31/12/2000")
redni_broj_dana("31/12/2001")
1
74
366
365
8 Petlje i logički izrazi
Tabela subjektivnog osećaja hladnoće
def sub_osecaj(t, v):
return 3.74 + 0.6215 * t - 35.75 * (v**0.16) + \
0.4275 * t * (v**0.16)
def napravi_tabelu(min_v, max_v, min_t, max_t):
temperatures = range(min_t, max_t + 1)
# prvi red
first_row = [" "] + ["t=" + str(i) for i in temperatures]
print("\t".join(first_row))
# ostali redovi
for v in range(min_v, max_v + 1):
# deo sa v = ...
vetar = "v=" + str(v)
# ostale kolone
temps = ["{0:.3f}".format(sub_osecaj(t, v)) for t in temperatures]
# ceo red
red = "\t".join([vetar] + temps)
print(red)
napravi_tabelu(0, 10, 5, 10)
t=5 t=6 t=7 t=8 t=9 t=10
v=0 6.848 7.469 8.091 8.712 9.334 9.955
v=1 -26.765 -25.716 -24.667 -23.618 -22.569 -21.520
v=2 -30.707 -29.608 -28.509 -27.410 -26.311 -25.212
v=3 -33.224 -32.093 -30.962 -29.831 -28.700 -27.569
v=4 -35.112 -33.957 -32.802 -31.647 -30.491 -29.336
v=5 -36.637 -35.463 -34.288 -33.113 -31.939 -30.764
v=6 -37.924 -36.733 -35.542 -34.352 -33.161 -31.970
v=7 -39.042 -37.837 -36.632 -35.427 -34.222 -33.017
v=8 -40.033 -38.816 -37.598 -36.380 -35.162 -33.945
v=9 -40.925 -39.696 -38.467 -37.238 -36.009 -34.780
v=10 -41.737 -40.498 -39.258 -38.019 -36.780 -35.540
Koliko treba da prođe godina da bi se novac u banci udvostručio
def broj_godina(kamata):
ulog = 1
dvostruko = 2 * ulog
godina = 0
while ulog < dvostruko:
ulog += ulog * kamata
godina += 1
print("U godini " + str(godina) + " ulog se uvećao na " + str(ulog))
print("Da bi se ulog udvostručio potrebno je da prođe " + str(godina) +
" godina.")
U godini 1 ulog se uvećao na 1.04
U godini 2 ulog se uvećao na 1.0816000000000001
U godini 3 ulog se uvećao na 1.124864
U godini 4 ulog se uvećao na 1.16985856
U godini 5 ulog se uvećao na 1.2166529024
U godini 6 ulog se uvećao na 1.265319018496
U godini 7 ulog se uvećao na 1.3159317792358398
U godini 8 ulog se uvećao na 1.3685690504052734
U godini 9 ulog se uvećao na 1.4233118124214843
U godini 10 ulog se uvećao na 1.4802442849183437
U godini 11 ulog se uvećao na 1.5394540563150774
U godini 12 ulog se uvećao na 1.6010322185676804
U godini 13 ulog se uvećao na 1.6650735073103877
U godini 14 ulog se uvećao na 1.7316764476028033
U godini 15 ulog se uvećao na 1.8009435055069154
U godini 16 ulog se uvećao na 1.872981245727192
U godini 17 ulog se uvećao na 1.9479004955562795
U godini 18 ulog se uvećao na 2.025816515378531
Da bi se ulog udvostručio potrebno je da prođe 18 godina.
Sirakuza sekvenca
def sirakuza(start):
ret_val = [start]
num = start
while num != 1:
if num % 2 == 0:
num = num / 2
else:
num = 3 * num + 1
ret_val.append(int(num))
return ret_val
[5, 16, 8, 4, 2, 1]
Provera da li je broj prost
import math as m
def is_prost(broj):
for i in range(2, int(m.sqrt(broj)) + 1):
if broj % i == 0:
return False
return True
is_prost(127)
is_prost(123)
is_prost(2)
is_prost(24)
is_prost(13)
is_prost(15)
is_prost(9)
True
False
True
False
True
False
False
Funkcija koja vraća listu prostih brojeva koji su manji od
prosleđeno argumenta
def get_prosti_to(broj):
ret_val = []
for i in range(1, broj):
if is_prost(i):
ret_val.append(i)
return ret_val
[1, 2, 3, 5, 7, 11, 13, 17, 19]
Isti zadatak ali uz korišćenje list comprehensions.
def get_prosti_to(broj):
return [i for i in range(1, broj) if is_prost(i)]
[1, 2, 3, 5, 7, 11, 13, 17, 19]
Najveći zajednički delilac po Euklidovom algoritmu
def nzd(m, n):
while m != 0:
m_staro = m
n_staro = n
n = m_staro
m = n_staro % m_staro
return n
5
5
8.1 get_prost_to uz korišćenje filter funkcije. za_radoznale
def get_prost_to(broj):
filter(is_prost, range(1, broj))
[1, 2, 3, 5, 7, 11, 13, 17, 19]
filter dakle kao parametar prima funkciju i neku strukturu kroz
koju se može "prolaziti". Vraća samo one elemente strukture za koje
prosleđena funkcija vraća istinitosno tačnu vrednost
(npr. True ). Pogledaj poglavlje o funkcijama višeg reda u
dodatku.
8.2 is_prost uz korišćenje funkcija višeg reda za_radoznale
import math as m
def is_prost(broj):
return not any(filter(lambda x: broj % x == 0,
range(2, int(m.sqrt(broj)) + 1)))
is_prost(127)
is_prost(123)
is_prost(2)
is_prost(24)
is_prost(13)
is_prost(15)
True
False
True
False
True
False
8.3 Zadatak koji liči na projekat
Korisnik se prijavljuje na sistem. Nakon toga unosi
proizvode. Svaki put kada unese neki proizvod program mu ispisuje
sve proizvode koji se nalaze na spisku. Program se prekida kada
korisnik unese quit za naziv, količinu ili cenu nekog proizvoda.
Spisak registrovanih korisnika se nalazi u korisnici.register a
spisak proizvoda je u proizvodi.vezbe_7 .
# coding: utf-8
import os
delimiter = "|"
def prijava(u_name, pasw):
with open("korisnici.register", 'r') as f:
for l in f.readlines():
if [u_name, pasw] == [s.strip() for s in l.split(delimiter)]:
return True
return False
def prikazi_proizvode(fajl):
with open(fajl, 'r') as p:
for l in p.readlines():
print("\t".join([i.strip() for i in l.split(delimiter)]))
def program():
u_name = input("Unesite korisničko ime: ")
pasw = input("Unesite lozinku: ")
if not prijava(u_name, pasw):
print("Pogrešan par korisničkog imena i lozinke")
return
while True:
naziv = input("Unesite naziv proizvoda: ")
if naziv == "quit":
return
cena = input("Unesite cenu proizvoda: ")
if cena == "quit":
return
kolicina = input("Unesite količinu proizvoda: ")
if kolicina == "quit":
return
# izbacim whitespace karaktere sa kraja i pocetka
naziv, cena, kolicina = [s.strip() for s in [naziv, cena, kolicina]]
with open("proizvodi.vezbe_7", 'a') as p:
p.write(delimiter.join([naziv, cena, kolicina]) + os.linesep)
# prikazujem sve proizvode
prikazi_proizvode("proizvodi.vezbe_7")
Program se pokreće sa:
9 Kolekcije podataka
Ispis i dodavanje knjiga
Korišćeni koncepti:
# Ova globalna varijabla simulira fajl u kome se nalaze podaci o knjizi
knjige = []
def dodaj_knjigu(k):
knjige.append(k)
def ispisi_sve_knjige():
# string u više linija
zaglavlje = ("id" "\t" "naslov" "\t" "autori" "\t" "izdavac" "\t"
"cena" "\t" "kolicina" "\t" "godina")
print(zaglavlje)
print(int(3/2 * len(zaglavlje)) * "-")
for k, i in zip(knjige, range(len(knjige) + 1)):
print(str(i + 1) + "\t" + k["naslov"] + "\t" + k["autori"] + "\t" +
k["izdavac"] + "\t" + str(k["cena"]) + "\t" + str(k["kolicina"]) +
"\t" + str(k["godina"]))
dodaj_knjigu({"naslov": "N1", "autori": "A1, A2", "izdavac": "I1",
"cena": 123.23, "kolicina": 12, "godina": 2016})
dodaj_knjigu({"naslov": "N2", "autori": "A11, A22", "izdavac": "I2",
"cena": 123.23, "kolicina": 12, "godina": 2015})
ispisi_sve_knjige()
id naslov autori izdavac cena kolicina godina
-------------------------------------------------------------------
1 N1 A1, A2 I1 123.23 12 2016
2 N2 A11, A22 I2 123.23 12 2015
Isti zadatak ali sa čitanjem i pisanjem u fajl
Korišćeni koncepti:
Opcioni imenovani parametri
Python ima mogućnost pisanja funkcija koje imaju opcione
parametre.
Opcioni parametri su oni koji funkciji mogu ali ne moraju
biti prosleđeni pri pozivu.
Python pruža tri tipa takvih parametara:
Imenovani
def foo_a(obavezan, opcioni1="nisi prosledio opcioni1",
opcioni2="nisi prosledio opcioni1"):
print(obavezan)
print(opcioni1)
print(opcioni2)
foo_a("ovo moram da prosledim")
ovo moram da prosledim
nisi prosledio opcioni1
nisi prosledio opcioni1
foo_a("ovo moram da prosledim", "prosleđujem opcioni1")
ovo moram da prosledim
prosleđujem opcioni1
nisi prosledio opcioni1
foo_a("ovo moram da prosledim", "prosleđujem opcioni1",
"prosleđujem opcioni2")
ovo moram da prosledim
prosleđujem opcioni1
prosleđujem opcioni2
Neimenovani
def foo_b(obavezni, *args):
print(obavezni)
print("ostali parametri: ")
print(*args)
ovo mora
ostali parametri:
foo_b("ovo mora", 1, 2, 3, "pera", {'zivotinja': 'zec'})
ovo mora
ostali parametri:
1 2 3 pera {'zivotinja': 'zec'}
Ključne reči
def foo_c(obavezni, **kwargs):
print(obavezni)
for (k, v) in kwargs.items():
print(k, v)
ovo mora
foo_c("ovo mora", ime1="vrednost1", ime2=2, ime3=[1, 2, 3])
ovo mora
ime2 2
ime3 [1, 2, 3]
ime1 vrednost1
Funkcija naravno može od jednom da ima sve navedene tipove
opcionih parametara ( ukoliko to ima smisla ).
*args i **kwargs su samo nazivi. Sve što počinje sa * i
** se tretira kao skup neimenovanih i imenovanih opcionih
parametara, respektivno.
def foo_d(obavezni, *neimenovani_parametri,
imenovani="default value", **kljucne_reci):
print(obavezni)
print("Neimenovani opcioni:")
print(neimenovani_parametri)
print("Imenovani parametri:")
print(imenovani)
print("Ključne reči:")
for (k, v) in kljucne_reci.items():
print(k, v)
foo_d("ovo mora", 1, 2, "neimenovani", imenovani="prosleđujem imenovani",
kljucna_rec_1="k1", kljucna_rec_2="k2", kljucna_rec_3=33)
ovo mora
Neimenovani opcioni:
(1, 2, 'neimenovani')
Imenovani parametri:
prosleđujem imenovani
Ključne reči:
kljucna_rec_3 33
kljucna_rec_1 k1
kljucna_rec_2 k2
foo_d("ovo mora", 1, 2, imenovani="prosleđujem imenovani")
ovo mora
Neimenovani opcioni:
(1, 2)
Imenovani parametri:
prosleđujem imenovani
Ključne reči:
foo_d("ovo mora", imenovani="prosleđujem imenovani")
ovo mora
Neimenovani opcioni:
()
Imenovani parametri:
prosleđujem imenovani
Ključne reči:
foo_d("ovo mora", k_rec = "ovo je kljucna rec")
ovo mora
Neimenovani opcioni:
()
Imenovani parametri:
default value
Ključne reči:
k_rec ovo je kljucna rec
Ne mogu neimenovani argumenti ići posle imenovanih
parametara ili posle ključnih reči:
foo_d("ovo mora", imenovani="prosleđujem imenovani", "opcioni")
File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
foo_d("ovo mora", k_rec = "ovo je kljucna rec", 12)
File "<stdin>", line 1
SyntaxError: non-keyword arg after keyword arg
if u jednom redu
ako_je_uslov_tačan if uslov else ako_uslov_nije_tačan
a = 4
a = "jeste veće od 5" if a > 5 else "nije veće od 5"
nije veće od 5
Implementacija:
import os
# ova funkcija koristi imenovane opcione parametre
def file_to_list(f_name, delimiter='|',
numericki=["cena", "kolicina", "godina"]):
with open(f_name, 'r') as f:
knjige = []
# prolazim kroz svaku liniju
for l in f.readlines():
# u svakoj liniji je po jedna knjiga
k = {}
# liniju splitujem po delimiteru i sklonim whitespace
# karaktere sa kraja i početka
podaci_u_liniji = [d.strip() for d in l.split(delimiter)]
# pogledaj šta je zip ranije
for osobina, podaci in zip(["naslov", "autori", "izdavac",
"cena", "kolicina", "godina"],
podaci_u_liniji):
# koristim if u jednom redu
# da pretvodim numeričke podatke u brojeve
# i izgrađujem rečnik koji predstavlja jednu knjigu
k[osobina] = float(podaci) if osobina in numericki else podaci
# dodam knjigu
knjige.append(k)
return knjige
def list_to_file(li, f_name, delimiter="|"):
with open(f_name, 'a') as f:
lines = []
for dic in li:
# preuzmem sve podatke iz rečnika po standardnom redosledu
line_data = [dic["naslov"], dic["autori"], dic["izdavac"],
dic["cena"], dic["kolicina"], dic["godina"]]
# napravim liniju za snimanje u fajl
lines.append(delimiter.join([str(v) for v in line_data]) +
os.linesep)
f.writelines(lines)
def dodaj_knjigu(k):
list_to_file([k], "knjige.data")
def ispisi_sve_knjige(f_name):
zaglavlje = ("id" "\t" "naslov" "\t" "autori" "\t" "izdavac" "\t"
"cena" "\t" "kolicina" "\t" "godina")
print(zaglavlje)
print(int(3/2 * len(zaglavlje)) * "-")
knjige = file_to_list(f_name)
for k, i in zip(knjige, range(len(knjige) + 1)):
print(str(i + 1) + "\t" + k["naslov"] + "\t" + k["autori"] + "\t" +
k["izdavac"] + "\t" + str(k["cena"]) + "\t" + str(k["kolicina"]) +
"\t" + str(k["godina"]))
dodaj_knjigu({'naslov': 'Novi', 'kolicina': 12.0, 'godina': 2016,
'izdavac': 'Novi Izdavac', 'autori': 'Novi Novic',
'cena': 123.23})
ispisi_sve_knjige("knjige.data")
id naslov autori izdavac cena kolicina godina
-------------------------------------------------------------------
1 SICP Sussman I1 12.0 12.0 1979.0
2 SICP Sussman I1 12.0 12.0 1979.0
3 Novi Novi Novic Novi Izdavac 123.23 12.0 2016.0
S obzirom da ovde knjiga nema eksplicitan id već je on
predstavljen indeksom u listi to znači da ne možemo znati da li su
SICP i SICP jedna te ista knjiga i zato je moguće da se u
spisku knjiga nađe knjiga koja se zove SICP više puta.
Ako želimo da rešimo ovaj problem onda moramo napraviti funkciju
dodaj_knjigu takvu da prima knjigu koja eksplicitno sadrži
id . To stvara novi zadatak — potrebno je voditi računa da se u
našem spisku knjiga ne nađu dve sa istim id .
10 Dodatak
10.1 Rekurzija
Rekurzija je kada neki pojam definišemo koristeći sam pojam.
U programskim jezicima rekurzija se može postići na nivou funkcija:
def reci_ciao():
print("Ciao!")
reci_ciao()
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in reci_ciao
File "<stdin>", line 3, in reci_ciao
File "<stdin>", line 3, in reci_ciao
File "<stdin>", line 3, in reci_ciao
File "<stdin>", line 3, in reci_ciao
File "<stdin>", line 3, in reci_ciao
File "<stdin>", line 3, in reci_ciao
...
RuntimeError: maximum recursion depth exceeded while calling a Python object
Računari su konačne prirode pa ne mogu (tek tako) izraziti nešto
što je beskonačno, a poziv funkcije reci_ciao je beskonačan.
Kako bi se rekurzija nekada završila moramo joj dati uslov završetka:
def reci_ciao(p):
# ovo je uslov završetka
if p < 10:
print("Ciao!")
reci_ciao(p + 1)
else:
return
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
10.1.1 Rekurzija kao imperativna petlja
Rekurzija se često može napisati kao imperativna petlja:
def reci_ciao(p):
for i in range(p, 10):
print("Ciao!")
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Ciao!
Imperativna petlja troši konstantnu količinu
memorije. Neoptimizovana rekurzija troši novu memoriju pri svakom
pozivu, dakle — više ulazaka u funkciju (poziva) više memorije
potrošeno.
Rekurzija u Python-u je neoptimizovana (u svojoj osnovnoj
verziji) ali to nije situacija sa svim programskim jezicima.
10.2 Python modularizacija
Svi netrivijalni Python programi su podeljeni u delove.
10.2.1 Moduli
Svaki Python file je ujedno i modul. Svaki modul bi trebao da
sadrži kod koji čini neku veću logičku celinu.
Ime svakog modula odgovara imenu fajla bez ekstenzije py . Dakle,
ako imamo fajl prijava.py onda se modul zove prijava .
Svaki modul ima ime __main__ ako je pokrenut direktno kao
skripta:
U svakom fajlu možete doći do imena njegovog modula preko globalne
varijable __name__ :
print("Ime ovog modula je: " + __name__)
Ime ovog modula je: __main__
… zato što je ovaj modul pokrenut direktno kao skripta.
10.2.2 Paketi
Svaki direktorijum u strukturi Python projekta može biti paket
ako sadrži prazan fajl sa nazivom __init__.py .
Subpaketi(podpaketi) nekog modula su takođe direktorijumi koji sadrže prazan
__init__.py fajl.
projekat/ Top-level paket
__init__.py Inicijalizator top-level paketa
prodavnica.py
formatiranje/ Subpaket za formatiranje
__init__.py
tabela.py
ascii_slika.py
...
prijava/ Subpaket za proijavu
__init__.py
admin.py
ostali.py
...
Sadržaj fajla projekat/prijava/admin.py je:
def prijavi_se(u_name, pasw):
return "Korisnik " + u_name + ", " + pasw + " se prijavljuje."
Ako želimo da koristimo funkciju koja je definisana u
projekat/prijava/admin.py iz projekat/prodavnica.py onda u
projekat/prodavnica.py treba da stoji sledeće:
import prijava.admin
prijava.admin.prijavi_se("pera", "peric")
>>> 'Korisnik pera, peric se prijavljuje.'
Ovakvo ime funkcije, koje u sebi sadrži potpunu informaciju o tome
gde je tačno funkcija definisana se zove fully qualified
name. Možemo to prevesti sa puno ime funkcije, za funkciju
iznad puno ime je:
Ili, ako želite da modul za prijavljivanje administratora zovete
a_prijava :
import prijava.admin as a_prijava
a_prijava.prijavi_se("pera", "peric")
>>> 'Korisnik pera, peric se prijavljuje.'
a_prijava se još naziva i alias modula.
Možete uključiti funkciju i bez ikakvog aliasa ili punog imena
koristeći sledeću konstrukciju:
from putanja.do.modula import funkcija
from prijava.admin import prijavi_se
prijavi_se("pera", "peric")
>>> 'Korisnik pera, peric se prijavljuje.'
... >>> Neki potpuno bespotreban print.
I ako njega uključimo da bismo koristili njegovu funkciju
prijavi_se pri tome će nam se ispisati i bespotreban tekst!
import prijava.admin_pogresan
prijava.admin_pogresan.prijavi_se("pera", "peric")
Neki potpuno bespotreban print.
'Korisnik pera, peric se prijavljuje'
10.2.3 Primena modula i paketa
Python fajl se često piše tako da se može koristiti i direktno
kao skripta i tako što će biti uključen kao modul.
Za onaj kod koji treba biti izvršen samo kada se fajl pokreće
direktno kao skripta koristi se sledeći idiom:
if __name__ == '__main__':
# kod koji se izvršava kada je fajl pokrenut kao skripta
print("Pokrenut kao skripta")
Pretpostavimo da imamo fajl prikaz.py i da ga pokrećemo kao
skriptu:
# fajl prikaz.py
def javi_se():
return "Dobar dan, ja sam modul prikaz"
def za_direktno():
print("Pokrenut sam direktno kao skripta!")
def pozdravi_se():
return "Doviđenja, ja sam modul prikaz"
if __name__ == '__main__':
za_direktno()
>>> ... ... >>> ... ... >>> ... ... >>> ... ... Pokrenut sam direktno kao skripta!
Taj modul takođe možemo uključiti sa import i pri tome se neće
ispisati ništa.
10.3 lambda funkcije
Lambda funkcije potiču iz formalnog sistema u matematičkoj logici
koji se zove lambda račun. Taj sistem je uveo još Alonzo Črč
početkom 30-tih godina prošlog veka. U programske jezike je uveden
kroz Lisp sredinom 50-tih godina prošlog veka.
Dakle, stvar je prilično stara (za istoriju računarstva) iako se iz
nekog čudnog razloga danas smatra novinom u programskim jezicima
koji je naknadno uvode.
10.3.1 Šta je to?
Lambda funkcije zovemo još i neimenovanim jer nemaju ime po kome
bismo mogli naknadno da ih identifikujemo.
Primer jedne imenovane, "obične" funkcije:
Poziv imenovane funkcije:
13
Korišćenjem lambda izraza istu ovu funkciju možemo definisati na
sledeći način:
inc_prim = lambda x: x + 1
I pozivati je na potpuno uobičajen način:
13
Dakle, lambda izraz ima sledeću formulaciju:
lambda param1, param2, param3 ... : izraz
Gde će rezultat izraz -a biti vraćen kao rezultat izvršavanja
čitave lambda funkcije.
Na primer izraz x^2 + 3*x + 2 možemo zapisati:
lambda x : x**2 + 3 * x + 2
<function <lambda> at 0x7f6de72afae8>
Međutim ovde lambda izraz nismo vezali ni za kakvo ime pa se ne
možemo kasnije referisati na njega.
Ako želimo da definišemo funkciju i na istom mestu joj prosledimo
parametre i pozovemo je to možemo uraditi na sledeći način:
(lambda x : x**2 + 3 * x + 2)(2)
12
10.3.2 Funkcije višeg reda
Funkcije višeg reda (Higher-order functions) su one funkcije koje
ispunjavaju barem jedan od uslova:
- Uzimaju jednu ili više funkcija za argumente
- Vraćaju funkciju kao rezultat
- Neke funkcije višeg reda
Neki standardni problemi u Python-u se idiomatski rešavaju
korišćenjem funkcija višeg reda.
Sortiranje kolekcija:
k = [{'ime': "Bananica", 'kalorije': 128},
{'ime': "Jaffa keks", 'kalorije': 178},
{'ime': "Munchmallow", 'kalorije': 104},
{'ime': "Plazma keks",'kalorije': 202}]
sorted(k, key=lambda x: x['kalorije'])
[{'kalorije': 104, 'ime': 'Munchmallow'}, {'kalorije': 128, 'ime': 'Bananica'}, {'kalorije': 178, 'ime': 'Jaffa keks'}, {'kalorije': 202, 'ime': 'Plazma keks'}]
[napomena]
Svakoj funkciji koja prima neku drugu funkciju kao
parametar možete proslediti i imenovanu ("običnu") funkciju.
def sort_funkcija(x):
return x['kalorije']
sorted(k, key=sort_funkcija)
[{'kalorije': 104, 'ime': 'Munchmallow'}, {'kalorije': 128, 'ime': 'Bananica'}, {'kalorije': 178, 'ime': 'Jaffa keks'}, {'kalorije': 202, 'ime': 'Plazma keks'}]
Razlog zbog koga se u funkcijama višeg reda češće koriste
lambda izrazi je zato što se funkcije koje se prosleđuju kao
parametri obično neće više nigde koristiti pa nema ni potrebe
da im dajemo ime.
Filtriranje kolekcija:
Želimo da dobijemo samo one slatkiše koji imaju više od 110 kalorija:
filter(lambda x: x['kalorije'] > 110, k)
<filter object at 0x7f6de71ff828>
O! Ne! Šta je ovo?! Gde je lista?!
filter funkcija vraća lenju sekvencu kao što npr. radi
range koju smo spominjali ranije. Da bismo dobili evaluiranu
(već formiranu) listu od lenje sekvence možemo je naterati da
se pretvori u listu korišćenjem list funkcije:
list(filter(lambda x: x['kalorije'] > 110, k))
[{'kalorije': 128, 'ime': 'Bananica'}, {'kalorije': 178, 'ime': 'Jaffa keks'}, {'kalorije': 202, 'ime': 'Plazma keks'}]
Map funkcija
map funkcija radi nešto slično kao list comprehensions koji
smo pominjali ranije samo što je funkcija višeg reda i što
vraća lenju sekvencu.
map(lambda x: x**2, [1, 2, 3])
<map object at 0x7f6de72040b8>
list(map(lambda x: x**2, [1, 2, 3]))
[1, 4, 9]
list(map(lambda x: x**2, nums)) == [x**2 for x in nums]
True
11 Korisne biblioteke
Da biste instalirali nove Python biblioteke potrebno je da
prethodno na Vašem sistemu imate alat koji to ume da radi. Standard
u Python-u je pip . Ako ste instalirali Python na neki od
standardnih načina onda pip već imate instaliran, potrebno je samo
da ga upgrade-ujete.
11.1 tabulate
Instalacija:
Korišćenje:
from tabulate import tabulate
headers = [["prvo", "drugo", "treće"]]
tabela = [[11, 12, 13], [21, 22, 23], [31, 32, 33]]
-- -- --
11 12 13
21 22 23
31 32 33
-- -- --
print(tabulate(headers + tabela, headers='firstrow'))
prvo drugo treće
------ ------- -------
11 12 13
21 22 23
31 32 33
print(tabulate(headers + tabela, headers='firstrow', tablefmt='grid'))
+--------+---------+---------+
| prvo | drugo | treće |
+========+=========+=========+
| 11 | 12 | 13 |
+--------+---------+---------+
| 21 | 22 | 23 |
+--------+---------+---------+
| 31 | 32 | 33 |
+--------+---------+---------+
Author: Novak Boškov
Created: 2016-12-14 сре 12:46
|
|