Operatori

7.1 Operatori 

Ajde, neću te mnogo daviti sa njima... Brzinski ćemo „preleteti“ kroz razne vrste operatera i njihove upotrebe.
Pokreni interaktivni prompt, i svaki primer izvežbaj, na taj način što ćeš zamisliti neke svoje brojeve. Što više vežbaš, to će ti lakše „ući u prste“. 
Pa da krenemo:

Sabiranje – znak: + (plus) 

Kada se radi sa brojevima, onda vraća rezultat sabiranja ta dva broja, kada se radi sa stringovima, koncentriše ih u jedan string:
>>> 1 + 1 
2 
>>> 3 + 9 
12 
>>> 0.5 + 12.8 
13.3 
>>> 'a' + 'b' + ' c' 
'ab c' 
>>> 'a' + 1 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly
>>> 
Vidimo da ne možemo sabrati dva objekta različitog tipa (u primeru broj i string).

Oduzimanje – znak: - (minus)

Oduzima jedan broj od drugog i vraća nam broj koji je rezultat.
>>> 5 - 2 
3 
>>> 56 -89 
-33 
>>> 5.36 - 20.68 
-15.32 
>>> 2 - 5 
-3 
>>> 'a' - 'b' 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'str'
>>> 
Vidimo da, iako se mogu „sabirati“, stringovi ne mogu oduzimati.
Ako nismo „prosledili“ prvi broj, Python pretpostavlja da je on nula:
>>> -59 
-59 
>>> -32.369999 
-32.369999 
>>> 

Množenje – znak * (puta)

Vraća rezultat množenja dva broja, ili vraća string ponovljen dat broj puta.
>>> 2 * 3 
6 
>>> 4598989 * 89895655456 
413429130589933984 
>>> 458.589 * -1 
-458.589 
>>> 'trolololo' * 15 
'trolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololotrolololo' 
>>> 2 * ' trolololo ' 
' trolololo  trolololo ' 
>>> 't' * 'k' 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'str'
>>> 
Očigledno se dva stringa međusobno ne mogu množiti.

Stepenovanje – znak ** (stepen)

Vraća prvi broj stepenovan sa drugim brojem. Ukoliko ne znate matematiku: a ** 2 = a * a i a **3 = a * a * a 
>>> 2 ** 3 
8 
>>> 36.25 ** 0.5 
6.020797289396148 
>>> 36 ** 0.5 
6.0 
>>> 158 ** 14 
6042257331792746762298544635904 
>>> -15 ** 3 
-3375 
>>> 'a' ** 3 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
>>> 
Primeti da, iako stringovi podržavaju množenje sa brojem, ne podržavaju stepenovanje (jer Python ne podržava množenje stringa sa stringom).

Deljenje – znak / (podeljeno)

Vraća rezultat deljenja prvog broja sa drugim.
>>> 9 / 3 
3.0 
>>> 6 / 4 
1.5 
>>> -5 / -1 
5.0 
>>> -5 / 2 
-2.5 
>>> 'a' / 'a'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'str'
>>> 'a' / 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'int'
>>> 
Obrati pažnju na dve stvari. Prva je da nam deljenje uvek vraća broj sa decimalnim zarezom (float), a druga je da se stringovi ne mogu deliti ni sa čim.

Celobrojni rezultat deljenja – znak // (dupla kosa crta)

Vraća nam ceo broj rezultata deljenja, primeri će pokazati šta je to:
>>> 4 // 3 
1 
>>> 5 // 5 
1 
>>> 5 // 50 
0 
>>> 48 // 13 
3 
Primeri jasno govore, da nam ova operacija vraća rezultat koji je isti kao da smo od operacije deljenja dobili neki broj i zaokružili ga na ceo (jednostavno, kao da smo obrisali zarez, i sve što ide iza njega). Ali, da li je naše opažanje ispravno?
>>> -6 // 2 
-3 
>>> -6 // 4 
-2 
>>> 6 // 4 
1 
>>> -6 / 4 
-1.5 
>>> 6 / 4 
1.5 
>>> -15 // 4 
-4 
>>> 
Šta je ovo, dođavola?!?
Jednostavno, naša logika prilikom našeg opažanja nije bila ispravna. Hajde da se vratimo na definiciju ove operacije – ona vraća ceo broj rezultata podele. Ako 15 delimo sa 4, gledajući iz „obrnute perspektive“, celobrojna vrednost je 3, pa imamo 3 * 4 = 12, i ostane nam 3 (do 15). Znači to je ceo broj kojim množimo naš broj sa desne strane, da bi smo dobili manji broj od onoga sa leve strane!
Pa ako obrnemo primer, tj ako delimo -15 sa 4, gornjom logikom bi to opet bio broj -3, ali -3 * 4 = -12, a -12 je veće od -15! A to kao što vidimo, nije dozvoljeno, jer nama treba manji broj, tj, biće -4, onako kako nam je i Python „vratio“. A evo i zašto: -4 * 4 je -16 (što je manje od -15) a ostatak je 1 (-16 + 1 = -15)!
Uradi više primera da bi shvatio ovo bolje, a kad sam već spomenuo ostatak, evo ga i on:

Ostatak podele dva broja – znak % (modulo)

Vraća nam ostatak od podele dva broja.
Opet ista priča važi i za njega, čisto da se ne iznenadiš prilikom računanja sa negativnim brojevima (ostatak od 15 podeljeno sa 3 je 3, a ostatak od -15 podeljeno sa 3 je – 1, gledajući u predhodan primer)
>>> 58 % 25 
8 
>>> 5 % 100 
5 
>>> 0 % 12 
0 
>>> -45 % 58 
13 
>>> 45 % 58 
45 
>>> -15 % -4 
-3 
>>> -15 % 4 
1 
>>> 15 % 4 
3 
>>> 
I, na kraju ovih „matematičkih“ operacija, obrati pažnju na 0 (nulu)!
>>> 2 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 2 // 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
>>> 2 % 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
>>> 
Deljenje sa nulom – nije moguće.
Za razliku od ove grane matematike koja se naziva aritmetika (i koju srećeš u svakodnevnom životu), u programiranju je jednako važna (ako ne i mnogo važnija) jedna druga grana – matematička logika!
Da se podsetimo... Naša logika se zasniva na pretpostavkama da li je nešto tačno ili ne. Ako je nešto tačno radimo ovo, netačno, radimo nešto drugo. Ako kažem „Pera i Žika su juče u 2 sata rasklapali bicikl.“, to je laž ako je Žika bio kod Mileve na kafi u to vreme. Ili „Hoćeš da ti kupim čips, ili ćeš čokoladu?“ - Briši od mene, nemam zube za čips, a od čokolade imam probavne probleme (a ako si uporan, pokušaj da nađeš šta me zanima)!
Budući da postoje samo dve vrednosti – tačno i netačno, što ih ne bi smo uprostili? Može 1 i 0? Jel to samo računar razume? Da, cela logika je „laganica“... Ostadoše samo logičke operacije, ali gle čuda... Jedan čika sa prezimenom Bul (George Bool) je razrešio tu „glavolomku“ davno pre pojave računara, pa se po njemu, cela grana matematike koja se bavi logikom naziva – Bulova algebra.
Možda ti zastrašujuće zvuči, pa nemoj da se iznenadiš što nisi u pravu – ona je prosta, da prostija ne može biti! Ali za početak, kao mali uvod u ovu algebru, potrebno nam je naše obično znanje iz – upoređivanja vrednosti! U životu, ako kažem da imam manju platu od tebe, to može biti istina (ja imam 20.000, a ti 21.000) ili laž (nisam ti rekao da dobijam još 100 eura na ruke?). Tako isto i Python posmatra stvari.... Pa da vidimo operacije koje nazivamo komparatori.

Manje od – znak < (manje)

Proverava da li je prva vrednost manja od druge. Vraća nam novu vrednosti True (istina, tačno je) ili False (netačno, pogrešno, laž). Obrati pažnju na velika slova prilikom imenovanja ovih vrednosti.
>>> 2 < 5 
True 
>>> 15 < 1.23 
False 
>>> 15 < 'a' 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < str()
>>> 'A' < 'a' 
True 
>>> 
Ovde vidiš nešto novo. True je vrednost koju Python smatra za istinitu tvrdnju, False je obrnuto, znači da Python smatra da to nije tačno (nije istina). Kako smo rekli da kompjuteri razumeju samo brojeve 0 i 1, možeš smatrati da je vrednost False jednostavno drugačije napisan broj 0, a vrednost True je, u stvari, drugačije napisan broj 1.
Poređenja ne moramo raditi striktno sa dve vrednosti:
>>> 5 < 10 < 100 
True 
>>> 2.45 < 5.789 < 6.369 
True 
>>> 2.45 < 5.789 < 6.369 < 1.0 
False 
>>> 'a' < 'b' < 'c' < 'd' 
True 
>>> 'a' < 'b' < 'c' < 'd' < 'A' 
False 
>>> 
Obrati pažnju da možemo da poredimo slova i stringove. Kao što sam ti rekao, u računaru je sve predstavljeno pomoću brojeva, tako su i slova. Velika slova imaju manju vrednost od malih slova, i kako idemo abecednim redom, tako im i njihova vrednost raste.
>>> 'anadolija' < 'srbija' 
True 
>>> 'šećer' < 'srbija' 
False 
>>> 'šećer' < 1 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() < int()
>>> 'šećer' < '1' 
False 
>>> 
Vidimo da ne možemo porediti objekte koji nisu istog tipa, tako ne možemo porediti broj sa stringom!

Veće od – znak > (veće)

Proverava da li je prva vrednost veća od druge. Vraća nam vrednost True ili False.
>>> 12 > 11.999999999 
True 
>>> 12 > 12 > 12 
False 
>>> 'a' > "Š" > 'Č' 
False 
>>> "Š" > 'Č' 
True 
>>> 
Uh... Čekaj... Zar nisi rekao da su slova poređana tako da veća imaju manju vrednost od malih? Zar onda 'a' > 'Š'  > 'Č' ne bi trebalo da je True?
Zapravo ne. Jer postoji jedna začkoljica, koju saam ti već napomenuo. Veća slova imaju manju vrednost od malih, kada su u ASCII formatu, a to znači, da to važi za sva slova koja se nalaze u engleskom alfabetu. Ukoliko koristimo slova i oznake koji su „van“ engleskog alfabeta, treba imati na umu da se ta slova predstavljaju kroz takozvane Unikod table. U Unikod tabli, oznake koje su „dodate“ se nalaze iza (tj. imaju veću vrednost) od postojećih iz ASCII-ja. Slovo 'Š' ne postoji u engleskom jeziku, znači da je dodato na nekom mestu iza svih „rezervisanih“ slova, zato ima veću vrednost od malog slova 'a' koje – postoji u engleskom jeziku.

Manje ili jednako  - znak <= (manje ili jednako)

Poredi da li je prva vrednost manja ili jednaka drugoj vrednosti.
>>> 1 <= 1 <= 2 <= 2 <= 2.158 
True 
>>> 1 <= 1.0001 
True 
>>> 2 <= 1.0001 
False 
>>> "a" <= "a" 
True 
>>> 

Veće ili jednako – znak >= (veće ili jednako) 

Poredi da li je prva vrednost veća ili jednaka drugoj vrednosti.
>>> 'a' >= 'a' >= 'B' 
True 
>>> 1 >= 1/3 >= 1/6 
True 
>>> 1 >= 2 
False 
>>> 
Iako važni, ovi operatori komparacije se mnogo manje upotrebljavaju od sledeća dva, koja su sastavni deo gotovo svakog programa na koji ćeš naleteti. Hajde da i njih upoznamo, a zaključak zašto su oni toliko važni ćeš izvući znatno kasnije.

Provera jednakosti – znak == (dva znaka = , značenje: da li je jednako?) 

Poredi da li je vrednost sa leve strane jednaka vrednosti sa desne.
>>> 1 == 1 
True 
>>> 1 == '1' 
False 
>>> 1 == 1 == 2 
False 
>>> 'a' == 'A' 
False 
>>> 'mana' == 'mana' 
True 
>>> 'mana' == 'Mana' 
False 
>>> 'mana' == True 
False 
>>> 1 == True 
True 
>>> 0 == False 
True 
>>> 
Opa... Sada imamo i potvrdu da je vrednost 1 jednaka vrednosti True, i vrednost 0 vrednosti False!
Proučavaj malo ove primere, i izmisli neke svoje, da bi ti ovo bilo jasnije.
Jedna stvar, koja može da predstavlja problem je – nemoj da mešaš znak za proveru jednakosti, koji se piše kao dva znaka jednako (==) sa jednim znakom jednako, koji je znak dodele vrednosti promenljivoj! Vežbaj malo, evo za primer:
>>> 1 == 1 
True 
>>> 1 = 1 
  File "<stdin>", line 1
SyntaxError: can't assign to literal
>>> a = 1 
>>> 
Prvo je znak komparacije i znači – da li je broj 1 jednak broju 1? I, dobili smo True (jeste, istina je...).
Drugo je znak dodele i znači: dodeli vrednost broja 1 promenljivoj sa imenom 1. Ups.... Ime 1 nije legalno ime za promenljivu! GREŠKA!!!!!
I sledeće je dodela vrednosti broja 1 promenljivoj koja nosi ime a.
Da se uvežbaš, uradi što više primera na ovu foru:
>>> a = 'a' 
>>> b = 'b' 
>>> a == b 
False 
>>> b = 'a' 
>>> b == a 
True 
>>> a = 'b' 
>>> a == b 
False 
>>> 
Vidiš li poentu?
E sad, i jedna zanimljivost. Sećaš li se da sam ti rekao da računari ne greše? Ovo je jedno mesto na kom ta tvrdnja „ne drži vodu“:
>>> (2 ** 0.5) * (2 ** 0.5) == 2 
False 
>>> 
Ako se još nisi izveštio sa matematičkim operacijama, ovo prethodno je provera dal' je istina da ako pomnožimo dva kvadratna korena broja 2 dobijamo sam taj broj 2? Znajući matematiku to je uvek istina, ali zar ovo znači da Python ne zna matematiku?
Hajde da ne „testiramo“ već da vidimo rezultat, pa da vidimo „đe je, ba, zapelo“:
>>> (2 ** 0.5) * (2 ** 0.5) 
2.0000000000000004 
>>> 
Uh? Šta je bre ovo?
Ništa.... Treba da znaš, kao što ljudi zaokružuju decimalne brojeve, tako isto rade i računari. Zbog toga, računanje pri kom se upotrebljavaju decimalni brojevi nikada ne može biti savršeno tačno. Da se ne bi razočarao, kako su računari glupi, obrati pažnju na „tipično“ ljudsku grešku pri ovom zadatku:
>>> (2 ** 0.5) 
1.4142135623730951 
>>> 1.41 * 1.41 
1.9880999999999998 
>>> 
Po nekom nepisanom pravilu, mi ljudi volimo da zaokružujemo na dve decimale. Ni naše računanje nas nije dovelo ništa bliže tačnom rešenju, pa zato, nemoj se srditi na mašinu.
Pa to znači da sve ovo što učim i radim pada u vodu? Pa i ja mogu da grešim dok radim, šta će mi onda računar?
Razmišljaj pametno! „Mudra“ provera tačnosti, pri korišćenju decimalnih brojeva bi izgledala, kao npr ovo:
>>> a = (2 ** 0.5) * (2 ** 0.5) 
>>> -0.00001 <= a - 2 <= 0.000001 
True 
>>> 
Šta je bre ovo?
Jednostavno, izračunali smo traženu vrednost, za koju znamo da mora biti broj 2. Zatim smo od te vrednosti oduzeli taj broj 2. Po logici stvari, treba da dobijemo broj 0. Budući da znamo da postoji greška, znamo da nismo dobili 0, pa umesto da proveravamo da li smo dobili broj koji je jednak 0, mi proveravamo da li je broj manji ili jednak nekoj matematičkoj greški, koja je dovoljno blizu broju 0, tako da ni ne utiče na rezultat. Greška može biti i na „suprotnoj strani“ broja 0 (tj može biti negativna), pa smo zato postavili i gornju, ali i donju granicu.
I, P.S. Ne vezano za temu, ali vezano za način razmišljanja prilikom programiranja – ovakav način račiunanja, gde se neka vrednost „navlači“ u neke očekivane granice se naziva normalizacija. Ona je bitna samo sa naše (ljudske) perspektive. Na primer, možemo napisati da nešto košta 236 centi. To za ljude nije baš „normalan“ način prikaza, jer čovek očekuje da mu cena bude napisana kao 2 eura i 36 centi. Računaru je, sa druge strane, sve jedno kako je napisano, i baš ga boli uvo što ti ne očekuješ ono što ti on daje. Mudri programeri „normalizuju“ vrednosti, kako ih ne bi sačekalo neprijatno iznenađenje (što od korisnika, koji su nezadovoljni, što od računara koji pogrešno računa decimale....).
No, vreme je da se vratim na temu, sledeći komparator, gotovo iste važnosti kao i provera jednakosti, je:

Provera nejednakosti – znak != (nije jednako) 

Poredi vrednosti i vraća True, ukoliko objekti nisu jednakih vrednost:
>>> "baba" != "deda" 
True 
>>> 1 != 2 
True 
>>> 1 != "2" 
True 
>>> 
Obrati pažnju da čak i objekti koji nisu istog tipa mogu da se „porede“, i naravno – nisu jednaki.
Pošto su ti komparatori stvorili prilično jasnu sliku šta predstavljaju te čudne vrednosti True i False, napokon možemo da se „bacimo“ na matematičku logiku. Da se podsetimo, ona nam služi da shvatimo da li je nešto istina ili laž, tačno ili netačno, 1 ili 0, ljubav ili mržnja, imam ili nemam itd itd... Znači da, od ovih operatora očekujemo da nam daju prost odgovor – True ili False.
Prvi komparator koji želim da ti objasnim je jednostavan – uzima jednu vrednost i – vraća nam ono što ta vrednost nije... 'Ajmo...

Bulovo Ne – znak not (not)

Vraća suprotnu logičku vrednost od one koja se proverava, ako proveravamo True, vraća False, ako proveravamo False, vraća True.
>>> x = True 
>>> not x 
False 
>>> x = False 
>>> not x 
True 
>>> not True 
False 
>>> not False 
True 
>>> 
Na ovom mestu se nadam da si se zapitao nešto što nisam pomenuo. Šta je logička vrednost? Pokazao sam ti kako se logička vrednost može dobiti komparacijom, ali razmisli o ovome – koja je logička vrednost rečenice : „Moj automobil je žut.“? Jel to istina ili laž? Kako ti to možeš znati? Zapravo, ne možeš! Moraš se osloniti na svoja čula, tj moraš da pogledaš u moj automobil, da proveriš boju... I, jesi li video? Da li te lažem ili govorim istinu? Opet ne znaš? Ah... Ne znaš koji je moj automobil.... Parkiran je negde u tami... Eno onaj tamo... Mrak je pa ne vidiš boju? Ajde da ti kažem – ja nemam automobil... Znači posle neke provere ti znaš da sam te slagao sa svojom izjavom. 
Posle ovog šlagvorta, ostaje pitanje – a koja su to Pythonova čula? Kako on zna šta je šta? Moram te razočarati – računar ne zna šta je šta, ako mu mi to ne kažemo, ali šta je sledeće što sam napisao gore? Napisao sam „...posle neke provere...“, što nas dovodi do nekog dubljeg razmišljanja: posle kakve provere Python zaključuje šta je istinito, a šta je pogrešno?
Ajde, kada znamo da upotrebljavamo Bulovo NE da proverimo:
>>> not "abrakadabra" 
False 
>>> not "" 
True 
>>> not " " 
False 
>>> not 2 
False 
>>> not 0 
True 
>>> 
Obrati pažnju! Kada smo Python-u zadali da nam da suprotnu logičku vrednost od nekog stringa, vratio nam je – False, što znači da je istinita vrednost stringa True!
Kada smo mu zadali prazan string (znakove navoda između kojih nema ništa), on nam je vratio True, što će reći da „prazan string“ on posmatra kao False!
No, kada smo mu prosledili za nas prazan string (samo znak razmaka na tastaturi, takozvani spejs), on nam je vratio False, tj taj „prazan string“ Python posmatra kao True! E, sad, ovaj „prazan string“ baš i nije „prazan“, u njemu postoji znak razmaka, koji mi ne vidimo, ali Python ga smatra znakom, kao i bilo koje drugo slovo! Znači, ovaj string za Python nije prazan! Onaj prethodni string jeste prazan, kako nama, tako i Python-u, jer u njemu nema nikakvih znakova.
Dalje razmišljajući shvatamo da Python sve što ima neku vrednost smatra True, dok sve one stvari koje nemaju nikakvu vrednost (npr. prazan string) smatra False! I to je to! Jedina provera logičke vrednosti ičega u Pythonu je postoji – nepostoji! (Ukoliko naravno, objekat ne poseduje neku svoju istinitu vrednost, ali to je izvan domena ovog dela tutorijala, tako da komotno možeš da zaboraviš da si ikada pročitao ovo u zagradi...)
Ali, šta je u primeru sa brojem 0? Pa to je broj! Pa ima neku svoju vrednost, pobogu! Tu je... Nisam slep!
Upravo to i govorim, rekli smo da je False, u stvari, samo drugačije napisan broj 0. Ali, sa stanovišta broja 0, kažemo da on ima svoju logičku vrednost False, i on je jedini broj koji će te iznenaditi, ukoliko ne paziš!

Bulovo I – znak and (and)

Bulovo I je prvi od dve „komplikovane“ operacije matematičke logike. Svoje „duboko“ značenje ima u samom jeziku kojim govorimo – Bulovo I ima isto značenje kao što ima i veznik „i“ u našem jeziku. Kada kažem: „Daj mi čekić i ekser.“ a ti mi daš samo čekić, nije teško shvatiti da će taj čekić završiti na tvojoj glavi! Ako kažem „Ona je bila ljubav mog života i oduzimala mi je dah“ - lažem – jer ne postoji način da neko nekom oduzima dah (ukoliko nije reč o krivičnom delu davljenja i ovo nije deo iskaza sudiji za prekršaje). A ako kažem „Ja sam napisao ovaj tuorijal i ti ga čitaš“ rečenica je tačna, jer ja JESAM napisao, i ti ga upravo sada, čitaš.
Obrati pažnju na logiku – kada su dve proste rečenice povezane sa slovom i, ceo iskaz je tačan jedino ako su OBE rečenice tačne. U suprotnom – to je neistina, laž, netačno...
Ista logika je i u Python-u, ukoliko obe vrednosti imaju logičku vrednost True, onda dobijamo True, u suprotnom ćemo dobiti uvek False!
Da proverimo mi to....
>>> True and True 
True 
>>> True and False 
False 
>>> False and True 
False 
>>> False and False 
False 
>>> 
A da vidimo sa nekim vrednostima?
>>> 1 and 2 
2 
>>> "a" and "babac" 
'babac' 
>>> "a" and False 
False 
>>> "a" and '' 
'' 
>>> 
Čekaj.... Šta je sad pa ovo?
Objašnjenje je jednostavno: Pošto je, po definiciji, vrednost izraza uvek False kada je prva vrednost False, Python se ni ne trudi da proverava drugu vrednost (nije to znak lenjosti, već je više pitanje – a što bi, kada će ionako iovako rezultat biti False?). To se naziva „logički kratak spoj“. U stvarnosti, kada slušate nekoga, kada kaže jednu laž, ako ste dovoljno inteligentni, ne trudite se da ga slušate dalje (samo trošite svoje vreme).
A, pogledajmo suprotno... Ako je prva vrednost True? Pa, gledajući definiciju – vrednost ovog izraza u tom slučaju je uvek vrednost drugog prosleđenog podatka! Zato je sve što Python radi prilikom logičke operacije I da proveri prvi operand – ako je on False, vraća False, a ako je on True – onda vraća drugi operand!
Budući da u ovim primerima imamo neku vrednost (što broj, što string), a kada postoji neka vrednost – onda je to za Python logička vrednost True, on nam samo „vrati“ drugu vrednost!
Zapetljano? Zapravo, i nije, ako to lagano predstavimo ovako:
>>> x = 'x' 
>>> x and x 
'x' 
>>> x and True 
True 
>>> True and x 
'x' 
>>> x and False 
False 
>>> False and x 
False 
>>> 
Ako je ovo jasno, idemo dalje....

Bulovo ILI – znak or (or)

Ako pratimo istu logiku, kao kod Bulovog I, Bulovo ILI je ekvivalent našem jezičkom vezniku „ili“. Tako, na primer, ako kažem „kasnim zato što sam išao na kupanje ili sam trošio svojih milion dolara u kazinu“ ti 100% znaš da lažem, jer odajem neprijatan miris, a Kazina nema u okolnih 150 km! „Daj mi hleb ili pogaču“ - evo ti obe stvari, pa ti biraj, jer si zadovoljan u svakom slučaju!
I ovde obrati pažnju na logiku. Rečenica će biti lažna jedino u slučaju kada su sve činjenice u njoj laž, a biće istinita u svim ostalim slučajevima. Tako na primer rečenica : „Sada trošim svojih milion dolara ili pišem Python tutorijal“ je tačna – jer pišem Python tutorijal, iako nemam milion dolara!
Da proverimo to u interaktivnom promptu:
>>> True or True 
True 
>>> True or False 
True 
>>> False or True 
True 
>>> False or False 
False 
>>> 
Ali, kako stvari stoje sa podacima?
>>> 'a' or 'ahgjh' 
'a' 
>>> 0 or 1 
1 
>>> 'kanda' or False 
'kanda' 
>>> 
Opa... Sličan zaključak ide kao i za Bulovo I. Budući da Bulovo ILI može biti False jedino u slučaju kada su oba operanda False, Python samo pogleda prvi operand, ako je on True, vraća njega, ako nije, onda vraća drugi operand. I ovo je verzija „kratkog spoja“ logike (zašto trošiti vreme na nešto, za šta znam da je tačno? - ovo se u životu primenjuje kod „brzog čitanja“, tehnike koju praktikuju ljudi koji rade sa ogromnom količinom dokumentacije).
Da bi bilo jasnije:
>>> x = 'x' 
>>> x or True 
'x' 
>>> True or x 
True 
>>> x or False 
'x' 
>>> False or x 
'x' 
>>> x or x 
'x' 
>>> 
Ovo bi bili svi operatori Bulove algebre koje nam Python daje.....
Napokon......
…. da mi ne pričamo o programiranju, i računarima. Šta napokon? Pa sad ću malko da ti „promućkam“ razmišljanje u svakom smeru...
Budući da računari rade sa brojevima koji su pretstavljeni kao binarne cifre u memoriji računara, logika je da se i nad tim binarnim ciframa može raditi Bulova algebra.
Ako ti nije jasno kako je broj predstavljen u memoriji računara, probaj ovo:
>>> p = '{:b}' 
>>> p.format(12) 
'1100' 
>>> p.format(23568) 
'101110000010000' 
>>> p.format(1248654385654341354765463) 
'100001000011010011011000010011100000000100010011101110100000000011011110010010111'
U ovom primeru sam koristio jednostavno formatiranje stringova. „Šablon“ formatiranja može da ima u sebi oznaku b, koja, ako je za to mesto prosleđen neki broj, taj broj predstavlja u binarnom obliku (onako kako ga računar „vidi“).
Zatim sam prosledio par brojeva da ih osmotrim, kako oni u stvari izgledaju.
Dobio sam ono što sam i očekivao – samo skup 0 i 1 koji u određenom rasporedu grade logičku celinu koja predstavlja prosleđen broj. Budući da su to 0 i 1 ili, drugim rečima False i True, zar ne bih mogao da upoređujem bitove jednog broja sa bitovima drugog? Zar ih ne bih mogao pomerati levo-desno, ili raditi I/ILI operacije?
Odgovor je – pa mogu!
Sledeće operacije pokazuju kako se radi ova matematika.

Pomeranje bitova broja ulevo – znak << (left shift)

Pomera bitove datog broja ulevo za vrednost drugog prosleđenog broja.
>>> 2 << 2 
8 
>>> 3 << 100 
3802951800684688204490109616128 
>>> 12 << 1 
24 
>>> 
Da bi se ovo shvatilo, hajde da uradimo mali „trik“. Zašto nam Python služi – za programiranje, a zašto nam programiranje služi? Za shvatanje stvari. Evo, ovo ne shvatamo... Pa hajde da predstavimo to na malo „shvatljiviji“ način – napravimo šablon koji će nam prikazati ovo na način na koji mi to i želimo!
Šablon već imamo: {:b}, ali bilo bi dobro da on bude neke fiksne dužine.... Ajde neka bude 16 bita: {:16b}, no... treba nam i neki naziv, koji bi govorio o čemu se ovde radi.... Idemo da skupimo to u jedan programčić.... Sačuvajte ga kao shablon.py.
Prvo moramo da razmislimo šta želimo? Želimo da možemo da unesemo dva broja, prvi kojem ćemo da „pomeramo“ bitove, i drugi, za koliko želimo da pomeramo, budući da do sada nismo se mnogo bakćali oko input funkcije, šta misliš , šta nam ona vraća?
>>> input('joj :: ') 
joj :: jhkj 
'jhkj' 
>>> 
Auh.... Nevalja... Ona nam „vraća“ string. Kako od stringa napraviti broj (integer)? Python nam tu priskače u pomoć – da bi smo string prebacili u integer koristimo funkciju int():
>>> int('jel ovo radi?')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'jel ovo radi?'
>>> 
Hm? Ajd opet:
>>> int('deset')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'deset'
>>> 
Ne radi? A da pročitamo šta nam piše u greški? Python kaže da nije dobra vrednost, jer nismo prosledili dobre oznake! Da bi smo string prebacili u integer, taj string mora biti sačinjen od oznaka od 0 – 9, na primer:
>>> int('10') 
10 
>>> 
Aha... Jel sad jasnije?
Posle toga uradimo malko formatiranja i evo ga programče:
#! /usr/bin/env python3 

############################################### 
# Skripta koja nam vizuelizuje operacije nad  # 
# bitovima                                    # 
############################################### 

prvi = int(input('Unesi prvi broj >> ')) 
drugi = int(input('Unesi drugi broj >> ')) 
resenje = prvi << drugi 

oznake = '{:*^56}' 
razmak = 56 * '-' 

sablon = '{:0>16b}' 
ime = '{0:<16}{1:^16}' 

print(oznake.format('Left Shift: <<')) 
print(razmak) 
print('|', ime.format('Prvi broj', prvi), '|', sablon.format(prvi), '|') 
print('|', ime.format('Drugi broj', drugi), '|', sablon.format(drugi), '|') 
print(razmak) 
print('|', ime.format('Rešenje', resenje), '|', sablon.format(resenje), '|') 
print(oznake.format('Enter za kraj')) 
input()
Uh? Zašto ovako komplikovano?
Zato što nam treba i za kasniji rad.... Da bi shvatio ovu skriptu, pokušaj iznad svake linije koda da napišeš komentar, šta ona predstavlja (šta radi). Inače cela skripta radi ovo:
Unesi prvi broj >> 12 
Unesi drugi broj >> 3 
*********************Left Shift: <<********************* 
-------------------------------------------------------- 
| Prvi broj              12        | 0000000000001100 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                96        | 0000000001100000 | 
*********************Enter za kraj********************** 
Lepo? Ha? (Doduše, kako budemo napredovali kroz ovo poglavlje, izlaz će biti sve veći i veći, a skripta neće biti pisana na baš „adekvatan“ način – naime, pisana je za nivo koji ti trenutno možeš razumeti, kasnije kada budeš napredovao ćeš shvatiti da se mogla napisati i na mnogo kraći način)
Šta nam predstavlja ovo? Pa uneo sam dva broja, ispod je tabela koja mi daje naziv operacije nad bitovima koja je izvršena. Zatim nam prikazuje brojeve predstavljene u binarnom obliku, kao i rešenje.
Pažljivo analiziraj šta se dešava? Za trenutak zaboravi binarnu predstavu drugog broja, gledaj samo prvi broj i rešenje. Vidimo, da smo u stvari samo bitove prvog broja pomerili ulevo za 3 mesta. Znači da je 12 << 3 = 96!
Ajde još jedan primer:
Unesi prvi broj >> 3 
Unesi drugi broj >> 1 
*********************Left Shift: <<********************* 
-------------------------------------------------------- 
| Prvi broj              3         | 0000000000000011 | 
| Drugi broj             1         | 0000000000000001 | 
-------------------------------------------------------- 
| Rešenje                6         | 0000000000000110 | 
*********************Enter za kraj********************** 

Probaj još par primera, uz pažljivo analiziranje izlaznih podataka, kako bi ti bilo jasnije.

Pomeranje bitova broja udesno – znak >> (right shift)

Analogijom pomeranja bitova ulevo, ova operacija pomera bitove broja udesno za prosleđen broj.
Samo dodajte ove linije koda na kraj prethodne skripte:
resenje = prvi >> drugi 

print(oznake.format('Right Shift: >>')) 
print(razmak) 
print('|', ime.format('Prvi broj', prvi), '|', sablon.format(prvi), '|') 
print('|', ime.format('Drugi broj', drugi), '|', sablon.format(drugi), '|') 
print(razmak) 
print('|', ime.format('Rešenje', resenje), '|', sablon.format(resenje), '|') 
print(oznake.format('Enter za kraj')) 
input()
Da je „isprobamo, odmah:
Unesi prvi broj >> 12 
Unesi drugi broj >> 3 
*********************Left Shift: <<********************* 
-------------------------------------------------------- 
| Prvi broj              12        | 0000000000001100 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                96        | 0000000001100000 | 
*********************Enter za kraj********************** 

********************Right Shift: >>********************* 
-------------------------------------------------------- 
| Prvi broj              12        | 0000000000001100 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                1         | 0000000000000001 | 
*********************Enter za kraj**********************
(ako ti opet nije jasno, slobodno iznad svake linije u skripti unesi komentare, šta misliš da ta linija „radi“).
Probaj slobodno sa više brojeva, analiziraj rezultat... Kako to da su se bitovi pomerili levo-desno? Šta je dodato broju, a šta je oduzeto (u binarnom obliku).

Logičko I nad bitovima broja – znak & (AND)

Gledajući sa desna na levo vrši operaciju logičkog I jednog bita prvog broja, sa adekvatnim bitom drugog.
Da bi olakšali reprezentovanje šta to znači, i kako izgleda, dodajte sledeći kod na kraj vaše skripte:
resenje = prvi & drugi 

print(oznake.format('Bit - Wise AND: &')) 
print(razmak) 
print('|', ime.format('Prvi broj', prvi), '|', sablon.format(prvi), '|') 
print('|', ime.format('Drugi broj', drugi), '|', sablon.format(drugi), '|') 
print(razmak) 
print('|', ime.format('Rešenje', resenje), '|', sablon.format(resenje), '|') 
print(oznake.format('Enter za kraj')) 
input()
I sa nekim primerom:
Unesi prvi broj >> 5 
Unesi drugi broj >> 3 
*********************Left Shift: <<********************* 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                40        | 0000000000101000 | 
*********************Enter za kraj********************** 

********************Right Shift: >>********************* 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                0         | 0000000000000000 | 
*********************Enter za kraj********************** 

*******************Bit - Wise AND: &******************** 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                1         | 0000000000000001 | 
*********************Enter za kraj********************** 
Vidimo da je Python odradio 1 i 1 = 1, 0 i 1 = 0 itd. Pokušaj još primera, i ne zaboravi da je vrednost broja 1 – True, a broja 0 – False.

Logičko ILI nad bitovima brojeva – znak | (OR)

Logikom prethodnog primera, ova operacija vrši logičko ili, upoređujući bitove prvog broja, sa bitovima drugog broja.
Dodaj sledeće linije na kraj skripte:
resenje = prvi | drugi 

print(oznake.format('Bit - Wise OR: |')) 
print(razmak) 
print('|', ime.format('Prvi broj', prvi), '|', sablon.format(prvi), '|') 
print('|', ime.format('Drugi broj', drugi), '|', sablon.format(drugi), '|') 
print(razmak) 
print('|', ime.format('Rešenje', resenje), '|', sablon.format(resenje), '|') 
print(oznake.format('Enter za kraj')) 
input()
I sad kada primenimo našu skriptu, dobijamo:
Unesi prvi broj >> 5 
Unesi drugi broj >> 3 
*********************Left Shift: <<********************* 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                40        | 0000000000101000 | 
*********************Enter za kraj********************** 

********************Right Shift: >>********************* 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                0         | 0000000000000000 | 
*********************Enter za kraj********************** 

*******************Bit - Wise AND: &******************** 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                1         | 0000000000000001 | 
*********************Enter za kraj********************** 

********************Bit - Wise OR: |******************** 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                7         | 0000000000000111 | 
*********************Enter za kraj********************** 
1 ili 1 je 1, 0 ili 1 je 1 itd... Isprobaj još primera, dok ti ne bude jasnije....

Logiško KSILI nad bitovima brojeva – znak ^ (XOR)

Šta je sad pa ovo?
Ništa strašno.... XOR logička operacija je takva operacija koja za rezultat daje Tačno (TRUE) samo u slučajevima kada upoređuje različite vrednosti (True i False), ukoliko su vrednosti iste (True i True; False i False) ona daje False. Pitanje na koje ova logička operacija daje odgovore je – da li su stvari različite?
Kao i uvek, dodaj ove linije koda u svoju skriptu:
resenje = prvi ^ drugi 

print(oznake.format('Bit - Wise XOR: ^')) 
print(razmak) 
print('|', ime.format('Prvi broj', prvi), '|', sablon.format(prvi), '|') 
print('|', ime.format('Drugi broj', drugi), '|', sablon.format(drugi), '|') 
print(razmak) 
print('|', ime.format('Rešenje', resenje), '|', sablon.format(resenje), '|') 
print(oznake.format('Enter za kraj')) 
input()
Što nam daje:
...... 
*******************Bit - Wise XOR: ^******************** 
-------------------------------------------------------- 
| Prvi broj              5         | 0000000000000101 | 
| Drugi broj             3         | 0000000000000011 | 
-------------------------------------------------------- 
| Rešenje                6         | 0000000000000110 | 
*********************Enter za kraj********************** 
........
Probaj još kombinacija, da bi bilo jasnije.

Logička inverzija bitova broja – znak ~

Logička inverzija broja x je - (x +1)
>>> ~5 
-6 
>>> ~-25 
24 
>>> 
To je to što se tiče operacija.
Huh, napokon... 
Čekaj, samo za kraj, malko da „istvikujemo“ onu skriptu, pa da ti dam domaći da napišeš komentar iznad svega šta misliš da određene linije kodova predstavljaju....
Evo, pa lupaj glavu!
#! /usr/bin/env python3 

############################################### 
# Skripta koja nam vizuelizuje operacije nad  # 
# bitovima                                    # 
############################################### 

def prikaz(prvi, drugi, resenje, naziv): 
    oznake = '{:*^56}' 
    razmak = 56 * '-' 
    sablon = '{:0>16b}' 
    ime = '{0:<16}{1:^16}' 
    print(oznake.format(naziv)) 
    print(razmak) 
    print('|', ime.format('Prvi broj', prvi), '|', sablon.format(prvi), '|') 
    print('|', ime.format('Drugi broj', drugi), '|', sablon.format(drugi), '|') 
    print(razmak) 
    print('|', ime.format('Rešenje', resenje), '|', sablon.format(resenje), '|') 
    print(oznake.format('\/')) 


prvi = int(input('Unesi prvi broj >> ')) 
drugi = int(input('Unesi drugi broj >> ')) 
resenje = prvi << drugi 
naziv = 'left shift <<' 
prikaz(prvi, drugi, resenje, naziv) 

resenje = prvi >> drugi 
naziv = 'right shift >>' 
prikaz(prvi, drugi, resenje, naziv) 

resenje = prvi & drugi 
naziv = 'bit-wise AND &' 
prikaz(prvi, drugi, resenje, naziv) 

resenje = prvi | drugi 
naziv = 'bit-wise OR |' 
prikaz(prvi, drugi, resenje, naziv) 

resenje = prvi ^ drugi 
naziv = 'bit-wise XOR ^' 
prikaz(prvi, drugi, resenje, naziv) 

input('Pritisni Enter za kraj.')
A sad kratka napomena:

7 Matematičke operacije Indeks 7.1.1 Prečice za
matematičke operacije

Коментари

Popularno

Audacious - program za slušanje muzike

LibreOffice Calc - program za izradu tabela

Brasero - program za rezanje CD-ova

Bekstvo iz Titela

Minitube - program za praćenje YouTube sadržaja

Idemo

Bezimena

Pozadina Bekstva iz titela

Pažljivo sa MS Word dokumentima koje primate putem elektronske pošte

Šta je to "prosijački štap" i kako se do njega dolazi? (prvi deo)