Mario Essert, Domagoj Ševerdija, Ivan Vazler
Digitalni udžbenik
Python - osnove -
Odjel za matematiku Sveučilišta Josipa Jurja Strossmayera Osijek, 2007.
Sadržaj Sadržaj
3
1 Python interpreter 1.1 Jezične značajke . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Izvođenje Python programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Naš prvi Python program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7 7 8 9
2 Tipovi podataka 2.1 Brojevi . . . . . . . . . . . . . . . . . . . . . . . 2.2 Nizovi . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Stringovi - nizovi alfanumeričkih znakova 2.2.2 N-terac . . . . . . . . . . . . . . . . . . . 2.2.3 Lista . . . . . . . . . . . . . . . . . . . . . 2.3 Temeljne operacije i metode s nizovima . . . . . 2.3.1 Ugrađene metode string-ova . . . . . . . . 2.3.2 Ugrađene metode listi . . . . . . . . . . . 2.4 Rječnik . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 Ugrađene metode rječnika . . . . . . . . . 2.5 Skup . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
11 14 15 15 17 17 18 19 21 22 22 23
3 Izrazi, operatori i operacije 3.1 Varijable . . . . . . . . . . . . . . . . . . . . . . 3.2 Naredbe pridruživanja . . . . . . . . . . . . . . 3.2.1 Obična pridružba . . . . . . . . . . . . . 3.2.2 Proširena pridružba . . . . . . . . . . . 3.2.3 Naredba del . . . . . . . . . . . . . . . 3.2.4 Bool -ove vrijednosti . . . . . . . . . . . 3.3 Operatori i operacije . . . . . . . . . . . . . . . 3.3.1 Numeričke i aritmetičke operacije . . . . 3.3.2 Prisilna i eksplicitna pretvorba . . . . . 3.3.3 Usporedba . . . . . . . . . . . . . . . . 3.3.4 Operacije na bitovima cijelih brojeva . . 3.4 Operacije na nizovima . . . . . . . . . . . . . . 3.4.1 Kriška (eng. slicing) niza . . . . . . . . 3.4.2 Stacionarne operacije na listi i rječniku 3.5 Naredba Print . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
25 25 25 26 27 27 27 28 29 29 30 30 30 31 32 32
upravljanje if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33 33 34 35
4 Programsko 4.1 Naredba 4.2 Naredba 4.3 Naredba
. . . . . . . . . . . . . . .
3
4.4 4.5 4.6 4.7
Iteratori . . . . . . . . . Funkcije range i xrange Sažete liste . . . . . . . Naredba break . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
36 37 37 38
5 Iznimke 5.1 Vrste iznimki . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Rad s iznimkama . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Obradba iznimki . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1 Ignoriranje iznimke . . . . . . . . . . . . . . . . . . . 5.3.2 Pronalaženje argumenta iznimke . . . . . . . . . . . 5.3.3 Obradba svih iznimki . . . . . . . . . . . . . . . . . 5.3.4 Pokretanje programskog koda bez prisustva iznimke 5.3.5 Obradba više iznimki . . . . . . . . . . . . . . . . . 5.3.6 Pokretanje obaveznog kôda za čišćenje . . . . . . . . 5.3.7 Eksplicitno podizanje iznimke . . . . . . . . . . . . . 5.4 Korisnički definirane iznimke . . . . . . . . . . . . . . . . . 5.4.1 Tvorba iznimki . . . . . . . . . . . . . . . . . . . . . 5.4.2 Dodjelivalo . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
39 39 42 43 44 44 44 45 45 45 45 46 46 47
6 Funkcije 6.1 Naredba def . . . . . . . . . . . 6.2 Parametri . . . . . . . . . . . . 6.3 Atributi funkcijskih objekata . 6.4 Naredba Return . . . . . . . . 6.5 Pozivanje funkcija . . . . . . . 6.5.1 Prenošenje argumenata 6.5.2 Vrste argumenata . . . 6.5.3 Prostori za imena . . . . 6.6 Globalna naredba . . . . . . . . 6.7 Ugnježđene funkcije . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
49 49 50 51 52 52 52 53 53 54 54
7 Python - objektni jezik 7.1 Klasične klase i instance . . . . . . . . . . . . . 7.2 Naredba class . . . . . . . . . . . . . . . . . . 7.3 Tijelo klase . . . . . . . . . . . . . . . . . . . . 7.3.1 Atributi objekata klase . . . . . . . . . . 7.3.2 Definicije funkcija unutar tijela klase . . 7.3.3 Varijable specifične za klasu . . . . . . . 7.3.4 Dokumentacijski string . . . . . . . . . . 7.4 Instance . . . . . . . . . . . . . . . . . . . . . . 7.4.1 __init__ . . . . . . . . . . . . . . . . 7.4.2 Atributi objekata instance . . . . . . . . 7.4.3 Tvornička funkcija . . . . . . . . . . . . 7.4.4 Brojanje referenci i uništenje instance . 7.5 Reference atributa . . . . . . . . . . . . . . . . 7.6 Metode povezivanja i odvezivanja . . . . . . . . 7.6.1 Detalji nepovezanih metoda . . . . . . . 7.7 Nasljeđivanje . . . . . . . . . . . . . . . . . . . 7.7.1 Premošćujući (engl. overriding) atributi 7.7.2 Posluživanje metoda superklase . . . . . 7.7.3 "Brisanje" atributa klasa . . . . . . . . 7.7.4 Višeobličje (eng. polymorphism) . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . .
57 57 58 58 58 59 60 60 60 61 61 62 62 62 63 64 64 66 66 67 67
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
5
7.8
7.7.5 Skrivanje informacije (engl. information hiding) . . . . . . . . . . . . . . . . . . . 7.7.6 Operatorsko punjenje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Testovi pripadnosti klasa i tipova . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
67 67 68
8 Moduli i paketi 8.1 Moduli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1.1 Modulski put traženja (engl. Search Path) . . . . . . . . . 8.1.2 Učitavanje, punjenje (engl. import) modula i compilacija 8.1.3 Ponovno punjenje modula (engl. reloading) . . . . . . . . 8.2 Paketi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
71 71 73 73 74 74
9 Ulaz i izlaz 9.1 Čitanje opcija i varijabli okoliša . . . . 9.2 Datoteke (engl. files) . . . . . . . . . . 9.3 Standardni ulaz, izlaz i pogreška (engl. 9.4 Naredba print . . . . . . . . . . . . . . 9.5 Otpornost . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
77 77 78 79 80 81
. . . . . . . . Input, . . . . . . . .
. . . . . . . . . . Output, . . . . . . . . . .
. . . . . . . . Error) . . . . . . . .
. . . . .
. . . . .
Literatura
83
Indeks
84
POGLAVLJE
Python interpreter Python je interpreterski, interaktivni, objektu orjentirani programski jezik, kojeg je 1990. godine prvi razvio Guido van Rossum. Već do konca 1998., Python je imao bazu od 300.000 korisnika, a od 2000. već su ga prihvatile ustanove kao MIT, NASA, IBM, Google, Yahoo i druge. Python ne donosi neke nove revolucionarne značajke u programiranju, već na optimalan način ujedinjuje sve najbolje ideje i načela rada drugih programskih jezika. On je jednostavan i snažan istodobno. Više nego drugi jezici on omogućuje programeru više razmišljanja o problemu nego o jeziku. U neku ruku možemo ga smatrati hibridom: nalazi se između tradicionalnih skriptnih jezika (kao što su Tcl, Schema i Perl ) i sistemskih jezika (kao što su C, C++ i Java). To znači da nudi jednostavnost i lako korištenje skriptnih jezika (poput Matlab-a), uz napredne programske alate koji se tipično nalaze u sistemskim razvojnim jezicima. Python je besplatan (za akademske ustanove i neprofitnu upotrebu), open-source software, s izuzetno dobrom potporom, literaturom i dokumentacijom.
1.1
Jezične značajke
Interpretacija međukôda Python kôd sprema se u tekst datoteke koje završavaju na .py. Program kompilira kôd u niz bytecode-ova koji se spremaju u .pyc datoteke koje su prenosive na bilo koje platforme gdje se mogu izvoditi interpretacijom tog međukôda. Na sličan način izvršava se Java kôd interpretacijom međukôda. Brzina izvođenja Python kôda istog je reda veličine kao u Javi ili Perlu. Python je napisan u ANSI C i raspoloživ za cijeli niz strojeva i operacijskih sustava uključujući Windows, Unix/Linux i Macintosh. Jezik visoke razine Osim standardnih tipova podataka (brojevi, nizovi znakova i sl.) Python ima ugrađene tipove podataka visoke razine kao što su liste, n-terci i rječnici. Interaktivnost Python se može izvoditi u različitim okruženjima. Za razvitak programa najlakši je interaktivni način rada u kojem se programski kôd piše naredbu za naredbom. Ne postoji razlika u razvojnom i izvedbenom (engl. runtime) okolišu: u prvom se izvodi naredba za naredbom , a u drugom odjednom čitava skripta. Čista sintaksa 7
1
8
Python interpreter
Sintaksa jezika je jednostavna i očevidna. Uvlake zamjenjuju posebne znakove za definiranje blokova kôda, pa je napisani program vrlo pregledan i jednostavan za čitanje. Napredne značajke jezika Python nudi sve značajke očekivane u modernom programskom jeziku: objektu orijentirano programiranje s višestrukim nasljeđivanjem, dohvaćanje izuzetaka ili iznimki (engl. exception), redefiniranje standardnih operatora, pretpostavljene argumente, prostore imena (engl. namespaces), module i pakete. Proširivost Python je pisan u modularnoj C arhitekturi. Zato se može lako proširivati novi značajkama ili API-ima. (engl. application programming interface). Bogate knjižnice programa Pythonova knjižnica (engl. library), koja uključuje standardnu instalaciju, uključuje preko 200 modula, što pokriva sve od funkcija operacijskog sustava do struktura podataka potrebnih za gradnju web-servera. Glavni Python web site (www.python.org) nudi sažeti index mnogih Python projekata i različitih drugih knjižnica. Potpora Python ima veliku entuzijastičku zajednicu korisnika koja se svake godine udvostručuje.
1.2
Izvođenje Python programa
Python kôd može se izvoditi na više načina: Interaktivni rad To je najčešći način rada kod pisanja novih programa, a započinje pozivom python u Linux -u, odnosno dvostrukim klikom na ikonicu u Windows okruženju. U MS-DOS okruženju, Python se poziva isto kao u Unix -u/Linux -u, jedino je sistemski znak (engl. prompt) drugačiji. Pozivom interpetera otvara se njegova okolina, npr. pod PythonWin-om: PythonWin 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)] on win32. Portions Copyright 1994-2006 Mark Hammond - see ’Help/About PythonWin’ for further copyright information. >>> ili pod Linux-om: $ python Python 2.5 (r25:51908, Oct 6 2006, 15:24:43) [GCC 4.1.2 20060928 (prerelease) (Ubuntu 4.1.1-13ubuntu4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> Interepreter dakle ispisuje svoj prompt >>>, iza kojeg korisnik unosi (utipkava) naredbu, a koju završa s ENTER tipkom (ili Return tipkom). Zatim Python izvodi tu naredbu, ispisuje rezultat i ponovo ispisuje prompt očekujući novu naredbu: >>> print ’Znam zbrojiti: 1+2 =’, 1+2 Znam zbrojiti: 1+2 = 3 >>>
1.3. Naš prvi Python program
9
Na ovaj način Python se može koristiti kao jednostavan, ali i vrlo složen kalkulator. U slučaju naredbi koje pretpostavljaju daljnje naredbe u nastavku, npr. naredbe petlje (for, while, ...), Python interpreter ispisuje ’...’ i automatski čini uvlaku za nove naredbe. U Windows okruženju postoji više grafičkih rješenja za interaktivan rad. U instalacijskom paketu s Pythonom dolazi IDLE kojeg je razvio Python-ov autor. IDLE koristi Tkinter GUI framework i prenosiv je na sve Python platforme koje imaju Tkinter potporu. Bolja rješenja od IDLE-a su PythonWin, PyScripter i novija, koja korisniku daju puno grafičkih rješenja za jednostavnu Python upotrebu kako u interaktivnom tako i u skriptnom radu. Skriptni rad Programi se spremaju u skripte s pomoću običnog text editora ili Python orjentiranog grafičkog okruženja, a onda se kao Unix /Linux ili Windows skripte pozivaju iz sistemske linije. Ako smo na primjer gornju naredbu (ili više njih) spremili u datoteku-skriptu ’moj.py’, onda se pozivom: python moj.py skripta izvodi i na zaslonu se dobije rezultat: Znam zbrojiti: bio isti onaj utipkan u interaktivnom radu.
1+2 = 3 jer je kôd skripte
Umetnuti (embeded) kôd Iako se češće unutar Pythona mogu pozivati funkcije iz drugih programa (npr. C -a za slučaj programskog ubrzanja), moguće je Python kôd u obliku izvornih tekst naredbi izvoditi i unutar programa pisanog u drugom programskom jeziku, koristeći Python runtime API, na primjer unutar C -programa: #include
. . . Py_Initialize(); PyRun_SimpleString("x = a + 2*pi");
1.3
Naš prvi Python program
Neka se na početku promotri jedan primjer Python programa, kako bi se uočila svojstva i način pisanja programskog kôda. from random import r a n d i n t gotovo=F a l s e ; korak=0 b r o j=r a n d i n t ( 1 , 1 0 0 ) w h i l e not gotovo : x=i n t ( raw_input ( " Pogodi ␣ z a m i s l j e n i ␣ b r o j : " ) ) i f x==b r o j : p r i n t ’ Cestitamo ! ’ gotovo=True ; e l i f x
10
Python interpreter
Prva linija programa uvlači (engl. import) iz modula random funkciju randint() s kojom će se generirati slučajan cijeli broj. Varijabla ’gotovo’ postavlja se u Bool-ovo stanje neistine (engl. False), a varijabla ’korak’ inicijalizira se sa 0. Znak ’;’ služi za odvajanje naredbi pisanih na istoj liniji. U varijablu ’broj’ sprema se slučajni broj (između 1 i 100), kojeg korisnik pogađa. Kako se vidi, postoji petlja while koju program u izvođenju vrti sve dok varijala gotovo ne postane istinita, tj. True, a to se dogadja kad zamišljeni ’broj’ bude jednak, od korisnika izabranoj, vrijednosti varijable ’x’. U slučaju da to nije ispunjeno, program ’pomaže’ korisniku savjetom da pogađa naviše ili naniže. Pritom se varijabla ’korak’ svaki put povećava za 1, kako bi na koncu, nakon čestitke, bilo ispisano i koliko koraka je trebalo da se do nje dođe. Treba primjetiti kako u Pythonu ne postoje oznake početka i konca bloka naredbi (kao što su to vitičaste zagrade u C -jeziku ili begin-end u Pascal -u), nego se to ostvaruje uvlakama. Na taj način korisnik je prisiljen pisati strukturirani kod, lagan za čitanje. Sve upravljače naredbe (if, while, else i sl.) završavaju sa znakom dvotočke (’:’). Treba također uočiti kako je rad sa ulazom i izlazom u Pythonu jednostavan (poput Basic-a) - postoje dvije funkcije: row_input() za ulaz i print za izlaz. Prva ispisuje poruku korisniku i učitava niz znakova (string) koji korisnik upiše, a druga samo ispisuje string i/ili sadržaj varijabli. Moguće je također i formatiranje izlaza (zadnja print naredba).
POGLAVLJE
Tipovi podataka Računalni program je algoritam zadan programskim naredbama koje se izvršavaju nad nekom vrstom ili tipom (binarno spremljenih) podataka. Sve podatčane vrijednosti u Pythonu predstavljene su objektima, pa se za Python s pravom kaže: "Sve je objekt". Svaki objekt može imati najviše četiri svojstva: • identitet - adresa u memoriji gdje je objekt spremljen • tip - veličina memorijskog prostora kojeg objekt zauzima i na kojem se stanovite metode (obrade) mogu tj. smiju obavljati • vrijednost - sadržaj memorijskog prostora spremljenog objekta • metodu - programski kôd koji se primjenjuje na vrijenosti(ma) objekta Identitet i tip objekta su nepromjenljive veličine i definiraju se stvaranjem, generiranjem, objekta. Svaki objekt može imati jednu ili više vrijednosti, te jednu ili više metoda. Neki objekti dolaze se Python interpreterom, zovemo ih ugrađeni objekti (engl. built-in objects), a druge stvara sâm korisnik preko Python klasa. Vrijednosti objekta često se zovu atributi. Dohvaćanje atributa u objektu ostvaruje se sintaksom obj.atr, gdje je obj ime objekta, a atr ime atributa. Objekti kojima se vrijednost(i) mogu mijenjati bez promjene identiteta zovu se promjenljivi (engl. mutable) objekti, a oni kojima se vrijednost ne može mijenjati bez stvaranja novog objekta istog tipa zovu se nepromjenljivi (engl. immutable) objekti. Promjena vrijednosti objekta obično se događa pridruživanjem različitih literala ili djelovanjem metode na vrijednost objekta. Literal označuje vrijednost podatka koja se neposredno, direktno, pojavljuje u programskoj naredbi: 2347 13.514 5.0J ’hello’
# # # #
Cjelobrojni literal Realni (Floating-point) literal Imaginarni literal String literal, niz znakova
Osim alfanumeričkih znakova za brojeve i stringove, Python koristi i posebne simbole i to kao međaše ili graničnike (npr. za početak i završetak string literala koristi simbole jednostrukih, dvostrukih ili trostrukih navodnika) ili kao simbole aritmetičko-logičkih i odnosnih (relacijskih) operatora. Simbol ’#’ koristi se za početak komentara i ne obrađuje se od strane Python interpretera: sve napisano u linije iza njega, udesno, interpreter neće obrađivati. Međaši služe i kod definicije složenih tipova, od kojih su najčešće koriste: [ 63, ’faks’, 8.6 ] ( 450, 320, ’600’ ) { ’a’:72, ’b’:1.4 }
# Listina, lista ili popis (engl. \emph{list}) # n-terac (engl. \emph{tuple}) # rje\v{c}nik (engl. \emph{dictionary}) 11
2
12
Tipovi podataka
Tipovi objekata mogu se složiti u kategorije (tablica 2.1), pa razlikujemo brojeve, nizove, klase, datoteke, module i sl. Neki objekti su promjenljivi (npr. liste), a neki nisu (npr. stringovi). Tablica 2.1: Ugrađeni (built-in) tipovi u Python programskom jeziku Kategorija tipa podataka Prazno (None) Brojevi
Ime tipa podatka
Opis
Preslikavanje Klase, razredi
ComplexType StringType UnicodeType ListType TupleType XRangeType BufferType DictType ClassType
Instanca klase, objekt
InstanceType
Datoteka
FileType
Moduli Objekti koji se pozivaju
ModuleType
’null’ objekt Cijeli broj Dugi cijeli broj Realni broj s pom. zarezom Kompleksni broj Niz znakova (string) Unicode (string) Listina, popis ili lista n-terac Vraćeno iz xrange() Vraćeno iz buffer() Rječnik Definicija klase Stvaranje instance klase Datoteka - podaci na mediju Modul (skup objekata)
BuiltinFunctionType
Ugrađene funkcije
BuiltinMethodType ClassType FunctionType InstanceType
Ugrađene metode Objekt klase Korisnička funkcija Instanca klase, objekt Ograničena (bound) metoda Neograničena metoda klase Byte-compilirani kôd Izvedbeni okvir Složaj slijeda izuzetaka Tip kriške (odlomka) Prošireni odlomci ()
NoneType IntType LongType FloatType
Nizovi
MethodType UnboundMethodType Nutarnji tipovi
CodeType FrameType TracebackType SliceType EllipsisType
Python program pristupa vrijednostima objekata preko identiteta, adresnih referenci. Referenca je broj koje se odnosi na neku specifičnu lokaciju u memoriji na kojoj je spremljena vrijednost objekta. Vrijednost objekta često se još zove atribut objekta. Atributi složenih tipova (npr. liste, stringa ili rječnika) često se zovu članovi (engl. items). Referenca objekta sprema se u memorijsku lokaciju koja se zove varijabla. Varijabla može pokazivati na spremljeni literal, na isti način kao i na objekt koji ima više vrijendosti i/ili više metoda. Jedna ili više Python programskih naredbi može se spremiti u funkciju. Razlikuju se ugrađene (engl. built-in) i korisničke funkcije. Korisničke funkcije definira korisnik, a ugrađene dolaze s Python interpreterom. Dakako, funkcija je objekt. Funkcija u objektu zove se metoda, a dohvaća se sa obj.fun(), gdje je obj
Tipovi podataka
13
ime objekta, a fun()je ime funkcije. Unutar okruglih zagrada mogu doći i argumenti, odnosno parametri funkcije. Funkcija može imati ulazne argumente i vraćati izlazne vrijednosti. Na primjer, provjera tipa nekog objekta ostvaruje se pozivom ugrađene funkcije type(): >>> type("Zanimljivi Python svijet!") >>> type(512) >>> k=2.178 >>> type(k) >>> type ({ ’a’:72, ’b’:1.4 }) >>> z=2+3j >>> type(z)
# string literal # numericki literal # varijabla k
# varijabla z
Objekti (varijable, funkcije, klase i dr.) s programskim naredbama koje na njima rade mogu se spremati u module, a moduli u pakete. Modul se u memoriju učitava s pomoću naredbe ’import’. import sys
# ucitava se modul sistemskih funkcija
Pojedinačni podatak ili funkcija iz modula dohvaća se naredbom ’from ... from math import sin, cos
import ... ’ :
# ucitavaju se samo sin i cos funkcije
Dohvaćanje vrijednosti podatka preko atributa objekta postiže se sintaksom ’objekt.atribut’. Objekt može imati više atributa. U slučaju da je atribut neka funkcija, odgovarajuća sintaksa je ’objekt.atribut()’. >>>import math >>> print math.pi, math.sin(2.3) 3.14159265359 0.745705212177 Dohvaćanje vrijednosti podatka preko članova, često se naziva indeksiranje i odnosi se samo na strukturirane tipove podataka (liste, stringove i sl.). Indeksacija počinje s nultim (0) indeksom. >>> x=[1, 3, 9, 16] >>> print x[3] 16
# lista s cetiri podatka # dohva\’{c}anje treceg podatka
Vrijednost reference može se doznati pozivom funkcije id(). Pridruživanjem objekata referenca se ponavlja, tj. objekti se ne dupliciraju. >>> a=123 >>> id(a) 3695888 >>> b=a >>> b 123 >>> id(b) 3695888 >>> a=a+1 >>> print ’a=’,a,’ b=’,b a= 124 b= 123 >>> print ’id(a)=’,id(a),’ id(b)=’,id(b) id(a)= 3695876 id(b)= 3695888
# pridruzba b sa a; objekt se ne kopira, samo adresa
# b kao i a pokazuje na istu memorijsku adresu # stvoren je novi objekt
# ne pokazuju isto!
14
Tipovi podataka
Izraz (engl.expression) je kombinacija vrijednosti (literala), varijabli i operatora. Vrijednost izračunatog izraza ispisuje se na zaslon računala korištenjem naredbe print: >>> print ’gruba aproksimacija pi = ’, 22./7 gruba aproksimacija pi = 3.14285714286 Programske naredbe Pythona temelje se na pridruživanju (objekata referencama), upravljanju tijekom programa (if, else,...), programskim petljama (for, while, ...) i pozivima funkcija i klasa. Funkcije obuhvaćaju jednu ili više naredbi. Postoji velik broj ugrađenih (built-in) funkcija, a ostale stvara korisnik. Funkcije, zajedno s podacima, grupiraju se u klase. Funkcije definirane unutar klasa, zovu se metode. Identifikator je ime objekta, tj. ime varijable, funkcije, klase i sl. Identifikatori ne smiju koristiti neku od 30 ključnih riječi Python-a (tablica 2.2), jer su one pridružene osnovnim Python naredbama.
Tablica 2.2: and assert break class continue def
2.1
del elif else except exec finally
Python ključne riječi for from global if import in
is lambda not or pass print
raise return try while with yield
Brojevi
Ugrađeni brojevni objekti u Pythonu podržavaju cijele brojeve (obične i dugačke), brojeve s pomičnim zarezom (realne brojeve) i kompleksne brojeve. Objekti brojeva u Pythonu su nepromjenljivi (immutable) objekti, što znači da bilo kakva aritmetička operacija na brojevnom objektu, uvijek stvara novi brojevni objekt. >>> a=1234 >>> id(a) 19431452 >>> a=a+0 >>> id(a) 18681652 >>> print a 1234 Literali cijelih brojeva mogu biti decimalni, oktetni, ili heksadecimalni. Decimalni literal je predstavljen nizom znamenki gdje je prva znamenka različita od nule. Oktetni literal je određen s početnom 0 iza koje ide niz oktetnih znamenki (0 do 7). Na sličan način heksadecimalni literal koristi početni niz 0x nakon čega slijedi niz heksadecimalnih znamenki (0 do 9 i A do F bilo velikim ili malim slovom). Na, primjer: 1, 23, 3493 01, 027, 06645 0x1, 0x17, 0xda5
#Decimalni cijeli brojevi #Oktetni cijeli brojevi #heksadecimalni cijeli brojevi
Bilo kojem literalu cijelog broja može može se dodati slovo ’L’ ili ’l’ kako bi se označio dugački cijeli broj (long integer ). Na primjer: 1L, 23L, 99999333493L 01L, 027L, 01351033136165L 0x1L, 0x17L, 0x17486CBC75L
#Dugacki decimalni cijeli brojevi #Dugacki oktetni cijeli brojevi #Dugacki heksadec. cijeli brojevi
2.2. Nizovi
15
Razlika između dugačkog i običnog cijelog broja je u tome što dugački cijeli broj nema predodređenu numeričku granicu; može biti toliko dug koliko računalo ima memorije. Običan cijeli broj uzima nekoliko okteta memorije i ima minimalnu i maksimalnu vrijednost koju diktira arhitektura stroja. sys.maxinit je najveći dostupni običan cijeli broj, dok je sys.maxinit-1 najveći negativni. >>> print sys.maxint # za uobicajeni stroj najveci cijeli broj je 2147483647 >>> 2L**500 # 2 na 500-tu potenciju 3273390607896141870013189696827599152216642046043064... 7894832913680961337964046745548832700923259041571508866841275600710092172565458853... 93053328527589376L Realni literal (broj s pomičnim zarezom) predstavljen je nizom decimalnih znamenki koje uključuju decimalni zarez, tj. točku (.), exponent (e ili E, te + ili - iza, s jednom ili više znamenki na kraju), ili oboje. Vodeći znak decimalnog literala ne smije biti e ili E, a može biti bilo koja znamenka ili točka (.). Na primjer: 0.,
1.0,
.2,
3.,
4e0,
5.e0, 6.0e0
Pythonova decimalna vrijednost odgovara uobičajena 53 bita preciznosti na modernim računalima. Kompleksni broj sastavljen je od dviju decimalnih vrijednosti, jedne za realni, a druge za imaginarni dio. Moguće je pristupiti dijelovima kompleksnog objekta z kao samo-čitajućim "read-only" atributima z.real i z.imag. Imaginarni literal dobije se dodavanjem znaka ’j’ ili ’J’ realnom literalu: 1j,
1.j,
1.0j,
1e0j,
1.e0j,
1.0e0j
Znak J (ili j ) na kraju literala označuje kvadratni korijen od -1, što je uobičajena oznaka imaginarnog dijela u elektrotehničkoj praksi (neke druge discipline koriste znak ’i’ u tu svrhu, ali Python je izabrao baš znak j). Treba primijetiti da brojevni literali ne uključuju predznak: ako postoji + ili - ispred broja, onda su to posebni operatori.
2.2
Nizovi
Niz je spremnik (engl. container) članova (engl. items) koji se indeksiraju ili dohvaćaju ne-negativnim cijelim brojevima. Python pruža tri ugrađene (engl. built-in) vrste nizova za stringove (obične i Unicode), n-terace, i liste. Knjižnički i ekstenzijski moduli pružaju druge vrste nizova, a korisnik također može sam napisati svoje. Nizovi se mogu obrađivati na više načina.
2.2.1
Stringovi - nizovi alfanumeričkih znakova
Ugrađeni objekt string je poredan skup znakova koji se koristi za skladištenje i predstavljanje podataka na tekstovnoj bazi. Nizovi znakova u Pythonu su nepromjenljivi (engl. immutable), što znači da se novom operaciijom na nizu znakova, uvijek proizvede novi niz, a ne modificira stari. Objekti stringa imaju ugrađeno više metoda. Literalni niz znakova može biti pod navodnicima jednostrukim, dvostrukim ili trostrukim navodnicima. String u navodnicima je niz od nula ili više znakova unutar identičnih znakova navodnika. Na primjer: ’Ovo je string literal’ "Ovo je novi string literal" Dvije različite vrste navodnika imaju identičnu funkciju. Mogu se koristiti tako da apostrofiramo string unutar stringa, što je često jednostavnije nego apostrofirati string upotrebom posebnog znaka (źa jednostruki ili ¨za dvostruki navodnik): ’ jel\’ me netko trazio?’ " jel’ me netko trazio?"
# eksplicitni navodnik u stringu # Na ovaj nacin je citljivije
16
Tipovi podataka
Ako se string želi prikazati u više linija, onda se na koncu svake linije stavlja znak lijeve kose crte (\): "Ovo je prva, \ a ovo druga linija istog stringa"
# Komentar nije dopusten na # liniji sa znakom \
U stringu se dakako mogu umetati i posebni znakovi (\n za novu liniju, \t za tabulator i sl.), ako se takav niz želi programom ispisivati: "Ovo je prva, \n a ovo druga linija istog stringa" Drugi pristup je uporaba stringa s trostrukim navodnicima, koji se dobiju trostrukim ponavljanjem jednostrukih (” ’) ili dvostrukih navodnika ("""). """A ovo je jedan duuugi string koji se proteze na vise linija, u ovom slucaju na tri""" # Komentar dopusten samo na kraju U ovakvom literalu stringa s tri navodnika, automatski su sačuvani novi redovi, pa se njihovi kontrolni znakovi ne trebaju dodavati u niz. Nije dopuštena ni upotreba nekih kontrolnih (tzv. ’escape’) znakova (tablica 2.3), kao na primjer znaka lijeve kose crte (engl. backslash;) Tablica 2.3: ’Escape’ znakovi Niz \ < novired > \\ \0 \” \a \b \f \n \r \t \v \0ooo \xhh \uhhh
Značenje Konac linije se zanemaruje Kosa crta ulijevo, backslash Jednostruki navodnik Dvostruki navodnik Zvono, bell Brisanje ulijevo, backspace Nova stranica, form feed Nova linija, newline Skok u novi red, carriage return Tabulator, tab Vertikalni tabulator Oktalna vrijednosti ooo (\0000 do \0377) Heksadecimalna vrijednost hh (\x00 do \xf f ) Unicode vrijednosti
ASCII/ISO kod Nema ga 0x5c 0x27 0x22 0x07 0x08 0x0c 0x0a 0x0d 0x09 0x0b kako je zadano kako je zadano Samo za Unicode str.
Unicode je novi standard za pisanje znakova. Za razliku od ASCII standarda, novi standard uključuje sve znakove iz gotovo svih svjetskih jezika. Unicode literalni string ima istu sintaksu kao obični literalni string uz dodatak znaka ’u’ ili ’U’ koji se piše odmah ispred početnog navodnika. Unicode literalni nizovi znakova mogu koristiti ’\u’ iza kojeg slijede četiri heksadecimalne znamenke koje opisuju Unicode znak. >>> a=u’str\xf6m gr\xfcn’ >>> print a ström grün Više string literala bilo koje vrste napisanih u slijedu, compiler će povezati u jedan string objekt. >>> print ’koliko’ ’je’ ’tu’ ’stringov’ u’\xe4’ ’?’ kolikojetustringovä?
2.2. Nizovi
2.2.2
17
N-terac
N-terac je nepromjenljivi niz članova. Članovi u n-tercu su bilo koji objekti, istih ili različitih tipova. Nterac se definira nabrajanjem objekata odvojenih zarezima (,). Zadnjem članu u nizu takodjer se može dodati zarez. N-terac sa samo jednim članom mora imati zarez na kraju, jer inače gubi tip n-terca. Prazan n-terac je označen s praznim parom zagrada. Članovi se mogu grupirati, pa nastaju ugnježdeni n-terci. (100, 200, 300) # N-terac s tri clana (3.14,) # N-terac sa samo jednim clanom ( ) # Prazan n-terac Za generiranje n-terca, osim nabrajanjem, moguće je pozvati i ugrađenu funkciju ’tuple()’. Ako je x neki niz, onda tuple(x) vraća n-terac s članovima jednakima članovima niza x. >>> x=’abrakadabra’ >>> tuple(x) (’a’, ’b’, ’r’, ’a’, ’k’, ’a’, ’d’, ’a’, ’b’, ’r’, ’a’) >>> y=’sezame’ >>> (x,y) (’abrakadabra’, ’sezame’)
2.2.3
Lista
Lista, listina ili popis je promjenljiv poredani niz članova objekata. Članovi u listi su bilo kakvi objekti različitih tipova. Lista se definira nabrajanjem članova odijeljenih zarezima (,) i smještenih unutar uglatih zagrada ([ ]). Dopušteno je iza zadnjeg člana liste, ostaviti još jedan zarez. Prazna lista se označava praznim parom uglatih zagrada. Evo nekih primjera: [42, 3.14, ’zdravo’ ] [123] [’a’, [-45j, ’b’], 4.5] [ ]
# # # #
Lista s tri clana Lista s jednim clanom ugnjezdena lista s tri clana Prazna lista
Na sličan način, kao i s generiranjem n-teraca, moguće je pozvati prikladnu funkciju ’list()’ za generiranje listi. Na primjer: >>> a=’ovo’ >>> b=’je’ >>> c=’lista’ >>> d=[a,b,c] # tvorba liste nabrajanjem clanova >>> print d [’ovo’, ’je’, ’lista’] >>> list(d) # tvorba liste pozivom funkcije [’ovo’, ’je’, ’lista’] >>> list(a) # tvorba liste pozivom funkcije [’o’, ’v’, ’o’] >>> type(d) >>> type(a) Treba primjetiti kako se tvorba listi preko list() funkcije uvijek realizira nad pripadnim tipom objekta.
18
Tipovi podataka
2.3
Temeljne operacije i metode s nizovima
Dohvaćanje elementa bilo kojeg niza (stringa, n-terca, liste) postiže se indeksiranjem. Dio niza, odlomak ili kriška (engl. slice) dobiva se sintaksom ’i:j’ gdje je ’i’ početni indeks, a ’j’ završni indeks kriške (tablica 2.4). Dužina niza dobiva se pozivom funkcije len(), a maksimalni i minimalni član niza s funkcijama max(), odnosno min(). Tablica 2.4: Operacije i metode nad svim nizovima Član s[i] s[i:j] len(s) min(s) max(s)
Vraća Vraća Vraća Vraća Vraća
Opis element i u nizu s krišku - niz elemenata od i-tog do j-tog indeksa broj elemenata u s minimalni elemenat iz s maksimalni elemenat iz s
Promjenljivi nizovi (liste) imaju mogu mijenjati članove ili kriške članova odjednom, kao i brisati članove i skupine članova. >>> a=(1,3,5,7,9) >>> print a[0], a[3] 1 7 >>> b=’ovo je string’ >>> print b[9],b[0],b[-1] r o g >>> c=[7,’marko’,-5,’kompleksni’] >>> print c[3],c[1] kompleksni marko >>> print len(a),len(b),len(c) 5 13 4 >>> print max(a), max(b), max(c) 9 v marko >>> print min(a), min(b), min(c) 1 -5 >>> print a[1:3],b[7:12],c[0:2] (3, 5) strin [7, ’marko’] >>> Treba primjetiti kako se dohvaćanje članova preko indeksa u kriškama ostvaruje od početnog indeksa do konačnog, ali koji se pritom isključuje, ne uzima u obzir. Negativan indeks pak dohvaća članove od kraja niza. Tako je ’-1’ indeks za zadnji član, ’-2’ za predzadnji i tako dalje. Budući da se u kategoriji nizova samo liste mogu mijenjati direktno, postoje pridružbe članovima liste i funkcije brisanja članova (tablica 2.5). Obje operacije mogu se izvesti nad pojedinačnim i skupnim članovima liste. Tablica 2.5: Pridružba i brisanje Član s[i] = v s[i:j] = t del s[i] del s[i:j] Evo kratkog primjera:
Opis Pridružba članu na i-tom mjestu Pridružba skupini članova Brisanje člana Brisanje skupine članova
2.3. Temeljne operacije i metode s nizovima
>>> lista=[’tko zna’,’bilje’,’siroko mu’,’polje’] >>> lista[1]=’bolje’ >>> lista [’tko zna’, ’bolje’, ’siroko mu’, ’polje’] >>> lista[1:3]=[’,zna!’] >>> lista [’tko zna’, ’,zna!’, ’polje’] >>> del lista[-1] >>> lista [’tko zna’, ’,zna!’]
2.3.1
Ugrađene metode string-ova
Budući da svaki objekt ima članove (varijable) i metode (funkcije), korisno ih je skupno prikazati (tablica 2.6), te isprobati ugrađeno. Nabrojene metode nalaze se u modulu ’string’, pa u primjerima prije njihove uporabe treba pozvati naredbu ’from string import *’
Tablica 2.6: String metode
19
20
Tipovi podataka
Metoda s.capitalize() s.center(width) s.count(sub[,start [,end]]) s.encode([encoding [,errors]]) s.endswith(suffix [,start[,end ]]) s.expandtabs([tabsize]) s.find(sub[,start[,end]]) s.index(sub[,start[,end]]) s.isalnum() s.isalpha() s.isdigit() s.islower() s.isspace() s.istitle() s.isupper() s.join(t ) s.ljust(width ) s.lower() s.lstrip() s.replace(old , new [,maxreplace ]) s.rfind(sub[,start[,end]])
Opis Pretvara svako slovo od s u veliko slovo. Centrira string u polju duljine width. Broji pojavljivanja podstringa sub u stringu s. Vraća kodiranu inačicu stringa. Provjerava kraj stringa za suffix. Proširuje tabulatore praznim mjestima. Pronalazi prvo pojavljivanje zadanog podstringa sub. Pronalazi prvo pojavljivanje zadanog podstringa sub uz podizanje izuzetka, ako ga nema. Provjerava jesu li svi znakovi alfanumerički. Provjerava jesu li svi znakovi alfabetski. Provjerava jesu li svi znakovi znamenke. Provjerava jesu li svi znakovi pisani malim slovima. Provjerava jesu li svi znakovi praznine. Provjerava jeli string pisan kao naslov (prvo slovo svake riječi napisano velikim slovom). Provjerava jesu li svi znakovi pisani velikim slovima. Povezuje stringove u listi t koristeći s kao međaš. Lijevo poravnanje s u stringu duljine width. Vraća s pretvoren u string s malim slovima. Odstranjuje prazna mjesta ispred stringa. Zamjenjuje podstring old sa new.
Nalazi zadnji pojavak podstringa sub. Nalazi zadnji pojavak podstringa sub ili javlja s.rindex(sub[,start[,end]]) izuzetak s.rjust(width) Desno poravnanje s u stringu duljine width. s.rstrip() Odstranjuje prazna mjesta iza stringa. Dijeli string koristeći sep kao međaš. s.split([sep[,maxsplit]]) maxsplit je naveći broj dijeljenja koji će se izvršiti. Dijeli string u listu linija. Ako je keepends s.splitlines([keepends]) jednak 1, čuvaju se kontrolni znakovi novih redaka. s.startswith(prefix Provjerava da li string započinje s prefix-om [,start [,end ]]) Odstranjuje prazna mjesta i ispred i iza s.strip() stringa. Vraća velika slova za string malih slova i s.swapcase() obratno. s.title() Vraća verziju stringa kao naslova. s.translate(table Mijenja string koristeći transformacijsku [,deletechars ]) tablicu znakova. s.upper() Vraća string pretvoren u velika slova.
2.3. Temeljne operacije i metode s nizovima
21
Primjer 1 String je nepromjenljivi objekt, pa se njegova promjena moguća tek stvaranjem novog stringa. treba primjetiti kako se aritmetički znak ’+’ koristi za povezivanje stringova, dok ’1:’ označuje sve znakove nakon prvog. >>> s 1 = "Moj␣ san " >>> s 2 = ’Tv ’ + s 1 [ 1 : ] >>> p r i n t s 2
Tvoj san >>>
Primjer 2 Modul ’string’ sadrži mnogo funkcija. Funkcija ’find’ pronalazi podstring u zadanom stringu. Vraća poziciju nađenog podstringa >>> >>> >>> >>> >>> >>> >>> >>>
2.3.2
import s t r i n g r i b a = " zubatac " index = s t r i n g . f i n d ( riba , " t " ) p r i n t index
4
s t r i n g . f i n d ( " abrakadabra " , " r a " ) s t r i n g . f i n d ( " abrakadabra " , " r a " , 4 ) 2 9
Ugrađene metode listi
Na sličan način, s pomoću tablice 2.7 mogu se u primjerima provjeriti ugrađene metode koje olakšavaju rad s listama. Tablica 2.7: Metode liste Metoda li.append(x) li.extend(t) li.count(x) li.index(x) li.insert(i,x) li.pop([i]) li.remove(x) li.reverse()) li.sort([cmpfunc ])
Opis Dodaje novi element x na kraj liste li. Dodaje novu listu t na kraj liste li. Broji pojavke od x u listi li. Vraća najmanji i za koji je s[i] == x . Umeće x na indeksu i . Vraća element i i briše ga iz liste. Ako se i izostavi, onda se vraća zadnji element. Traži x i briše ga iz liste li. Reverzira (obrće) članove liste li na mjestu. Sortira (slaže) članove liste li na mjestu. cmpfunc() je funkcija za usporedbu.
Primjer 3 Matrica je lista listi. >>> m a t r i c a = [ [ 1 , 2 , 3 ] , [ 2 , 3 , 1 ] ] >>> m a t r i c a [ 1 ] >>> m a t r i c a [ 0 ] [ 2 ]
[2 , 3 , 1] 3
22
Tipovi podataka
2.4
Rječnik
Preslikavanje (engl. mapping) je skup objekata indeksiranih s pomoću gotovo slobodnih vrijednosti koje se zovu ključevi (engl. keys). Tako nastali objekti su promjenljivi, a za razliku od nizova, nisu poredani. Python nudi jednu vrstu preslikavanja, rječnik (engl. dictionary). Knjižnički i ekstenzijski moduli pružaju još vrsta preslikavanja, a druge može načiniti korisnik sâm. Ključevi u rječniku mogu biti različitih tipova, ali moraju biti jednoznačni (engl. hashable). Vrijednosti u rječniku su također objekti i to mogu biti različitih tipova. Član u rječniku je par kjuč/vrijednost (engl. key/value). O rječniku se može razmišljati kao o asocijativnom polju. Eksplicitno stvaranje rječnika provodi se nizom parova ključ:vrijednost odvojenih zarezima, koji se smještaju unutar vitičastih zagrada. Dopušten je i zarez nakon zadnjeg člana. Ako se ključ pojavljuje više od jednom u rječniku, samo se jedan od članova s tim ključem sprema, jer ključ mora biti jedincat. Drugim riječima, rječnici ne dozvoljavaju duplikate ključeva. Prazan se rječnik označuje parom praznih vitičastih zagrada. Evo nekih rječnika:
{’x’:42, ’y’:3.14, ’z’:7} {1: 2, 3:4} { }
# Rjecnik s tri clana i string kljucevima # Rjecnik s dva clana i cjelobrojnim kljucevima # Prazan rjecnik
Tvorbu rječnika moguće je izvesti i s pomoću ugrađene funkcije dict(). Na primjer:
>>> dict([[’a’,12],[’b’,54]]) {’a’: 12, ’b’: 54} >>> dict(a=’zagreb’, d=’ogulin’, e=’Osijek’) {’a’: ’zagreb’, ’e’: ’Osijek’, ’d’: ’ogulin’} >>> dict([[12,’akumulator’],[’baterija’,4.5]]) {’baterija’: 4.5, 12: ’akumulator’}
dict( ) bez argumenata stvara i vraća prazan rječnik. Ako se ključ pojavljuje više nego jednom u popisu (argumentima funkcije dict), samo će se posljednji član s tim kjučem zadržati u rezultirajućem rječniku.
2.4.1
Ugrađene metode rječnika
Na sličan način, s pomoću tablice 2.8 mogu se u primjerima provjeriti ugrađene metode koje olakšavaju rad s rječnicima.
Tablica 2.8: Metode i operacije tipova preslikavanja (rječnika)
2.5. Skup
23
Član/metoda di[k] di[k] = x del di[k] di.clear() di.copy() di.has-key(k) di.items() di.keys()) di.update(b) di.values() di.get(k [,v]) di.setdefault(k[, v]) di.popitem()
2.5
Opis Vraća član od di s ključem k . Postavlja di[k] na x. Briše di[k]iz di . Briše sve članove iz di. Vraća kopiju od di. Vraća 1 ako di ima ključ k , a 0 inače. Vraća listu od (key ,value) parova. Vraća listu od vrijednosti ključeva. Dodaje sve objekte iz rječnika b u di . Vraća listu svih vrijednosti spremljenih u di . Vraća di[k] ako nađe; inače vraća v . Vraća di[k] ako nađe; vraća v i postavlja di[k]=v . Vraća slučajne (key ,value) parove kao n-terce iz di.
Skup
Od Python ver. 2.4, postoji ugrađeni tip (iako također postoji i modul s imenom ’sets’) s dvije varijante - običan i zamrznuti skup. Skup je neporedan niz jedincatih (neponavljajućih) elemenata. Elementi moraju biti jednoznačni, engl. hashable. Zamrznuti skupovi su jednoznačni, pa mogu biti elementi drugih skupova, dok obični skupovi to ne mogu biti.
Tablica 2.9: Glavne operacije skupova
24
Tipovi podataka
Operacija set/frozenset ([iterabilno=None]) Set/ImmutableSet ([iterabilno=None]) len(s elem in s / not in s for elem ins: process elem... s1.issubset(s2) s1.issuperset(s2) s.add(elem)
Rezultat [koristi se za ugrađene tipove] tvorba običnih ili zamrznutih skupova iz iterabilnog niza, npr. set([5,2,7]), set("zdravo") [koristi se za set modul] tvorba običnih ili nepromjenljivih skupova iz iterabilnog niza, npr. Set([5,2,7]) kardinalni broj skupa s Istinito ako element elem pripada / ne pripada skupu s Iterira na elementima skupa s
Istinito ako je svaki element u s1 u s2 Istinito ako je svaki element u s2 u s1 Dodaje element elem u skup s Briše element elem u skupu s. Podiže s.remove(elem)) KeyError iznimku ako se element ne pronađe Briše sve elemente iz skupa s (ne vrijedi za s.clear() nepromjenljive skupove!) s1.intersection(s2) ili Vraća novi skup s elementima zajedničkim u s1&s2 s1 i s2 Vraća novi skup s elementima koji su i u s1 i s1.union(s2) ili s1|s2 u s2. s1.symmetric_difference(s2) Vraća novi skup s elementima koji su ili u ili sl∧s2 s1,ili u s2, ali ne na oba mjesta s.copy() Vraća kopiju skupa s Dodaje sve vrijednosti iz iterabilnog niza u s.update(iterabilni niz skup s
POGLAVLJE
Izrazi, operatori i operacije 3.1
Varijable
Python pristupa podacima s pomoću referenci. Jedna takva referenca je varijabla, tj. imenovani prostor u memoriji koji čuva adresu nekog objekta ili literala. Referenca također postoji i na atribut (vrijednost) nekog objekta. Varijabla ili druga vrsta reference nemaju svoj vlastiti tip, za razliku od podatka na kojeg pokazuju, kojeg referenciraju (čiju adresu pohranjuju). Budući da je adresa jedisntvena u smislu broja okteta, svaka referenca može povezivati objekte različitih tipova i mijenjati se prilikom izvršenja programa. U Pythonu nema deklaracija. Postojanje varijable ovisi o naredbi koja povezuje (eng. binding) varijablu i podatak, ili, drugim riječima, koja postavlja ime koje da se odnosi na neki objekt. Moguće je odvezati (eng. unbinding) varijablu resetiranjem njenog imena, tako da više ne sadrži referencu. Naredba del odvezuje reference. Povezivanje reference koja je već povezana poznato je kao re-povezivanje (eng. rebinding). Repovezivanje ili odvezivanje reference nema nikakv učinak na objekt s koji je referenca bila povezana, osim što objekt nestaje ako više ne postoji nikakva referenca koja se na njega odnosi. Automatsko čišćenje objekata bez referenci zove se sakupljanje smeća (engl. garbage collecting). Varijabla se može imenovati bilo kojim identifikatorom, osim onih 30 koji su rezervirani kao Python ključne riječi. Pritom identifikator ima i neka svoja pravila: ne smije imati zabranjene simbole u sebi, ne smije počinjati brojem i sl. Varijabla može biti globalna ili lokalna. Globalna varijabla je dohvatljiva s više razina, a lokalna uglavnom u funkciji u kojoj se koristi.
3.2
Naredbe pridruživanja
Naredbe pridruživanja mogu biti obične ili proširene. Obično pridruživanje varijabli (npr. name=value) je način stvaranja nove varijable ili re-povezivanja postojeće varijable na novu vrijednost (tj. promjena vrijednosti). Obična pridružba na atribut objekta (npr. obj.attr=value) je zahtjev objektu obj da stvori ili re-poveže atribut attr. Obična pridružba za član u nekom nizu ili preslikavanju (listi ili rječniku) (npr. obj[key] = value) je zahtjev spremniku obj da stvori ili re-poveže član s indeksom key. Takva pridružba uključuje indeksiranje niza. Proširena pridružba (npr. name+=value) ne može stvoriti nove reference. Proširene pridružbe mogu samo re-povezati varijablu, narediti objekt da re-poveže jedan od svojih atributa ili članova, ili postaviti zahtjev određenom objektu da sam sebe modificira. Kad se postavi zahtjev objektu, na objektu može izvršiti zahtjev ili podignuti iznimku, kojom se javlja neka vrsta pogreške (tablica 3.1 sadrži neke osnovne iznimke). Iznimka je način na koji Python rješava pogreške bilo kojeg tipa.
25
3
26
Izrazi, operatori i operacije
Tablica 3.1: Neke osnovne ugrađene iznimke Iznimka ArithmeticError FloatingPointError OverflowError ZeroDivisionError IndentationError SyntaxError RuntimeError
3.2.1
Opis Baza za aritmetičke iznimke Pogreška floating-point operacije Aritmetički preliv Dijeljenje ili modulo operacija s 0 Pogreška uvlake Pogreška sintakse Pogreške u izvođenju programa
Obična pridružba
Naredba obične pridružbe u svom najjednostavnijem obliku ima sintaksu: cilj = izraz Cilj ili odredište (engl.target) je poznat kao lijeve strana pridružbe, a izraz (engl. expression) je desna strana. Kad se naredba pridružbe izvršava, Python izračunava izraz desne strane, te povezuje vrijednost izraza s ciljem na lijevoj strani. Ovo povezivanje ne ovisi o tipu vrijednosti. Budući da Python ne pravi velike razlike između pozivnih i nepozivnih objekata, za razliku od nekih drugih jezika, cilju su moguće pridružbe funkcija, metoda, tipova i drugih pozivnika. Cilj, na lijevoj strani, može biti varijabli /identifikator, atribut, indeksirani član niza ili kriška (engl. slicing) . Detalji povezivanja ipak ovise o tipu cilja: • Identifikator je ime varijable: pridružba na identifikator povezuje varijablu s tim imenom. • Referenca atributa ima sintaksu obj.name. Pritom je obj identifikator koji označava objekt, a name atributivno ime objekta. Pridružba na referencu atributa traži da objekt obj poveže svoj atribut zvan name. • Indeksiranje ima sintaksu obj[expr]. Pritom je obj objekt, a expr je izraz koji indeksira mjesto u nizu. Objekt može biti bilo kojeg tipa. Pridružba na indeksiranje pita spremnik obj da poveže svoj član koji je izabran pomoću vrijednosti expr, također poznate i kao indeksni ključ člana. • Kriška (eng. slicing) ima sintaksu obj[start:stop] ili obj[start:stop:korak]. Pritom je Obj objekt, a start, stop i korak su izrazi koji koji indeksiraju dio niza objekata. (Dopušteno je izostavljanje članova, pa je obj[:stop:] sintaksno ispravna kriška, ekvivalentna s obj[None:stop:None]). Pridružba traži od niza objekata obj da se povežu ili odvežu neki od njegovih članova. U jednostavnoj pridružbi može biti više ciljeva i znakova jednakosti (=). Na primjer: a = b = c = 0 povezuje varijable a, b, i c sa vrijednosti 0. Svaki cilj se povezuje s jednim objektom koji vraća izraz, isto kao kad bi se nekoliko jednostavnih naredbi izvršavale jedna za drugom. Cilj u jednostavnoj pridružbi može imati dvije ili više referenci odvojenih zarezima, proizvoljno ograđenih lučnim ili kutnim zagradama. Na primjer: a, b, c = x Ovo zahtijeva da x bude niz od tri člana, te povezuje a s prvim članom, b s drugim, te c s trećim. Ova vrsta pridružbe zove se raspakiravajuća pridružba i pritom izraz s desne strane mora biti niz s točnim brojem članova koliko ima i referenci u cilju, jer se inače podigne iznimka. Svaka referenca u cilju je jednoznačno povezana s odgovarajućim članom u nizu. Raspakiravajuća pridružba također može izmjenjivati reference: a, b = b, a Ovaj izraz repovezuje a da se pridruži na ono što je u b bilo povezano, i obratno.
3.2. Naredbe pridruživanja
3.2.2
27
Proširena pridružba
Proširena pridružba razlikuje se od obične pridružbe u tomu, što se umjesto znaka jednakosti (=) između cilja i izraza s desne strane koristi prošireni operator, tj. binarni operator nakon kojeg slijedi =. Operatori proširene pridružbe su: + =,− =, ∗ =, / =, // =, % =, ∗∗ =, | =, >>=, <<=, & = i ∧ =. Proširena pridružba (tablica 3.2) može imati samo jedan cilj na lijevoj strani, tj. proširena pridružba ne podržava više ciljeva.
Tablica 3.2: Proširena pridružba Operacija x+ = y x− = y x∗ = y x/ = y x∗∗=y x% = y x& = y x| = y x∧ = y x >>= y x <<= y
3.2.3
Ekvivalentno sa x=x+y x=x−y x=x∗y x = x/y x = x ∗ ∗y x = x%y x = x&y x = x|y x=x∧y x = x >> y x = x << y
Naredba del
Unatoč svome imenu, naredba del ne briše objekte, nego odvezuje reference. Brisanje objekta je implicitno moguće kao posljedica, sa sakupljanjem smeća, ako ne postoji više nijedna referenca na objekt. U Pythonu (slično kao u Java programskom jeziku) postoji ugrađeni sakupljač smeća (engl. garbage collector ) koji oslobađa memorijski prostor zauzet objektima koji se ne referenciraju. To se događa na sistemskoj razini, ciklički, tijekom izvođenja programa. Naredba del se sastoji od ključne riječi del, nakon koje slijedi jedna ili više ciljnih referenci razdvojenih zarezima (,). Svaki cilj može biti varijabla, referenca atributa, indeksiranje ili kriška, baš kao za naredbe pridružbe i mora biti povezan u vrijeme izvršavanja naredbe del. Ako je cilj del-a identifikator, naredba del specificira odvezivanje varijable. Dok god je identifikator povezan s objektom, odvezivanje je dopušteno: kada se zahtijeva, onda se i izvrši. U svim drugim slučajevima, naredba del specificira zahtjev objektu da odveže neke (ili sve) svoje atribute ili članove. Objekt može odbiti odvezati neke (ili sve) atribute ili članove, podižući iznimku ako se pokušava nedopušteno odvezivanje. Odvezivanje (ili brisanje) kriške obično ima jednak učinak kao zadavanje praznog niza toj kriški.
3.2.4
Bool -ove vrijednosti
Poslije Pythona ver. 2.3 postoji eksplicitna verzija Bool -ove (engl. boolean) vrijednosti za Python. Bool ove vrijednosti True i False postaju tip (podklasa od int). U ranijim Python verzijama označavale su se s ’1 ’ i ’0’. Svaka podatčana vrijednost u Pythonu ima vrijednost istine: istinito ili lažno, ovisi o tomu je li ta vrijednost različita ili jednaka nuli. U stringu nuli odgovara prazan string "", kod n-terca prazan n-terac (), kod rječnika prazan rječnik i sl. Python također ima nekoliko ugrađenih funkcija koje vraćaju Bool -ove vrijednosti kao rezultate. Promjene su bile praktične, jer je lakše govoriti o funkcijama i izrazima koje "vraćanje True ili False" nego izraza različitih ili jednakih nuli. Ove promjene također omogućuju pisanje čišćeg kôda, kada se želi vratiti vrijednost istine (npr. return True umjesto return 1).
28
Izrazi, operatori i operacije
3.3
Operatori i operacije
Izraz je fraza programskog kôda koju Python interpreter može izvršiti kako bi proizveo neku vrijednost. Najjednostavniji izrazi su literali i identifikatori (varijable). Složeniji izrazi grade se tako da se jednostavni izrazi povezuju operatorima. Tablica 3.3 opisuje operatore po prioritetima, od viših prema nižima. Operatori koji su zajedno imaju jednak prioritet. Stupac A ispisuje asocijativnost (djelovanje s obzirom na stranu) operatora, koja može biti L (s lijeva na desno), D (s desna na lijevo) ili NA (neasocijativna). Na primjer, operator ’<’ nije asocijativan, jer bi x < y se promjenom mjesta identifikatora (y < x)dobio sasvim suprotan rezultat. Tablica 3.3: Prioritet operatora u izrazima Operator ’izraz,...’ key:izraz,... [izraz,...] (izrazr,...) f(izraz,...) x[index1:index2] x[index] x.attr x**y x +x, -x x*y, x/y, x//y, x%y x+y, x-y x«y, x»y x&y x∧y x|y x < y, x <= y, x > y, x >= y, x <> y, x! = y, x == y x is y, x is not y x in y, x not in y not x x and y x or y lambda arg,...: izraz
Opis String pretvorba Stvaranje rječnika Stvaranje liste Stvaranje n-terca ili jednostavne zagrade Poziv funkcije Kriška (slicing) Indeksiranje (indexing) Referenca atributa Eksponent (x na y potenciju) Bitwise NE (NOT) Unarni plus ili minus Množenje, dijeljenje, dijeljenje na cijeli broj, ostatak Zbajanje, oduzimanje Lijevi pomak, desni pomak Bitwise I (AND) Bitwise eksluzivni ILI (XOR) Bitwise ILI (OR)
A NA NA NA
Usporedbe
NA
Provjera identiteta Provjera članstva Bool-ov NE (NOT) Bool-ov I (AND) Bool-ov ILI (OR) Anonimna jednostavna funkcija
NA NA NA L L
NA L L L L D NA NA L L L L L L
NA
Operatori usporedbe mogu se nizati, čime se implicira logična I (and) funkcija. Na primjer: a < b <=
c < d
ima isto značenje kao i: a < b
and
b <= c
and
c < d
Oblik niza je mnogo čitljiviji i provjerava svaki podizraz samo jednom.
3.3. Operatori i operacije
3.3.1
29
Numeričke i aritmetičke operacije
Python pruža uobičajene numeričke operacije, kako se vidi u tablici 3.4. Svi su brojevi samočitajući (engl. readonly) objekti, pa bilo koja numerička operacija na brojevnom objektu, uvijek proizvodi novi brojevni objekt. Objekt kompleksnog broja z također ima samočitajuće (atribute z.real i z.imag. Pokušaj repovezivanja ovih atributa na kompleksnom objektu podiže iznimku. Treba primjetiti da + ili - znak nekog broja, kao i znak + koji pridružuje decimalni literal imaginarnom broju kako bi se načinio kompleksan broj, nisu dijelovi sintakse literala. Iz tog razloga se na primjer, -2 ** 2 izračunava kao -4, jer potenciranje ima viši prioritet od znaka minusa, pa se cijeli izraz prevodi kao -(2 ** 2), a ne kao (-2) ** 2. Tablica 3.4: Numeričke operacije Operacija x+y x−y x∗y x/y x ∗ ∗y x%y −x +x
Opis Zbrajanje Oduzimanje Množenje Dijeljenje Potenciranje (x ∧ y) Modulo funkcija (x mod y ) Unarni minus Unarni plus
Ugrađena divmod funkcija uzima dva argumenta i vraća par čiji su članovi kvocijent i ostatak, što je jednostavnije nego koristiti operator // za cjelobrojno dijeljenje i % za ostatak (tablica 3.5). Ugrađena pow(a,b) funkcija vraća isti rezultat kao i a**b. Sa tri argumenta, pow(a,b,c) vraća isti rezultat kao i (a**b) % c, ali brže. Tablica 3.5: Ugrađene aritmetičke funkcije Funkcija abs(x) divmod(x,y) pow(x,y [,modulo]) round(x,[n])
3.3.2
Opis Apsolutna vrijednost Vraća (int(x / y ), x % y ) Vraća (x ∗ ∗y)x%modulo Zaokružuje na najbliži višekratnik od 10−n (samo za za realne brojeve)
Prisilna i eksplicitna pretvorba
Arithmetičke operacije i usporedbe mogu se primijeniti između bilo koja dva broja. Ako se tipovi operanda razlikuju, primjenjuje se prisila: Python prepravlja operande iz manje tipa u veći. Poredani od najmanjeg do najvećeg brojevni tipovi su sljedećei: cijeli brojevi, dugački cijeli brojevi, decimalni (realni, s pomičnim zarezom) brojevi i kompleksni brojevi. Eksplicitna pretvorba može se primijeniti tako da se numerički argument preda željenoj ugrađenoj funkciji: int, long, float te complex. U tom slučaju int i long će odbaciti decimalni dio svog argumenta i zadržati samo cijeli, npr. int (9.8) je 9. Konverzija pak kompleksnog broja na bilo koji drugi tip broja, odbacuje imaginarni dio. Za tvorbu kompleksnog broja moguće je pozvati ugrađenu funkciju complex s dva argumenta, koji predstavljaju realni i imaginarni dio. Funkcije Int i long također se mogu pozvati s dva argumenta: prvi je niz znakova za pretvorbu, a drugi baza (radix), tj. cijeli broj između 2 i 36 kao baza za pretvorbu (npr. int(’1101’,2) vraća 13, vrijedost ’1101’ u bazi 2).
30
Izrazi, operatori i operacije
3.3.3
Usporedba
Svi objekti, uključujući brojeve, mogu se uspoređivati s obzirom na jednakost (==) i nejednakost (!=). Usporedbe koje zahtijevaju poredak (<, <=, >, >=) mogu se koristiti između bilo koja dva broja osim kompleksnih, jer se kod njih javljaju ’runtime’ iznimke. Svi takvi operatori vraćaju Bool-ove vrijednosti (True ili False), kako je pokazano u tablici 3.6. Tablica 3.6: Operatori usporedbe Operator x x x x x x
3.3.4
< y > y == y != y >= y <= y
Opis Manje nego Veće nego Jednako Nije jednako (isto kao <>) Veće nego ili jednako Manje nego ili jednako
Operacije na bitovima cijelih brojeva
Cijeli brojevi i dugački cijeli brojevi se mogu promatrati kao nizovi bitova i koristiti u operacijama s bitovima prikazanima u Tablici 3.7. Operatori na bitovima imaju niži prioritet nego arithmetički operatori. Pozitivni cijeli brojevi su prošireni neograničenim nizom bitova 0 nalijevo. Negativni cijeli brojevi su predstavljeni dvojnim komplementom, te su tako prošireni neograničenim nizom bitova 1 nalijevo. Tablica 3.7: Operacije na bitovima cijelih brojeva Operacija x « y x » y x & y x | y x∧y ∼x
Opis Lijevi pomak (shift) Desni pomak (shift) Bitwise I (and) Bitwise ILI (or) Bitwise EX-ILI (xor - exclusive or) Bitwise negacija
Osim pomaka (ulijevo i udesno) na bitovima se mogu izvršavati i logičke funkcije (I, ILI, NOT i EX-ILI).
3.4
Operacije na nizovima
Python podržava nekoliko operacija koje se mogu primijeniti na slijedne tipove (nizove ili sekvence), koji uključuju nizove znakova (stringove), popise ili liste (list) i n-terce (tuple). Nizovi su spremnici s članovima koji su dostupni indeksiranjem ili kriškama. Nizovi istog tipa povezuju se operatorom +. Isto tako moguće je množiti bilo koji niz S s cijelim brojem n pomoću operatora *. Rezultat S*n ili n*S je povezivanje n kopija od S. Ako je n nula ili manje od nule, razultat je prazan niz istog tipa kao S. U nastavku se promatraju liste, ali ista zapažanja vrijede i za stringove i n-terce. Jedina razlika je što se, za razliku od listi, n-terci i stringovi ne mogu mijenjati. x in S operator provjerava je li objekt x jednak bilo kojem članu u nizu S. Ako jest, vraća True, a False ako nije. Slično tomu, x not in S operator je isto kao not(x in S). N-ti član niza S označuje se ili dohvaća indeksiranjem S[n]. Indeksiranje u Pythonu počinje od nule (prvi član u S je S[0]). Ako S ima L članova, indeks n smije biti 0,1,.., sve do L-1 uključno, ali ne i više. Indeks n može također biti -1, -2,..., sve do -L (isključno), ali ne i manji. Negativni n
3.4. Operacije na nizovima
31
označava iste članove u S kao što čini L+n. Drugim riječima, S [-1] je posljednji element od S, S[-2] je pretposljednje itd... Na primjer: x = [1,2,3,4] x[1] x[-1]
# 2 # 4
Korištenje indeksa većeg ili jednakog L ili manjeg od -L podiže (izaziva) iznimku. Pridružba članu niza s nepostojećim indeksom ima isti učinak.
3.4.1
Kriška (eng. slicing ) niza
Podniz S može se označiti s pomoću kriške, korištenjem sintakse S[i:j], gdje su i i j cijeli brojevi. S[i:j] je podniz S od i-tog člana do j-tog člana, ali ne uključujući ga. Treba primjetiti kako u Pythonu svi dosezi uključuju donju i isključuju gornju granicu. Kriška može biti prazan podniz ako je j manje od i ili ako je i veće ili jednako L, duljini niza S. Ako je j jednako nuli, i se može izostaviti, a ako se ide do konca niza (L) onda se i j smije izostaviti. Cijeli niz S može se dakle indeksirati sa S[:]. Bilo koji ili oba indeksa smiju biti manji od nule. Negativni indeks označuje mjesto u nizu s obzirom na kraj niza. Evo nekih primjera: x = [1, 2, 3, 4] x[1:3] # [2, 3] - ne zaboraviti da prvi \v{c}lan niza ima indeks jednak 0 x[1:] # [2, 3, 4] x[:2] # [1, 2] Kriška također može koristiti proširenu sintaksu S[i, j, k], gdje je k - korak indeksa. Liste mogu mijenjati svoje članove pridružbom izraza indeksiranom članu. Na primjer: x = [1, 2, 3, 4] x[1] = 42
# x je sada [1, 42, 2, 3]
Drugi način promjene objekata liste L je korištenjem kriške od L kao cilja (lijeva strana) uz naredbu pridružbe desne strane. Desna strana pritom također mora biti lista. Kriška s lijeve strane i lista s desne mogu biti bilo koje duljine, što znači da pridruživanje kriške može dodavati članove liste ili ih brisati. Na primjer: x = [1, 2, 3, 4] x[1:3] = [22, 23, 44] x[1:4] = [2, 3]
# x je sada [1, 22, 33, 44, 4] # x se vratio na [1, 2, 3, 4]
Evo nekih važnih posebnih slučajeva: • Koristeći praznu listu [ ] kao izraz s desne strane, briše se ciljna kriška iz liste L s lijeve strane. Drugim riječima, L[i:j] = [ ] ima isti učinak kao i del L[i:j]. • Koristeći praznu krišku liste L kao cilj s lijeve strane pridružbe ubacuju se članovi liste s desne strane na primjerenu poziciju u L. Drugim riječima, L[i:i] = [’a’,’b’] ubacuje članove ’a’ i ’b’ nakon člana i u listi L. • Koristeći krišku koja pokriva cijeli objekt liste L[:], kao cilj s lijeve strane, potpuno se zamjenjuje sadržaj liste L. Član ili dio (kriška) liste može se izbrisati naredbom del. Na primjer: x = [1, 2, 3, 4, 5] del x[1] # x je sada [1, 3, 4, 5] del x[1:3] # x je sada [1, 5]
32
Izrazi, operatori i operacije
3.4.2
Stacionarne operacije na listi i rječniku
Za liste su definirane stacionarne (in-line) verzije operatora + i *, koji se koriste u proširenim naredbama pridružbe. Proširena naredba pridružbe L+=L1 ima učinak dodavanja člana iz liste L1 na kraj liste L, dok L*=n ima učinak dodavanja n broja kopija liste L na kraj L. Metoda popitem() se može koristiti za destruktivnu iteraciju dnevnika, tj. iterativnim dohvaćanjem člana briše se njegov ključ i vrijednost u rječniku. Pritom i item() i popitem() vraćaju dnevničke članove kao parove ključ/vrijednost, ali korištenje funkcije popitem() upotrebljava manju količinu memorije. Uštede na korištenju memorije čine tu metodu korisnom za petlju po dugom rječniku. U Pythonu 2.2 i kasnije, izravno iteriranje na rječniku postiže se iterkeys() ili iteritems() metodama koji traže skromnu količinu memorije i ne uništavaju rječnik po kojemu se iteracija obavlja.
3.5
Naredba Print
Naredba za ispis označava se s ključnom riječi print nakon koje slijedi niti jedan ili više izraza odvojenih zarezima. Print je praktičan i jednostavan način ispisivanja vrijednosti u tekstovnom obliku. Print ispisuje na zaslon računala svaki izraz x kao niz znakova što je isto kao kad bi se prethodno pozvala funkcija str(x) koja bi ekslicitno tip podatka, npr. broja pretvorila u string. Print implicitno izbacuje razmak između izraza, i također implicitno uključuje novi red (\n) nakon posljednjeg izraza, osim u slučaju kad iza posljednjeg izraza slijedi zarez. Evo nekih primjera naredbe print: slovo = ’c’ print "daj mi ", slovo, "..." odgovor = 100 print "Odgovor je:", odgovor
# ispisuje:
daj mi c ...
# ispisuje:
Odgovor je:100
Odredište izlaza naredbe print je datoteka ili objekt sličan datoteci koji ima vrijednost stdout atributa u sys modulu. Obično je stdout pridružen zaslonu računala, ali se isto tako može pridružiti drugom objektu ili izlaznoj napravi. Format ispisa može se preciznije kontrolirati uporabom operatora % ili drugim tehnikama obradbe nizova znakova. Također je moguće koristiti write ili writelines metode datotečnih objekata.
POGLAVLJE
Programsko upravljanje Programsko upravljanje tokom izvođenja je redoslijed po kojem se programski kôd izvršava. Ovo upravljanje u Python programima, kao i u drugim programskim jezicima, temelji se na uvjetnim naredbama, petljama i pozivima funkcija.
4.1
Naredba if
Često se neka naredba ili niz (blok) naredbi treba izvršiti samo u slučaju ako je neki uvjet zadovoljen. Ponekad je to izvršavanje ovisno o nekoliko međusobno povezanih uvjeta. Pythonova kombinirana naredba if, koja koristi proširenja elif ili else služi za takvo uvjetno izvršavanje naredbi. Sintaksa za naredbu if izgleda ovako: if
uvjet(i): naredba(e) elif uvjet(i): naredba(e) elif uvjet(i): naredba(e) ... else uvjet(i): naredba(e) gdje uvjet(i) predstavlja jedan ili više uvjetnih izraza povezanih odnosnim (relacijskim) operatorima. Proširenja naredbe ’if ’ s ’elif ’ i ’else’ su dopuštene u slučaju ispitivanja više različitih uvjeta. ’Elif’ je kratica od ’else-if’, što znači ’inače-ako’, čime se prvo ispitivanje uvjeta proširuje na iduće. Ako niti jedan od uvjeta nije zadovoljen izvode se naredbe iza ’else’, ako postoji. Treba primjetiti kako, razliku od nekih jezika, Python nema naredbu switch, pa se moraju koristiti if, elif ili else za sve uvjetne obrade. Evo tipične naredbe if:
if x < 0: print "x je negativan" elif x % 2: print "x je pozitivan i neparan" else: print "x je paran i nije ne-negativan" Kada u ’ako’ ili ’inače’ odlomku ima više naredbi (npr. naredba se odnosi na čitav blok naredbi), naredbe su postavljene na razdvojene logičke linije nakon što linija koja sadrži ključnu riječ odlomka (poznatu kao početna linija odlomka) je pomaknuta udesno od linije početka. Blok završava kada se pozicioniranje vrati na ono od početka odlomka (ili još dalje lijevo od toga). Kada postoji jedna 33
4
34
Programsko upravljanje
jednostavna naredba, kao u gornjem primjeru, onda se ona piše na istoj logičkoj liniji neposredno iza dvotočja (’:’) kojim se završava jedan ili više uvjetnih ispitivanja. Dakako, moguće ju je napisati i na idućoj logičkoj liniji, ali se onda mora koristiti uvlaka. Mnogi koji rade u Pythonu smatraju stil odvojenih linija čitljivijim od onog u drugim programskim jezicima: if x < 0 print "x je negativan" elif x % 2: print "x je pozitivan i neparan" else: print "x is paran i ne-negativan" Kao uvjet u if ili elif odlomku može se koristiti bilo koji Python-ov izraz . Pritom se vrijednost izraza promatra u Bool-ovom kontekstu, gdje se svaka vrijednost uzima kao istinita, ili neistinita. Svaki broj koji nije nula ili niz znakova koji nije prazan, isto kao i n-terac, lista ili rječnik, izračunava se kao istinito (True). Nula (bilo kojeg brojevnog tipa), None i prazni stringovi, n-terci, liste i rječnici, izračunavaju se kao neistina (False). Kada se pak želi ispitati vrijednost x-a u Bool-ovom kontekstu, preporučuje se sljedeći stil kodiranja: if x: To je najčišći i ’najpython-skiji’ oblik. Nije potrebno koristiti konstrukcije kao: if x is True: if x == True: if bool(x) : ili slično. Postoji osnovna razlika između izjave da izraz "vraća True" (što znači da izraz vraća vrijednost kao Bool-ov rezultat) i izjave da se izraz "izračunava (evaluira) kao istinit" (što znači da izraz vraća bilo kakav rezultat koji je istinit u Bool-ovom kontekstu). Kad se testira izraz, brine se o ovom drugom uvjetu, a ne prvom. Ako se izraz za if odlomak izračuna kao istinit, naredbe koje slijede if odlomak se izvršavaju i cijela naredba if završava. Inače se izvršavaju izrazi za iduće elif odlomke, ako su uvjeti ispunjeni. Za prvu elseif klauzulu za koju je uvjet istinit, izvršavaju se sve narede koje je slijede i čitava naredba if time završava. U protivnom, ako niti jedan odlomak nije bio obrađen, jer uvjeti nisu bili zadovoljeni, onda se izvršavaju naredbe odlomka else, ako postoji.
4.2
Naredba while
Naredba while u Pythonu podržava ponavljajuće izvršavanje naredbe ili bloka naredbi koji je upravljan uvjetnim izrazom. Ovo je sintaksa za naredbu while: while izraz: naredba(e) While naredba također može uključivati klauzulu else i naredbe break. Tipična uporaba naredbe while: count = 0 while x > 0: x = x // 2 # cjelobrojno dijeljenje count += 1 print "Aproksimacija log2 je", count
4.3. Naredba for
35
Prvo se evaluira izraz poznat kao uvjet petlje (eng. loop condition). Ako je uvjet lažan (false), naredba while završava. Ako je uvjet petlje zadovoljen, naredba ili naredbe od kojih se sastoji tijela petlje se izvršavaju. Kada tijelo petlje završi s izvršavanjem, uvjet se ponovno evaluira, izračunava, da se vidi treba li se izvršiti nova iteracija. Ovaj se proces nastavlja sve dok uvjet petlje ne postane lažan, nakon čega while naredba završava. Tijelo petlje treba sadržavati kôd koji će u nekom trenutku učiniti petljin uvjet lažnim, ili petlja nikada neće završiti, osim ako se ne podigne iznimka ili tijelo petlje ne izvrši naredbu break. Petlja koja je napisana u tijelu funkcije također završava ako se naredba return izvrši unutar tijela petlje, jer u tom slučaju cijela funkcija završava.
4.3
Naredba for
Naredba for u Pythonu ostvaruje iterativno izvršavanje naredbi ili bloka naredbi, a upravlja se preko iteracijskog izraza. Sintaksa za naredbu for je: for cilj in nizu: naredba(e) Treba primjetiti da je ključna riječ in dio sintakse naredbe for. Ona nije povezana s operatorom in koji se koristi pri ispitivanju članova u nizovima. Naredba for također može uključivati i odlomak else i naredbu break. Tipična primjer uporabe naredbe for je: for znak in "dobar dan": print "slovo: ", znak,
"..."
što će kao rezultat dati: slovo: slovo: slovo: slovo: slovo: slovo: slovo: slovo: slovo:
d o b a r
... ... ... ... ... ... d ... a ... n ...
Iteracijski niz u ovom slučaju je string, pa varijabla znak u svakom prolazu, iteraciji, poprima vrijednost pojedinog člana tog niza, u ovom slučaju pojedinačnog slova. U ovom primjeru izvršava se samo jedna naredba, naredba print, koja ispisuje sadržaj upravljačke varijable s pripadnim formatiranjem (’slovo:’ ispred i ’...’ iza sadržaja). Iteracijski niz može biti bilo koji Pythonov izraz koji se može iskoristiti kao argument ugrađenoj funkciji iter, koja vraća iteratorski objekt. Cilj pridružbe iteracijske varijable je obično identifikator koji imenuje varijablu petlje, a naredba for slijedno repovezuje ovu varijablu na svaki član po redu unutar iteratora. Naredba ili naredbe od kojih se sastoji tijelo petlje izvršavaju se jedna po jedna za svaki član unutar iteratora (osim ako petlja završi uslijed podizanja iznimke ili izvršenja naredbe break ili return). Cilj s više identifikatora je također dopušten, kao kad se radi o pridružbi prilikom raspakiravanja. U tom slučaju, iteratorovi članovi moraju biti nizovi, svaki iste duljine jednake broju identifikatora unutar cilja. Na primjer, ako je d rječnik, ovo je uobičajeni način dohvaćanja člana u rječniku d: for key, value in d.items(): # dohvatiti samo istinite (pune) kljuceve i vrijednosti if not key or not value: del d[key]
36
Programsko upravljanje
Metoda items() vraća popis parova ključ/vrijednost, pa stoga for petlja koristi dva identifikatora u cilju da se svaki član razpakira u par ključ/vrijednost. Ako iterator sadrži promjenljiv objekt unutar samoga sebe, onda se taj objekt ne smije mijenjati dok se for petlja obavlja. Na primjer, predhodni primjer ne može koristiti iteritems() umjesto items. Naime, iteritems() vraća iterator čiji je sadržani objekt d, pa tijelo petlje ne može mijenjati d (sa del d[key]). S druge strane, items() vraća listu, tako da d nije sadržani objekt, pa tijelo petlje može mijenjati d. Upravljačka varijabla može se repovezati u tijelu petlje, ali se ponovno repovezuje na slijedeći član u iteratoru sa sljedećom iteracijom petlje. Tijelo petlje uopće se ne izvršava ako iterator ne oslobađa nikakve članove. U tom slučaju, upravljačka varijabla se ne povezuje ili reovezuje na niti jedan način pomoću naredbe for. Međutim, ako iterator oslobađa barem jedan član, kad se naredba petlje završi, upravljačka varijabla ostaje povezana na posljednju vrijednost na koju ju je naredba petlje povezala. Zato je sljedeći kôd ispravan, dok god neki-niz nije prazan. for x in neki-niz: obradi(x) print "Posljednji obradjeni \v{c}lan je: ",
4.4
x
Iteratori
Metode items(), keys() i values() vraćaju njihove rezultantne liste bilo kojim redoslijedom. Ako se pozove više od jedne od ovih metoda bez bilo kakve izmjene na rječniku, redoslijed rezultata je identičan za sve. Metode iteritems(), iterkeys()i itervalues(), koje su uvedene u Pythonu od inačice 2.2, vraćaju iteratore ekvivalentne tim listama. Iterator zauzima manje memorije od liste, ali nije dozvoljena promjena rječnika dok se iterira na jednom od njegovih iteratora. Iteriranje na listi vraćenoj sa items(), keys() ili values() dolazi bez takvih restrikcija. Iteriranje direktno na dnevniku D je isto kao iteriranje na D.iterkeys(). Tablica 4.1: Metode rječničkog objekta Metoda D.iteritems( ) D.iterkeys( ) D.itervalues( )
Opis Vraća iterator za sve članove (key/value parove) u D Vraća iterator za sve ključeve u D Vraća iterator za sve vrijednosti u D
Iterator je bilo koji objekt i takav da se može pozivati sa i.next() bez argumenata. Naredba i.next() vraća sljedeći član iteratora i ili, kada iterator i više nema članova, podiže StopIteration iznimku. Također se može dopustiti instancama klase da budu iteratori, definirajući u klasi takvu metodu next. Većina je iteratora izgrađena eksplicitnim ili implicitnim pozivima ugrađene funkcije iter. Pozivanje generatora također vraća iterator. Naredba for implicitno poziva iter da bi dobila iterator. Sljedeća naredba: for
x in clanovi: naredba(e)
je ekvivalentna s: _temporary_iterator = iter(clanovi) while True: try: x = _temporary_iterator.next ( except StopIteration: break naredba(e)
)
4.5. Funkcije range i xrange
37
Ako iter(clanovi) vraća iterator i tako da naredba i.next nikada ne podigne StopIterationiznimku (beskonačan iterator), petlja for x in clanovi: nikada ne završava (osim kad naredbe u tijelu petlje sadržavaju prikladne break ili return naredbe ili iznimke). iter(clanovi) poziva posebnu metodu c._iter_() da se dobije i vrati iterator na clanovi. Zahvaljujući iteratorima, naredba for se može koristiti na spremniku (kontejneru) koji nije niz znakova, poput rječnika, sve dok god je kontejner iterabilan (tj., definira _iter_ posebnu metodu tako da funkcija iter može prihvatiti kontejner kao argument i vratiti iterator na taj kontejner). Ugrađene funkcije koje su prije zahtjevale argumentni niz sad prihvaćaju bilo koji iterabilni objekt.
4.5
Funkcije range i xrange
Ponavljanje petlje preko niza cijelih brojeva čest je slučaj, pa zato Python pruža ugrađene funkcije range i xrange koje generiraju i vraćaju nizove cjelih brojeva. Najjednostavniji način da se zavrti petlja od n puta u Pythonu je: for i in xrange(n): naredba(e) range(x) vraća popis ili listu čiji članovi su sljedni cijeli brojevi od 0 (uključeno) do x (isključeno). Funkcija range(x,y) vraća popis čiji članovi su su sljedni cijeli brojevi od x (uključeno) do y (isključeno). Ako je x veći ili jednak y, onda je rezultat prazna lista . range(x,y,step) vraća popis cijelih brojeva od x (uključeno) do y (isključeno), tako da je razlika između svaka dva susjedna člana u popisu step. Ako je korak (eng. step) manji od 0, range odbrojava od x do y. Funkcija range vraća prazan popis kada je x veći ili jednak y, a korak je veći od 0, ili kada je x manji ili jednak y i korak je manji od 0. Ako je korak jednak 0, onda range podiže iznimku. Dok range vraća standardni objekt liste koja se može koristiti za bilo koju svrhu, xrange vraća objekt za posebne svrhe, posebno namijenjen korištenju u iteracijama kao naredba for pokazana ranije. Xrange uzima manje memorije od range-a za ovu specifičnu namjenu. Stavljajući na stranu potrošnju memorije, range se može koristiti u iste svrhe kao i xrange.
4.6
Sažete liste
Česta svrha for petlje je provjeravanje svakog člana unutar niza i tvorba nove liste dodajući rezultate izraza izračunatog na jednom ili svim članovima koji se provjeravaju. Oblik izraza, zvan sažeta lista (eng. list comprehension) omogućuje točno i neposredno izvršavanje ove zadaće. Kako je sažeta lista izraz (a ne blok naredbi), može se ga koristiti izravno (npr. kao stvarni argument u funkciji poziva, zatim u naredbi return ili kao podizraz za neki drugi izraz). Sažeta lista ima sljedeću sintaksu: [izraz
for
cilj
in
iter-clanovi
lc-odlomci]
gdje su cilj i iter-clanovi identični kao i u običnoj for naredbi. Izraz se može ograditi i okruglim, oblim zagradama, ako predstavlja n-terac. lc-odlomci je niz od nula ili više odlomaka, od kojih je svaki sličan obliku: for cilj in iter-clanovi if izraz Izraz unutar svake if klauzule ima istu sintaksu kao izraz običnoj if naredbi. Sažeta lista je ekvivalentna petlji for koja gradi istu listu ponavljajućim pozivima append metode rezultantne liste. Na primjer: result1 = [x+1 for x in neki_niz] jednak je kao sljedeća for petlja:
38
Programsko upravljanje
result2 = [ ] for x in neki_niz result2.append (x+1) Sažeta liste koji koristi if odlomak izgleda ovako: result3 = [x+1 for x in neki_niz if x<100] a to je identično for petlji koja sadrži naredbu if: result4 = [ ] for x in prva-lista: for y in druga lista: result6.append (x+y) Kao što ovi primjeri pokazuju, redoslijed naredbi for i if u sažetoj listi jednak je kao u ekvivalentnoj petlji, ali u sažetoj listi gnježdenje operacija ostaje implicitno.
4.7
Naredba break
Naredba break se dopušta jedino unutar tijela petlje. Kada se break izvrši, petlja završava. Ako je petlja smještena unutar drugih petlja, break završava jedino petlju koja je smještena najdalje unutra. U praktičnom korištenju, break naredba je obično unutar nekog odlomka u naredbi unutar tijela petlje, tako da se izvršava uvjetno. Jedno uobičajeno korištenje naredbe break je u implementaciji petlje koja odlučuje hoće li se izvršavati samo u sredini svake iteracije: while True: # ova petlja ne bi nikad prirodno zavr\v{s}ila x = get_next( ) y = preprocesses (x) if not keep_looping (x, y): break process (x, y)
POGLAVLJE
Iznimke Tri glavne vrste pogrešaka mogu nastati unutar programa: logičke pogreške, sintaktičke pogreške, te pogreške u radu tijekom izvođenja programa (eng. run-time errors). Logička pogreška, poput neispravnog algoritma, uzrokuje netočne rezultate, ali ne spriječava izvođenje programa. Ovakve se pogreške teško mogu uočiti. Sintaktička pogreška krši jedno od Pythonovih gramatičkih pravila i spriječava izvođenje programa. Ove je pogreške lako popraviti. Pogreška u radu je pogreška kod izvršenja koja se događa dok je program u nekoj operaciji. Neki česti uzroci pogrešaka u radu su neprimjereni ulazni podaci, arithmetičke pogreške, neispravne vrste objekata, nizovi indeksa izvan dometa, nepostojeći ključevi rječnika, nepravilno ispisana imena atributa, neinicijalizirane varijable, te problemi vezani uz operacijski sustav. Iako to ne pomaže u slučaju logičkih pogrešaka, Python podiže iznimku (engl. exceptions)pri otkrivanju sintaktičkih pogrešaka ili pogrešaka tijekom izvođenja programa. Interpreter zaustavlja program te ispisuje dijagnostičku poruku o pogrešci, zvanu "traceback ", koja ukazuje na vrstu iznimke te pokazuje približno mjesto pogreške. Sintaksne pogreške su najčešće pogreške u pisanju programa,a na njih upozorava Python prilikom izvođenja programa na način da na mjesto na kojem je greška pokazuje „strelicom“. >>> while True print Pozdrav svima’ File "", line 1, in ? while True print ’Pozdrav svima’ ^ SyntaxError: invalid syntax Kada je program sintaksno dobro napisan, postoji mogućnost da se druge pogreške jave prilikom izvođenja programa. Iznimka je način na koji Python dohvaća i pogreške tog tipa.
5.1
Vrste iznimki
Python organizira iznimke po hijerarhijskom stablu. Tablica 5.1 ispisuje i opisuje sve ugrađene iznimke. Sve vrste iznimki su Python klase. Na vrhu stabla iznimki je Exception, iz kojega su izvedene sve druge ugrađene iznimke. Exception je roditelj ili temelj dvaju nasljednika: SystemExit i StandardError. Funkcija sys.exit() generira iznimku SystemExit koja se može dohvatiti kod eksplicitnog zatvaranja programa. (SystemExit je iznimka ali ne i pogreška). StandardError je roditelj svih drugih iznimki. Ovakav hijerarhijski ustroj omogućuje otkrivanje i obradu skupnih, a ne samo individualnih iznimki. Na primjer, ako postoji skupina iznimki koje obrađuju matematičke izračune, onda se može prvo dohvatiti samo ArithmeticError iznimka, a ne i sva njezina djeca (FloatingPointError, OverflowError i ZeroDivisionError) pojedinačno, uz uvjet da se želi na isti način raditi sa svim iznimkama.
39
5
40
Iznimke
Tablica 5.1: Ugrađene iznimke
5.1. Vrste iznimki
41
Iznimka Exception
SystemExit
StandardError ArithmeticError FloatingPointError
OverflowError
ZeroDivisionError AssertionError AttributeError
EnvironmentError
IOError
OSError
WindowsError
EOFError
ImportError
KeyboardInterrupt
LookupError
Opis Korijen svih iznimki Podiže se sa sys.exit() funkcijom. Ako se ne obrađuje ova iznimka, onda Python interpreter završava program bez ispisa putanje završetka (engl. traceback ). Ako se pozove sys.exit(), Python prevodi poziv u iznimku i izvodi potporu iznimci (eng. exception handler ) koji se nalazi u finally odlomku od try naredbe. Osnova svih ugrađenih iznimki osim SystemExit. Roditelj za iznimke koje Python podiže za različite aritmetičke pogreške. Podiže se za pogreške u operacijama s pomičnom decimalnom točkom. Podiže se kad je rezultat aritmetičke operacije prevelik da bi se mogao prikazati. Ova iznimka ne može se pojaviti za duge cijele brojeve (eng. long integers). U njihovom slučaju Python podiže MemoryError. Podiže se kad je drugi argument običnog ili modularnog dijeljenja jednak nuli. Podiže se kad je pogreška u assert naredbi. Podiže se kad je atributna referenca ili pridružba pogrešna. Ako objekt ne podržava atributnu referencu ili pridružbu, onda Python podiže TypeError iznimku. Roditelj za iznimke koje se pojavljuju izvan Python-a. Podiže se kad je ulazno/izlazna operacija (kao što je print naredba, open() funkcijski poziv ili metoda u radu s datotekom) pogrešna, na primjer, za U/I razloge: "file not found" (datoteka nije pronađena) ili "disk full" (disk je pun). Podiže se kad se pojavi pogreška povezana s operacijskim sustavom (izvan Python-a). Obično se ovoj iznimci pridružuje numerički kôd pogreške, kao što je u os modulu iznimka os.error. Podiže se kad se pojavi pogreška povezana s Windows-operacijskim sustavom. Podiže se kad input() ili raw_input() otkrije konac datoteke (EOF) bez čitanja ikakvog podatka. (treba primjetiti da file-objekt read() i readline() metoda vraća prazan string kad se otkrije EOF.) Podiže se kad import griješi naći modul ili kad from-import griješi naći ime. Podiže se kad korisnik pritisne tipku prekida (interrupt key koja je obično Ctrl-C ili Del ). Python redovito provjerava takve prekide tijekom izvođenja programa. Python takođe podiže ovu iznimku ako korisnik utipka prekid za vrijeme input() ili raw_input() naredbe koja čeka korisnikov unos. Roditelj za iznimke koje Python podiže kada je indeks rječničkog ključa ili indeks niza (stringa, liste ili n-terca) nevaljao.
42
Iznimke
Evo nekih primjera čestih pogrešaka u programu koji podižu iznimke: >>> 10 * (1/0) Traceback (most recent call last): File "", line 1, in ? ZeroDivisionError: integer division or modulo by zero >>> 4 + spam*3 Traceback (most recent call last): File "", line 1, in ? NameError: name ’spam’ is not defined >>> ’2’ + 2 Traceback (most recent call last): File "", line 1, in ? TypeError: cannot concatenate ’str’ and ’int’ objects Posljednja linija poruke o pogreški govori što se dogodilo. Budući da postoji više vrsta iznimaka, njihov tip se nalazi ispisan u poruci (npr. ZeroDivisionError, NameError and TypeError). Svaka Python ugrađene iznimka podižu true pri pojavi pogreške njenog tipa. Ostatak ispisane linije poruke pruža detaljniji opis pogreške (TypeError), a dio prije imena iznimke govori o kontekstu u kojem se pogreška dogodila u obliku slijeda (Traceback).
5.2
Rad s iznimkama
U Pythonu je moguće pisati programe koji će raditi s određenim iznimkama, što se vidi na sljedećem primjeru: >>> ... ... ... ... ...
while True: try: x = int(raw_input("Unesite broj: ")) break except ValueError: print "Oops! To nije dobar broj. Probajte ponovo..."
Pri tome Try radi po sljedećem načelu: • ako se tokom izvršavanja ne pojavi iznimka, except linija se preskače i try završava • ako se iznimka pojavi tokom izvršavanja try-a, i ako odgovara iznimci navedenoj u except liniji, onda se ona izvršava • ako se iznimka pojavi, a ne odgovara except liniji provjeravaju se druge iznimke u try izrazu. Ako njih nema, program završava i pokazuje poruku koja je gore navedena. Pri tome try može imati više od jedne except linije (uvjeta), koji određuju rad za neke druge iznimke. Pri tome se najviše izvršava jedna od njih, i to samo za iznimke navedene u tom djelu except linije, ali ne za druge. Except linija može imati više iznimki, definiranih unutar n-terca, npr: ... except (RuntimeError, TypeError, NameError): ... pass Try...except izraz može sadržavati naredbu else koja se izvršava ako u try bloku nije izvršena nijedna iznimka. for arg in sys.argv[1:]: try: f = open(arg, ’r’)
5.3. Obradba iznimki
except IOError: print ’cannot open’, arg else: print arg, ’has’, len(f.readlines()), ’lines’ f.close() Koristi se umjesto pisanja dodatnih linija u try-u jer se s njom izbjegava mogućnost uporabe iznimke koja nije navedena u try bloku. Iznimke mogu imati pridružene vrijednosti, argumente, koji ovise o tipu iznimke. Except izraz može definirati varijablu nakon imena iznimke, koja je s instancom iznimke vezana s argumentima u instance.args. Umjesto korištenja instance.args dobro proslijediti jedinstveni argument iznimke i vezati ga atribut poruke. >>> try: ... raise Exception(’miki’, ’riki’) ... except Exception, inst: ... print type(inst) # instance iznimke ... print inst.args # argumenti pohranjeni u .args ... print inst # __str__ dozvoljava ispis args ... x, y = inst # __getitem__ dozvoljava da se args otpakiraju ... print ’x =’, x ... print ’y =’, y (’miki’, ’riki’) (’miki’, ’riki’) x = miki y = riki Ako iznimka ima argument, on se ispisuje kao zadnji dio poruke o pogrešci(’detail’). Programi za rad s iznimkama mogu raditi i s funkcijama, koje su unutar njih pozvane. >>> ... ... >>> ... ... ... ...
def nemoguce_dijeljenje(): x = 1/0 try: nemoguce_djeljenje() except ZeroDivisionError, detail: print ’Run time pogreska u dijeljenju:’, detail
Run time pogreska u dijeljenju: integer division or modulo by zero
5.3
Obradba iznimki
Kada Python podigne iznimku, ona se mora dohvatiti (uhvatiti) i obraditi, inače će Python zatvršiti izvođenje programa. Obradba iznimki prisiljava na razmišljanje o tome što može poći krivo unutar programa i što se može učiniti u vezi toga. Nije praktično (i skoro nemoguće) pokušavati imati na umu sve što može poći krivo. Umjesto toga treba tražiti stanja koja (govoreći općenito) mogu se ponovno postići koristeći korekcijski blok koda, koji se zove ’obrada iznimke’ (engl. exception handler ). On može automatski popraviti stanje bez korisničke interakcije, upitati korisnika za dodatne ili prihvatljive podatke za popravak problema, ili u nekim okolnostima zatvoriti program sa sys.exit(). (Dakako, cijeli je smisao iznimki u tome da se takve fatalne situacije izbjegnu). Pythonova naredba try detektira i obrađuje iznimke. Try je višeslojna naredba kao if ili while te slijedi pravila uvlake. Try također mijenja uobičajeno upravljanje tijeka programa. (Upravljanje tijekom programa je izvršni niz naredbi koje čine program).
43
44
Iznimke
try: try_block except ex: except_block Python pokreće kod u bloku try dok ga ne završi uspješno ili se pojavi iznimka. Ako završi uspješno, Python preskače blok except, te se izvršenje nastavlja na naredbi koja slijedi iza njega. Ako se pojavi iznimka, Python preskače ostatak naredbi bloka try i ispituje vrijednost ex u odlomku except kako bi se ustanovilo je li vrsta podignute iznimke odgovara vrsti koja je opisana sa ex. Ako iznimka odgovara ex, Python pokreće blok except, te se upravljanje tokom programa prebacuje na naredbu koja slijedi blok except. Ako iznimka ne odgovara ex, znimka se proširuje na bilo koje uključene try naredbe, koje bi mogle imati odlomak except u kojem bi se iznimka mogla obraditi. Ako ni jedna od obližnjih except klauzula ne obrađuje podignutu iznimku, onda Python zatvara program te ispisuje poruku o pogrešci.
5.3.1
Ignoriranje iznimke
Za ignoriranje iznimke koristi se naredba pass unutar odlomka except . try: try_block except ex: pass pa ako se dogodi iznimka, Python je ignorira i upravljanje tokom programa prelazi na prvu naredbu nakon pass naredbe.
5.3.2
Pronalaženje argumenta iznimke
Kada se dogod iznimka, ona može imati i pridruženu vrijednost također poznatu i kao argument iznimke. Vrijednost i tip argumenta ovise o tipu iznimke. Kod većine iznimki, argument je N-terac sastavljen od jednog string člana koji upućuje na uzrok pogreške. Kod pogrešaka operacijskog sustava tipa IOError, argument sadrži i dodatne atribute, kao što su broj pogreške ili ime datoteke. U tom slučaju može se koristiti funkcija dir() da bi se ispisao popis atributnih argumenta. Za pronalaženje vrijednosti argumenta, treba se specificirati varijabla nakon imena iznimke u odlomku except. try: try_block except ex, target: except_block pa ako se dogodi iznimka, Python će pridružiti argument iznimke varijabli target.
5.3.3
Obradba svih iznimki
Da bi se obuhvatilo sve iznimke, treba se specificirati odlomak except bez imena iznimke ili argumenta. Odlomak except koji na ovaj način obuhvaća sve iznimke je općenito slabo rješenje, jer obuhvaća sve iznimke, a ne samo one koje su bitne, a osim toga, može prikriti stvarne pogreške korisničkog programa. try: try_block except: except_block gdje except_block prihvaća i obrađuje sve iznimke.
5.3. Obradba iznimki
5.3.4
45
Pokretanje programskog koda bez prisustva iznimke
Moguće je također dodati odlomak uz else naredbu povezanu s odlomkom try kako bi se pokrenuo niz naredbi u slučaju da odlomak try ne uzrokuje iznimku. Pritom odlomak nakon else mora slijediti posljednji odlomak except (ako ih ima više). try: try_block except [...]: except_block else: else_block Python pokreće else_block jedino u slučaju kad try_block ne uzrokuje iznimku.
5.3.5
Obradba više iznimki
Moguće je koristiti jedan except odlomak da bi se obuhvatilo više tipova iznimki ili se može koristiti više except odlomaka kojima se obrađuju pojedine iznimke. try: try_block except (ex1, ex2, ...) [, target]: except_block Odlomak except obuhvaća bilo koju od popisanih iznimki (ex1, ex2, ...) te pokreće isti except_block za sve njih. Target je dopustiva varijabla koja uzima argument iznimke.
5.3.6
Pokretanje obaveznog kôda za čišćenje
Naredba try-finally može se koristiti za pokretanje programskog kôda bez obzira je li Python podigao iznimku ili nije. Za razliku od odlomka except , odlomak finally ne dohvaća iznimke, nego definira akcije čišćenja koje se moraju obaviti u svakom slučaju, bez obzira na postojanje pogreške. Odlomci finally i except ne mogu se pojaviti zajedno u istom try odlomku. Programeri obično postave naredbu try-finally unutar naredbe try-except kako bi obradili iznimke koje su podignute u naredbi try-finally. Isto tako, odlomak else ne može se dodati uz naredbu try-finally. try: try_block finally: finally_block Python pokreće kôd unutar finally_block-a nakon što ga pokrene u try_block-u. Python će pokrenuti finally_block bez obzira kako se try_block izvrši: bilo normalno, bilo putem iznimke ili putem naredbe tipa break ili return. Ako se iznimka dogodi unutar try_block-a, Python će preskočiti ostatak try_block-a, te pokrenuti finally_block, a onda ponovno podignuti iznimku kako bi se dohvatila naredbom try-except više razine.
5.3.7
Eksplicitno podizanje iznimke
Naredba raise se može upotrijebiti da bi se podigla željena iznimka. Za eksplicitno podizanje iznimke treba utipkati: raise ex ili
46
Iznimke
raise ex, arg ili raise ex, (arg1, arg2,...) Argument iznimke može biti jedna vrijednost, argument ili n-terac vrijednosti (arg1, arg2, ...). Ako je izostavljen, onda je pretpostavljena vrijednost argumenta None.
5.4
Korisnički definirane iznimke
U Pythonu je moguće stvarati korisničke iznimke na način da se definiraju nove klase iznimaka. Takve iznimke bi trebale direktno ili indirektno dolaziti iz klase ugrađenih iznimaka, na primjer: >>> class MojBad(Exception): ... def __init__(self, value): ... self.value = value ... def __str__(self): ... return repr(self.value) ... >>> try: ... raise MojBad(2*2) ... except MojBad, e: ... print ’Moja se iznimka dogodila, value:’, e.value ... Moja se iznimka dogodila, value: 4
5.4.1
Tvorba iznimki
Iznimke mogu biti stringovi, klase ili instance objekata. Iznimke u obliku stringova su zastarjele, Python ih još uvijek podržava zbog kompatibilnosti. Korisnički definirane iznimke mogu se stvoriti koristeći naredbu class . Preporučuje se kao temeljnu klasu uzeti Pythonovu korijensku iznimku Exception. S korisnički definiranim iznimkama radi se na isti način kao i s ugrađenim iznimkama. Uz except i else, postoji i način da se definira iznimka koja će se uvijek ispisati na kraju programa, bez obzira dali je baš nju program tražio ili neku drugu. To je finally clause i definira se kao: >>> def dijeli(x, y): ... try: ... rez = x / y ... except ZeroDivisionError: ... print "Djeljenje s nulom!" ... else: ... print "Rezultat je", rez ... finally: ... print "Ispisujem zadnju iznimku" ... >>> dijeli(2, 1) result is 2 Ispisujem zadnju iznimku >>> dijeli(2, 0) division by zero! Ispisujem zadnju iznimku >>> dijeli("2", "1") Ispisujem zadnju iznimku
5.4. Korisnički definirane iznimke
Traceback (most recent call last): File "", line 1, in ? File "", line 3, in divide TypeError: unsupported operand type(s) for /: ’str’ and ’str’ Kao što se vidi na primjeru, finally clause se ispisuje pri svakoj operaciji sa funkcijom djeli(). TypeError pozvan kod dijeljenja dva stringa (dijeli("2","1")) nije pozivan od strane iznimaka,te je stoga ponovo pozvan nakon što se zadnja iznimka izvršila. Sve iznimke se mogu pozvati naredbom raise exception[,value], gdje value daje detalje o iznimci koja je pozvana.
5.4.2
Dodjelivalo
Dodjelivalo (eng. assertion) je alat za ispravljanje pogrešaka koji se koristi za ispis dijagnostičkih podataka dok program radi. Python naredba assert sadrži bool-ov izraz koji ako je false (neistina), označava pogrešku. Izraz je uvijek jednak jedinici ako je istinit u trenutku kad se provjerava. Ako je izraz izračunat kao neistina (false), onda Python podiže AssertionError iznimku, koja se može dohvatiti i obraditi kao bilo koja druga iznimka. Sintaksa je: assert expr [,arg] expr je izraz koji se provjerava, a može biti true ili false. Ako je expr jednak false, onda Python podiže AssertionError iznimku s dopuštenim argumentom arg. Ako je pak izraz expr jednak true, onda assert ne poduzima ništa.
47
POGLAVLJE
Funkcije Većina naredbi tipičnog Python programa organizirana je preko funkcija. Funkcija je skupina naredbi koje se izvršavaju po pozivu. Python pruža mnogo ugrađenih funkcija i dopušta programerima definiranje vlastitih funkcija. Zahtjev za izvršenje funkcije zove se funkcijski poziv (engl. function call ). Kad se funkcija pozove, može primiti argumente koji specificiraju vrstu podataka nad kojima funkcija izvršava svoje izračune. U Pythonu funkcija uvijek vraća rezultantnu vrijednost, koja može biti None ili vrijednost koja predstavlja rezultat izračuna. U Pythonu su funkcije objekti, pa se sa njima upravlja isto kao i s drugim objektima. Tako se funkcija može proslijediti kao argument koji prima druga funkcija. Slično tome, funkcija može vratiti drugu funkciju kao rezultat poziva. Kao i svaki drugi objekt, funkcija može biti povezana s varijablom, članom unutar spremnika (polja, liste) ili atributom objekta. Funkcije također mogu biti ključevi u rječniku. Na primjer, ako se treba brzo naći inverzna funkcija za određenu funkciju, može se definirati rječnik čiji su ključevi i vrijednosti funkcije, a onda načiniti rječnik dvosmjernim: inverse = {sin:asin, cos:acos, tan:atan, log:exp} for f in inverse.keys( ): inverse[inverse[f]] = f Činjenica da su funkcije objekti u Pythonu, često se izražava riječima da su funkcije objekti prve klase.
6.1
Naredba def
Ključnom riječi def definira se funkcije. Def je jednoklauzulna komponentna naredba sa sljedećom sintaksom: def function-name(parameters): statement(s) function-name je identifikator. To je varijabla koja se povezuje (ili re-povezuje) s funkcijskim objektom prilikom izvršenja naredbe def. parameters je dopuštena, slobodna lista identifikatora, koji se zovu formalni parametri ili samo parametri, a koji se koriste za pridruživanje stvarnim vrijednostima koje se navode kao argumenti kod poziva funkcija. U najjednostavnijem slučaju, funkcija nema nikakvih formalnih parametara, što znači da funkcija ne uzima nikakve argumente prilikom pozivanja. U ovom slučaju, definicija funkcije ima prazne zagrade koje slijede iza imena funkcije tj. function-name(). Ako funkcija prihvaća argumente, onda parameters sadrži jedan ili više identfikatora, odvojenih zarezima. U ovom slučaju, svaki poziv fukciji pridružuje stvarne vrijednosti, poznate kao argumenti, koje odgovaraju parametrima specificiranima u definiciji funkcije. Parametri su lokalne varijable funkcije, te svaki poziv funkcije povezuje te varijable s odgovarajućim stvarnim vrijednostima koje pozivatelj prenosi kao 49
6
50
Funkcije
argumente. Niz naredbi koji nije prazan, poznatiji kao tijelo funkcije (engl. function body), ne izvršava se kada i naredba def. Ono se izvršava kasnije, svaki put kada se funkcija poziva. Tijelo funkcije može imati jednu ili više ponavljanja return naredbe, ali može postojati i bez nje. Evo primjera jednostavne funkcije koja vraća vrijednost koja je dvostruka od one koju primi: def double(x): return x*2
6.2
Parametri
Formalni parametri koji su jednostavni identifikatori predstavljaju obavezne parametre. Svaki poziv funkciji mora pružiti i odgovarajuću vrijednost (argument) za svaki obvezatni parametar. U listi parametara odvojenih zarezima s niti jednim ili više obvezatnih parametara može slijediti jedan ili više slobodnih parametara koji imaju sljedeću sintaksu: identifier=expression Naredba def računa, ocjenjuje izraz, te sprema referencu vrijednosti koju izraz vraća, a koja se zove pretpostavljena vrijednost (eng. default value). Kad poziv funkcije nema argument koji odgovara proizvoljnom parametru, onda se identifikator argumenta povezuje s tom pretpostavljenom (ili izračunatom) vrijednosti. Treba primjetiti da se isti objekt, pretpostavljena vrijednost, povezuje sa slobodnim parametrom kad god u pozivu funkcije nema pridruženog argumenta. Ovo dakako, može biti nezgodno, ako je pretpostavljena vrijednost je promjenljivi objekt, a tijelo funkcije mijenja taj parametar. Na primjer: def f(x, y=[ ]): y.append(x) return y print f(23) prinf f(42)
# ispisuje se: [23] # ispisuje se: [23,42]
Druga naredba print ispisuje [23,42] zato jer prvi poziv funkcije f mijenja vrijednost y, koja je prije bila prazna lista [], a onda dodavanjem 23 poprima tu novu vrijednost, pa novi poziv uzima zadnje stanje argumenta. Ako je potrebno povezati y s novim objektom liste svaki put kada se f poziva s jednim argumentom, koristi se sljedeće: def f(x, y=None): if y is None: y = [ y.append(x) return y print f(23) prinf f(42)
]
# ispisuje se: [23] # ispisuje se: [42]
Na kraju formalnih parametara dopušteno je koristiti jedan ili oba posebna oblika: *identifier1 i **identifier2. Ako su obadva na raspolaganju, onaj sa dvije zvjezdice mora doći zadnji. *identifier1 dopušta da bilo koji poziv funkciji može pružiti dodatne pozicijske argumente, dok **identifier2 dopušta da bilo koji poziv funkciji može pružiti dodatne argumente s imenom. Na taj način rješavaju se pozivi funkcija s varijabilnim brojem argumenata. Svaki poziv funkciji povezuje identifier1 sa n-tercem čiji su članovi dodatni pozicijski argumenti (ili praznim n-tercem, ako ih nema). identifier2 povezuje se rječnikom čiji su članovi imena i vrijednosti dodatnih argumenata koji se imenuju (ili praznim rječnikom, ako ih nema). Evo kako napisati funkciju koja prihvaća bilo koji broj argumenata i vraća njihov zbroj: def zbroj(*broj): rez = 0 for x in broj: rez += x return rez print zbroj(23,42)
# ispisuje se: 65
6.3. Atributi funkcijskih objekata
Oblik ** također dopušta konstrukciju rječnika s ključevima stringa u obliku koji se lakše čita nego standardna rječnička sintaksa: def vbr_rj(**kwds): return kwds print vbr_rj (a=23, b=42) # ispisuje se: {’a’:23, ’b’:42} Treba primjetiti da se tijelo funkcije vbr_rj sastoji od samo jedne jednostavne naredbe, tako da se može upotrijebiti opcija stavljanja na istu liniju kao i naredba def. Dakako, bilo bi jednako točno (i možda čitljivije) ako bi se funkcija vbr_rj ispisala koristeći dvije linije umjesto jedne: def vbr_rj (**kwds): return kwds
6.3
Atributi funkcijskih objekata
Naredba def definira neke atribute od objekta funkcije. Atribut func_name, kojem se može pristupiti i kao __name__, je samočitajući (engl. read-only) atribut (pa pokušaj ponovnog povezivanja tj. mijenjanja podiže iznimku) koji se odnosi na identifikator korišten kao ime funkcije u naredbi def. Atribut func_defaults, koji se može ponovno povezati ili re-povezati, se odnosi na n-terac pretpostavljenih vrijednosti za slobodne parametre (ili prazan n-terac, ako funkcija nema po izboru slobodnih parametara). Još jedan funkcijski atribut je dokumentacijski string (engl. documentation string), također poznat kao docstring. Docstring atribut funkcije može se koristiti ili re-povezati kao func_doc ili __doc__. Ako je prva naredba u tijelu funkcije string literal, compiler povezuje taj niz sa docstring atributom funkcije. Docstring-ovi se često protežu preko nekoliko fizičkih linija, te se stoga obično označuju kao string literali unutar trostrukih navodnika. Na primjer: def zbroj(*brojevi): ’’’Prihvati po volji koliko numeri\v{c}kih argumenata i vrati njihov zbroj Argumenti su butu jedan ili vi\v{s}e brojeva. Izlaz je njihov zbroj. ’’’ rez = 0 for broj in brojevi: rez += broj return rez Dokumentacijski nizovi bi trebali biti dio svakoga Python kôda. Njihova je uloga slična komentarima u bilo kojem programskom jeziku, ali im je iskoristivost šira, jer su dostupni pri procesu pokretanja programa (engl. runtime). Programerska okruženja i drugi alati mogu koristiti docstring-ove funkcijskih, klasnih i modularnih objekata da podsjete programera kako koristiti te objekte. Da bi se docstring učinio što je moguće korisnijim, trebalo bi poštovati nekoliko jednostavnih konvencija. Prva linija docstringa trebala bi biti sažeti opis svrhe funkcije, a počinjala bi s velikim slovom i završavala točkom. Unutar nje se ne bi trebalo spominjati ime funkcije, osim ako ime nije riječ iz prirodnog, govornog jezika pa dolazi kao dio opisa operacije te funkcije. Ako je docstring protegnut preko više linija, druga linija treba biti prazna, a sljedeće linije bi trebale formirati jedan ili više odlomaka, odvojenih praznim linijama, koji opisuju očekivane argumente funkcije, potrebne uvjete, povratne vrijednosti, te moguće nuspojave. Daljnja objašnjenja, književne reference, te primjeri korištenja (koji se mogu provjeriti sa doctest) mogu po slobodnom izboru slijediti iza, prema završetku docstring-a. Uz ove predefinirane atribute, funkcijskom objektu mogu se dodati i drugi atributi. Da bi se stvorio atribut objekta funkcije, prikladna atributna vrijednost se nakon izvršenja naredbe def povezuje s odgovarajućim referencama. Na primjer, funkcija može brojati koliko je puta pozivana: def counter( ): counter.count += 1 return counter.count counter.count = 0
51
52
Funkcije
Ovo, ipak, nije česta primjena. Mnogo češće, kada se trebaju grupirati neki podaci i kôd zajedno, trebaju se koristiti objektno-orijentirani mehanizmi. Ipak, mogućnost pridruživanja atributa s funkcijom može ponekad biti od koristi.
6.4
Naredba Return
Naredba return u Pythonu dopušta se jedino unutar tijela funkcije, te iza nje po izboru može još slijediti neki izraz. Kada se return izvrši, funkcija završava i dobiva se povratna vrijednost izraza. Funkcija vraća None ako završava dolaskom do konca svog funkcijskog tijela ili izvršenjem naredbe return bez pridruženog izraza. Stvar je stila da se naredba return ne piše na kraju tijela funkcije, ako nema izraz koji vraća. Ako neke return naredbe u funkciji imaju izraz, onda bi ga i sve ostale return naredbe trebale imati. Naredba return None može se pisati samo ako se eksplicitno želi zadržati stil takvog pisanja. Iako Python ne prisiljava na ovakve stilske konvencije, kôd će biti čitljiviji i jasniji ako ih se slijedi.
6.5
Pozivanje funkcija
Poziv funkciji je izraz sa sljedećom sintaksom: function-object(arguments) function-object može biti bilo kakva referenca na objekt funkcije, a to je najčešće ime funkcije. Zagrade označuju operaciju poziva funkciji, dok su arguments u najjednostavnijem slučaju niz od nula ili više izraza odvojenih zarezima, koji daju vrijednosti odgovarajućim formalnim parametrima funkcije. Kada se poziva funkcija, parametri poziva funkcije povezuju se s funkcijskim argumentima, tijelo funkcije se izvršava sa stvarnim vrijenostima argumenata, a neka vrijednost izraza je što god funkcija na koncu vrati nakon izvršenja.
6.5.1
Prenošenje argumenata
U tradicionalnim terminima rečeno, sve operacije prenošenja argumenata u Pythonu su putem vrijednosti (engl. by value). Na primjer, ako se varijabla prenosi kao argument, Python prenosi funkciji objekt (vrijednost) na koju se varijabla odnosi, a ne samu varijablu. Na taj način funkcija ne može re-povezati, tj. mijenjati varijable pozivatelja. Ali, ako se kao argument prenosi promjenljivi objekt, funkcija smije zahtjevati izmjene na objektu, jer Python prenosi sam objekt, a ne njegovu kopiju. Re-povezivanje varijable i promjena objekta su dva potpuno različita koncepta u Pythonu. Na primjer: def f(x, y): x = 23 y.append(42) a = 77 b = [99] f(a, b) print a, b
# prints: 77 [99, 42]
Naredba print pokazuje da je a još uvijek povezano sa 77. Re-povezivanje funkcijskog parametra x na 23 nema efekta s obzirom na poziv funkcije f, a posebno ne na povezivanje varijable pozivatelja, koje je bilo iskorišteno da prenese 77 kao vrijednost parametra. Ali, naredba print također pokazuje da je b sad povezano s [99,42]. Objekt b je još uvijek povezan s istim objektom liste kao i prije poziva, ali se taj objekt mijenjao, jer se unutar funkcije f pridodao 42 na taj objekt liste. U oba slučaja, f nije izmijenio poveznice pozivatelja, niti f može izmijeniti broj 77, jer su brojevi nepromjenljivi. Ali, f može izmijeniti objekt liste, jer su objekti liste promjenljivi. U ovom primjeru, f mijenja objekt liste koji pozivatelj prenosi na f kao drugi argument pozivajući append metodu objekta.
6.5. Pozivanje funkcija
6.5.2
Vrste argumenata
Upravo opisani argumenti zovu se pozicijski argumenti. Svakom pozicijskom argumentu pridružuje se vrijednost parametra koji mu odgovara po poziciji (redoslijedu) u definiciji funkcije. U pozivu funkcije s nula ili više pozicijskih argumenata mogu slijediti jedan ili više imenovanih argumenata sa sljedećom sintaksom: identifier=expression identifier mora biti jedno od imena formalnih parametara koja se koriste u def naredbi funkcije. expression daje vrijednost formalnog parametra. Poziv funkcije mora pružati, putem pozicijskih i/ili imenovanih argumenata, točno jednu vrijednost za svaki obvezatni parametar, te nula ili jednu vrijednost za svaki slobodno izabrani parametar. Na primjer: def divide(divisor, dividend): return dividend // divisor print divide(12,94) # prints: 7 print divide(dividend=94, divisor=12) # prints: 7 Očito je da su dva poziva za dijeljenje ekvivalentna. Imenovani argumenti mogu se prenositi u svrhu čitljivosti, kada se čitljivost i razumljivost napisanog kôda može povećati identifikacijom uloge i upravljanjem redoslijeda argumenata. Češća uporaba imenovanih argumenata je u svrhu povezivanja nekih izabranih parametara za specifične vrijednosti, dok drugi izabrani, opcionalni parametri uzimaju njihove pretpostavljene vrijednosti: def f(middle, begin=’init’, end=’finis’): return begin+middle+end print f(’tini’, end=’’) # prints: inittini Zahvaljujući imenovanom argumentu end=” pozivatelj može specificirati vrijednost, prazan string ’ ’ za funkcijski treći parametar end, te još uvijek dopustiti funkcijskom drugom parametru begin, korištenje njegove pretpostavljne vrijednosti, stringu ’init’. Na kraju argumenata u pozivu funkciji, po izboru se može koristiti bilo koji (ili oba) posebna oblika *seq i **dict. Ako su oba prisutna, onaj sa dvije zvjezdice mora doći na zadnjem mjestu. *seq prenosi članove seq kao pozicijske argumente funkcije (poslije običnih pozicijskih argumenata, ako ih ima, a koje poziv pruža s uobičajenom jednostavnom sintaksom). seq može biti bilo kakav niz ili iterator. **dict prenosi članove dict kao imenovane argumente funkcije, gdje dict mora biti rječnikj čiji su svi ključevi stringovi. Ključ svakog člana je ime parametra, a vrijednost tog člana je vrijednost argumenta. Ponekad je potrebno prenijeti argument oblika *seq ili **dict kad formalni parametri koriste slične oblike. Na primjer, koristeći funkciju sum može se ispisati zbroj svih vrijednosti u riječniku d. Ovo se postiže vrlo jednostavno sa *seq oblikom: def sum(*numbers): result = 0 for number in numbers: result += number return result print sum(*d.values( )) Međutim, argumenti oblika *seq ili **dict mogu se prenositi i kad se poziva funkcija koja ne koristi slične oblike u svojim formalnim parametrima.
6.5.3
Prostori za imena
Formalni parametri funkcije, plus bilo kakve varijable koje su povezane (pridružbom ili nekom drugom povezujućom naredbom) u funkcijskom tijelu, tvore lokalni prostor za imena funkcije (eng. local namespace), također poznat i kao lokalni doseg (eng. local scope). Svaka od ovih varijabli zove se lokalna varijabla funkcije. Varijable koje nisu lokalne zovu se globalne varijable. Ako lokalna varijabla unutar funkcije ima isto ime kao i globalna varijabla, kada god se to ime spomene u tijelu funkcije, koristi se lokalna, a ne globalna varijabla. Za ovakav pristup kaže se da lokalna varijabla sakriva globalnu varijablu istog imena kroz cijelo tijelo funkcije.
53
54
Funkcije
6.6
Globalna naredba
Standardno, bilo koja varijabla koja je povezana unutar tijela funkcije je lokalna varijabla funkcije. Ako pak funkcija treba re-povezati neke od svojih globalnih varijabli, prva naredba funkcije mora biti: global identifiers gdje su identifiers jedan ili više identifikatora odvojenih zarezima. Identifikatori popisani u global naredbi odnose se na globalne varijable (npr. atribute modul objekta) koje funkcija treba re-povezati. Na primjer, counter(brojilo) funkcije može se ubaciti u funkciju koristeći ključnu riječ global i globalnu varijablu, a ne atribut objekta funkcije, kako slijedi: _count = 0 def counter( ): global _count _count += 1 return _count Bez global naredbe, funkcija counter bi podigla UnboundLocalError iznimku, jer bi _count bio neinicijalizirana (nepovezana) lokalna varijabla. Također, iako naredba global omogućuje ovakvu vrstu programiranja, to ipak nije niti elegantno niti preporučljivo. Naredba global nije potrebna ako tijelo funkcije jednostavno koristi globalnu varijablu, uključujući mijenjanje objekta povezanog na varijablu, dakako ako je objekt promjenljiv. Naredba global treba se koristiti samo onda kada tijelo funkcije re-povezuje globalnu varijablu. Stvar je stila, a i preporuke, da se naredba global ne koristi osim kad je to apsolutno nužno.
6.7
Ugnježđene funkcije
Naredba def unutar tijela funkcije definira ugnježđenu funkciju (eng. nested function), a funkcija čije tijelo uključuje def je poznata kao vanjska funkcija (eng. outer function) s obzirom na ugnježđenu. Kôd unutar tijela ugnježđene funkcije može pristupiti (ali ne i re-povezati) lokalne varijable vanjske funkcije, također poznate i kao slobodne varijable ugnježđene funkcije. Najjednostavniji način da se dopusti ugniježđenoj funkciji pristup vanjskim vrijednostima nije oslanjati se na ugnježđene dosege varijabli, nego prijenos vanjskih vrijednosti preko funkcijskih argumenata. Vrijednost argumenta može biti povezana kada se ugnježđena funkcija definira korištenjem vrijednosti kao pretpostavljena vrijednost za izabrani argument. Na primjer: def percent1(a, b, c): def pc(x, total=a+b+c): return (x*100.0) / total print "Percentages are ", pc(a), pc(b), pc(c) Evo iste funkcionalnosti upotrebom ugnježđenih dosega: def percent2(a, b, c): def pc(x): return (x*100.0) / (a+b+c) print "Percentages are", pc(a), pc(b), pc(c) U ovom specifičnom slučaju, percent1 ima malu prednost: izračun a+b+c se događa samo jednom, dok kod percent2 nutarnja funkcija pc ponavlja izračun tri puta. Međutim, ako vanjska funkcija repovezuje svoje lokalne varijable između poziva ugnježđene funkcije, ponavljanje izračuna bi mogla biti i prednost. To znači da se preporučuje znanje oba pristupa, te izbor najprikladnijeg u danoj situaciji. Ugnježđena funkcija koja pristupa vrijednostima sa vanjskih lokalnih varijabla je poznata kao closure. Sljedeći primjer pokazuje kako izgraditi closure bez ugnježđenih dosega (koristeći pretpostavljenu vrijednost):
6.7. Ugnježđene funkcije
def make_adder_1(augend): def add(addend, _augend=augend): return addend+_augend return add A evo i iste funkcionalnosti korištenjem ugnježđenih dosega: def make_adder_2(augend): def add(addend): return addend+augend return add Closures su iznimke u općem pravilu gdje su objektno-orjentirani mehanizmi najbolji način povezivanja podataka i kôda zajedno. Kada se trebaju konstruirati pozivni objekti, s nekim parametrima u vremenu konstrukcije objekta, closures mogu biti efikasnije i jednostavnije od klasa. Na primjer, rezultat make_adder_1(7) je funkcija koja prihvaća jedan argument i dodaje 7 na taj argument (rezultat make_adder_2(7) se ponaša na isti način). Closure je "tvornica" za bilo kojeg člana obitelji funkcija koji se razlikuju po nekim parametrima, te može pomoći u izbjegavanju dvostrukog pisanja programskog kôda.
55
POGLAVLJE
Python - objektni jezik Python je programski jezik orijentiran prema objektima. Za razliku od nekih drugih, također objektnoorijentiranih, jezika, Python ne uvjetuje korištenje isključivo objektno-orijentirane paradigme. Python također podržava proceduralno programiranje s modulima i funkcijama, tako da je moguće izabrati najprikladniju paradigmu programiranja za svaki dio programa. Općenito, objektno-orijentirana paradigma najbolja je kada se žele skupiti podaci i funkcije u praktične pakete. Isto tako može biti korisna kada se žele koristiti neki od Pythonovih objektno-orijentiranih mehanizama, kao naslijeđe ili posebne metode. Proceduralna paradigma, koja je bazirana na modulima i funkcijama, je obično jednostavnija i prikladnija kada nikakve prednosti objektno-orijentiranog programiranja nisu potrebne. Sa Pythonom, je to obično stvar miješanja i prilagođavanja jedne ili više paradigmi. Novi stil objektnog modela postat će standard u budućim verzijama Pythona. Njegove prednosti nad klasičnim modelom, iako male, mogu se zamijetiti i mjeriti, te praktično nema mana koje ih kompenziraju. Zato je jednostavnije koristiti novi stil objektni model, a ne odlučivati o izboru modela svaki put kod kodiranja nove klase.
7.1
Klasične klase i instance
Klasična klasa ili razred je Python objekt s nekoliko značajki: • Objekt klase se može pozivati kao da je funkcija. Poziv stvara novi objekt, poznat kao instanca klase, za koju se zna kojoj klasi pripada. • Klasa ima po volji imenovane atribute koji se mogu povezivati i referirati. • Vrijednosti atributa klase mogu biti podatkovni objekti ili funkcijski objekti. • Atributi klase koji su povezani na funkcije poznati su kao metode klase. • Metoda može imati posebno ime definirano od Pythona sa dvije podcrte ispred i iza. Python upotrebljava takve posebne metode, kad se različite vrste operacija izvršavaju na instancama klase. • Klasa može naslijediti od drugih klasa, što znači da može potragu atributa koji nisu unutar same klase prenijeti na druge objekte klase. • Instanca klase je Python objekt s po volji imenovanim atributima koji se mogu povezivati i referirati. Objekt instance implicitno ostavlja svojoj klasi potragu za atributima koji se ne nalaze u samoj instanci. Klasa također može predati potragu klasama od kojih je naslijeđena. 57
7
58
Python - objektni jezik
• U Pythonu, klase su objekti(vrijednosti), te se sa njima postupa kao i s drugim objektima. Tako se klasa može prenijeti kao argument u pozivu funkcije. Slično tomu, funkcija može vratiti klasu kao rezultat poziva. Klasa, kao i bilo koji drugi objekt, može biti povezana na varijablu (lokalnu lili globalnu), član spremnika ili atribut objekta. Klase također mogu biti i ključevi u riječniku. Činjenica da su klase objekti u Pythonu se često izražava tako da se kaže da su klase objekti Prve klase.
7.2
Naredba class
Naredba class je najčešći način stvaranja objekta klase. Class je jednoklauzulna višedijelna naredba s ovom sintaksom: class classname[(base-classes)]: statement(s) classname je identifikator. To je varijabla koja postaje povezana (ili re-povezana) s objektom klase nakon što naredba class završi s izvršavanjem. base-classes je po volji zarezima odvojen niz izraza čije vrijednosti moraju biti objekti klase. Ove su klase poznate pod različitim imenima u različitim jezicima; o njima se može misliti kao o baznim klasama, superklasama, ili roditeljima klase koja se stvara. Za klasu koja se stvara kaže se da nasljeđuje oblik, počinje od, produžava se ili podklasira od svoje bazne klase. Ova klasa je također poznata kao izravna podklasa ili potomak svojih baznih klasa. Podklasna veza između klasa je prijelazna. Ako je C1 podklasa od C2, a C2 podklasa od C3, onda je C1 podklasa od C3. Ugrađena funkcija issubclass(C1,C2) prihvaća dva argumenta koji su objekti klase: vraća True ako C1 je podklasa od C2, u suprotnom vraća False. Svaka klasa je zapravo podklasa od same sebe, tako da issubclass(C, C) vraća True za bilo koju klasu C. Sintaksa naredbe class ima malu, nezgodnu razliku od sintakse naredbe def. U naredbi def, zagrade su obvezatne između imena funkcije i dvotočke. Da se definira funkcija bez formalnih parametara, mora se koristiti naredba kao: def name( ): statement(s) U naredbi class zagrade su obvezatne ako klasa ima jednu li više baznih klasa, ali su zabranjene ako klasa nema baznih klasa. Tako da se za definaciju klase bez baznih klasa mora koristiti naredba kao: class name: statement(s) Niz naredbi koji nije prazan, a koji slijedi naredbu class poznat je kao tijelo klase. Tijelo klase se izvršava odmah, kao dio procesa izvršenja naredbe class. Dok se tijelo ne izvrši, novi objekt klase ne postoji i classname identifikator nije još povezan (ili re-povezan). Konačno, valja primijetiti da naredba class ne stvara nove instance klase, nego definira skup atributa koji se dijeli između svih instanci kada se stvore.
7.3
Tijelo klase
Tijelo klase je mjesto gdje se specificiraju atributi klase; ovi atributi mogu biti podatčani ili funkcijski objekti:
7.3.1
Atributi objekata klase
Atribut objekta klase obično se specificira povezivanjem vrijednosti na identifikator unutar tijela klase. Na primjer:
7.3. Tijelo klase
class C1: x = 23 print C1.x
59
# ispisuje: 23
Objekt klase C1 sad ima atribut s imenom x, povezan na vrijednost 23, a C1.x se odnosi na taj atribut. Također je moguće povezati ili odvezati atribute klase izvan tijela klase. Na primjer: class C2: pass C2.x = 23 print C2.x
# ispisuje: 23
Ipak, program je čitljiviji ako se povežu, tj. stvore, atributi klase s naredbama unutar tijela klase. Bilo koji atributi klase implicitno se dijele svim instancama klase kad se te instance stvore. Naredba class implicitno definira neke atribute klase. Atribut __name__ je classname identifikacijski niz znakova korišten u naredbi class. Atribut __bases__ je n-terac objekata klase koji su dani kao bazne klase u naredbi class (ili prazan n-terac, ako nema danih baznih klasa). Na primjer, koristeći klasu C1 koju smo upravo stvorili: print C1.__name__, C1.__bases__
# ispisuje: C1, (
)
Klasa također ima atribut __dict__, što je rječnički objekt koji klasa koristi za potporu (popis postojećih) svih svojih ostalih atributa. Za svaki objekt klase C, bilo koji objekt x i bilo kakav identifikator S (osim __name__, __bases__ i __dict__) vrijedi: C.S=x je ekvivalentan s C.__dict__[’S’]=x. Na primjer, za poznatu klasu C1: C1.y = 45 C1.__dict__[’z’] = 67 print C1.x, C1.y, C1.z
# ispisuje: 23, 45, 67
Pritom nema razlike između atributa klase koji su stvoreni unutar tijela klase, izvan tijela klase zadavanjem atributa ili izvan tijela klase eksplicitnim povezivanjem sa C.__dict__. U naredbama koje su izravno u tijelu klase, reference na atribute klase moraju koristiti puno, a ne jednostavno ime kvantifikatora. Na primjer: class C4: x = 23 def amethod(self): print C4.x
# mora se koristiti C4.x, a ne samo x
Treba primijetiti da reference atributa (npr. izraz kao C.S) imaju bogatiju semantiku nego povezivanje atributa.
7.3.2
Definicije funkcija unutar tijela klase
Većina tijela klasa uključuju naredbu def, jer su funkcije (u ovom kontekstu se zovu metode) važni atributi za objekte klase. Uz to, metoda definirana unutar tijela klase uvijek ima obvezatan prvi parametar, koji se dogovorno imenuje kao self, a odnosi se na instancu u kojoj se metoda poziva. Parametar self igra posebnu ulogu u pozivima metode. Evo primjera klase koja uključuje definiciju metode: class C5: def hello(self): print "Hello" Klasa može definirati nekolicinu posebnih metoda (metoda sa imenima koja imaju dvije podcrte ispred i iza) koje se odnose na posebne operacije.
60
Python - objektni jezik
7.3.3
Varijable specifične za klasu
Kada naredba u tijelu klase (ili metodi unutar tijela) koristi identifikator koji počinje s dvije podcrte (ali ne završava podcrtama), kao __ident, Python kompiler implicitno mijenja identifikator u _classname__ident, gdje je classname ime klase. Ovo dopušta klasi korištenje privatnih imena za atribute, metode, globalne varijable i druge svrhe, bez rizika slučajnog dupliciranja imena korištenih drugdje. Dogovorno, svi identifikatori koji počinju jednom podcrtom također se namijenjeni kao privatni, za doseg koji ih povezuje, bez obzira je li doseg unutar klase ili nije. Python kompiler ne prisiljava dogovore oko privatnosti varijabli i metoda, to je ostavljeno programerima u Pythonu.
7.3.4
Dokumentacijski string
Ako je prva naredba u tijelu klase literal niza znakova (string), onda compiler povezuje taj niz znakova kao atribut dokumentacijskog stringa za tu klasu. Ovaj se atribut zove __doc__ te je poznat kao dokumentiranje klase.
7.4
Instance
Instance klase stvaraju se pozivom class objekta kao funkcije. Na taj način stvara se nova instanca i poziva __init__() metoda od klase (ako je definirana). Na primjer: # a # b
Create a few accounts = Account("Guido", 1000.00) Invokes Account.__init__(a,"Guido",1000.00) = Account("Bill", 100000000000L)
Jednom načinjeni, atributi i metode novo nastale instance dohvatljivi su korištenjem točkastog (.) operatora kako slijedi: a.deposit(100.00) b.withdraw(sys.maxint) name = a.name print a.account_type
# # # #
Call Account.deposit(a,100.00) Call Account.withdraw(b,sys.maxint) Get account name Print account type
Interno, svaka instanca se stvara koristeći rječnik koji je dohvatljiv kao isntanca __dict__ atributa. Ovaj rječnik sadrži informaciju koja je jedinstvena za svaku instancu. Na primjer: >>> print a.__dict__ {’balance’: 1100.0, ’name’: ’Guido’} >>> print b.__dict__ {’balance’: 97852516353L, ’name’: ’Bill’} Kad god se atributi instance promijene, ove promjene nastaju u lokalnom rječniku instance. Unutar metoda definiranih u klasi, atributi se mijenjaju kroz pridružbu self varijabli kako je pokazano u __init__(), deposit() i withdraw() metode od Account. Međutim, novi atributi mogu se dodati instanci u bilo kojem trenutku, kao na primjer: a.number = 123456
# Add attribute ’number’ to a.__dict__
Iako se pridružba atributima uvjek provodi na lokalnom rječniku neke instance, pristup atributu ponekad je vrlo složen. Kad god se pristupa atributu, interpreter prvo pretražuje rječnik instance. Ako ne nađe traženo, onda se pretražuje rječnik objekta klase koja se koristila za stvaranje instance. Ako ni to nije urodilo plodom, onda se provodi pretraživanje baznih klasa (što uključuje nasljeđivanje). Ako i to propadne, konačni pokušaj traženja atributa je pozivom __getattr__() metode te klase (ako je definirana). Na koncu, ako ni to ne uspije, onda se podiže AttributeError iznimka. Kad se želi stvoriti instanca klase, treba se pozvati objekt klase kao da je funkcija. Svaki poziv vraća novi objekt instance
7.4. Instance
61
te klase: anInstance = C5() Ugrađena funkcija isinstance(O,C) s objektom klase kao argumentom C vraća True ako je objekt O instanca klase C ili bilo koje podklase C. U protivnom isinstance vraća False.
7.4.1
__init__
Kada klasa ima ili nasljeđuje metodu __init__, poziv objektu klase implicitno izvršava __init__ na novoj instanci kako bi se obavila inicijalizacija potrebna instanci. Argumenti koji se predaju putem poziva moraju odgovarati formalnim parametrima __init__. Na primjer, u sljedećoj klasi: class C6: def __init__(self,n): self.x = n Evo kako stvoriti jednu instancu klase C6: jedna_instanca = C6(42) Kako je pokazano u C6 klasi, metoda __init__ obično sadrži naredbe koje povezuju atribute instance. Metoda __init__ ne smije vraćati nikakvu vrijednost osim vrijednosti None, jer svaka druga vraćena vrijednost uzrokuje TypeError iznimku. Glavna svrha __init__ je povezivanje, tj. stvaranje atributa novostvorene instance. Atributi instance se također mogu povezivati ili re-povezivati i izvan __init__ metode. Programski kod bit će čitljiviji ako se svi atributi klasne instance inicijalno povežu naredbama u metodi __init__.
7.4.2
Atributi objekata instance
Jednom kada se stvori instanca, može se pristupiti njenim atributima (podacima i metodama) koristeći točka (.) operator. Na primjer: anInstance.hello( ) print anotherInstance.x
# ispisuje: Hello # ispisuje: 42
Objektu instance može se dodati neki atribut povezivanjem neke vrijednosti na referencu atributa. Na primjer: class C7: pass z = C7( ) z.x = 23 print z.x
# ispisuje: 23
Objekt instance z sada ima atribut koji se zove x, povezan na vrijednost 23, i z.x se odnosi na taj atribut. To povezivanje atributa omogućuje također posebna metoda __setattr__ . Stvaranje instance implicitno definira dva atributa instance. Za svaku instancu z, z.__class__ je klasa objekta kojemu z pripada, a z.__dict__ je riječnik koji z koristi za čuvanje svih svojih ostalih atributa. Na primjer, za instancu z koja je upravo stvorena: print z.__class__.__name__, z.__dict__
# ispisuje: C7, {’x’:23}
Oba ova atributa mogu se re-povezati (ali ne odvezati), iako je ovo rijetko nužno. Za bilo koji objekt instance z, bilo koji objekt x, i bilo koji identifikator S (osim __class__ i __dict__), z.S=x je ekvivalentan z.__dict__[’S’]=x (osim ako __setattr__ posebna metoda presretne pokušaj povezivanja). Na primjer, za poznatu stvarenu instancu z: z.y = 45 z.__dict__[’z’] = 67 print z.x, z.y, z.z
# ispisuje: 23, 45, 67
Nema razlike u atributima instance stvorenima s funkcijom __init__, zadacvanjem preko atributa ili po eksplicitnom povezivanju sa z.__dict__.
62
Python - objektni jezik
7.4.3
Tvornička funkcija
Česta želja je stvoriti instance različitih klasa ovisno o nekim uvjetima ili željeti izbjeći stvaranje nove instance ako je postojeća još uvijek dostupna za korištenje. Te bi se potrebe mogu izvesti tako da __init__ vrati specifičan objekt, ali to nije moguće jer Python podiže iznimku kad __init__ vrati bilo koju vrijednost osim None. Najbolji način implementacije fleksibilnog stvaranja objekata je koristeći običnu funkciju, a ne pozivanjem objekta klase izravno. Funkcija koja se koristi u ovu svrhu zove se tvornička funkcija. Pozivanje tvorničke funkcije je fleksibilnije rješenje, jer takva funkcija može vraćati postojeću instancu koja se može ponovno koristiti ili stvoriti novu instancu pozivanjem odgovarajuće klase. Recimo da se ima dvije slične klase (SpecialCase i NormalCase) i da se treba fleksibilno generirati jedna od njih, ovisno o argumentu. Sljedeća tvornička funkcija appropriateCase to omogućuje: class SpecialCase: def amethod(self): print "special" class NormalCase: def amethod(self): print "normal" def appropriateCase(isnormal=1): if isnormal: return NormalCase( ) else: return SpecialCase( ) aninstance = appropriateCase(isnormal=0) aninstance.amethod( ) # ispisuje "special", kako je tra\v{z}eno
7.4.4
Brojanje referenci i uništenje instance
Sve instance imaju brojilo referenci. Ako brojilo referenci postane jednako nuli, instanca se briše. Iako postoji više načina kako izbrisati referncu, najčešće program koristi del naredbu za brisanje reference na objekt. Ako to utječe da se brojilo referenci objekta smanji na nulu, program poziva __del__() metodu. Pritom naredba del ne mora nužno direktno zvati __del__(). Sakupljač smeća konačno kupi sve instance koje su ostale bez referenci.
7.5
Reference atributa
Referenca atributa je izraz u obliku x.name, gdje je x bilo koji izraz, a name identifikator zvan atributno ime. Mnoge vrste Python objekata imaju atribute, ali referenca atributa ima posebnu bogatu semantiku gdje se x odnosi na klasu ili instancu. Metode su također atributi, tako da se sve što se odnosi na atribute generalno odnosi i na pozivajuće atribute (npr. metode). Neka je x instanca klase C, koja se naslijeđuje od bazne klase B. Obje klase i instanca imaju nekoliko atributa (podataka i metoda) kako slijedi: class B: a = 23 b = 45 def f(self): def g(self): class C(B): b = 67 c = 89 d = 123 def g(self): def h(self): x = C( ) x.d = 77 x.e = 88
print "metoda f u klasi B" print "metoda g u klasi B"
print "metoda g u klasi C " print "metoda h u klasi C"
7.6. Metode povezivanja i odvezivanja
63
Neka imena atributa su posebna. Na primjer, C.__name__ je string ’C’, tj. ime klase. C.__bases__ je n-terac (B, ), tj. n-terac C-ovih baznih klasa. x.__class__ je klasa C, klasa kojoj x pripada. Kada se odnosi na atribute s jednim od ovih posebnih imena, referenca atributa gleda izravno u poseban pretinac (eng. slot) u objektu klase ili instance i uzima vrijednost koju tamo nađe. Zato se ovi atributi nikada ne mogu odvezati. Re-povezivanje je dopušteno, tako da se imena i bazne klase ili klase instance mogu mijenjati, ali ovo je napredna tehnika i rijetko nužna. Klasa C i instanca x imaju još jedan poseban atribut, rječnik s imenom __dict__. Svi ostali atributi klase ili instance, osim nekoliko posebnih, su sadržani kao članovi u __dict__ atributu klase ili instance. Osim posebnih imena, kada se koristi sintaksa x.name za referenciranje na atribut instance x, proces traženja odvija se u dva koraka: • Kada je ’name’ ključ u x.__dict__, x.name uzima i vraća vrijednost u x.__dict__[’name’] • Inače, x.name prebacuje proces pretrage klasi od x (tj. radi identično kao x.__class__.name) Slično tome, potraga za referencom atributa C.name na objektu klase C također se odvija u dva koraka: • Kada je ’name’ ključ u C.__dict__, C.name uzima i vraća vrijednost u C.__dict__[’name’] • Inače, C.name prebacuje potragu na C-ovu baznu klasu, što znači da se vraća na C.__bases__ i pokušava potragu imena name na svakoj od njih Kada ova dva postupka potrage ne uspiju naći atribut, Python podiže AttributeError iznimku. Međutim, ako klasa x-a definira ili naslijedi posebnu metodu __getattr__, Python poziva x.__getattr__(’name’), a ne podiže iznimku. Korisno je razmotriti sljedeće reference atributa: print x.e, x.d, x.c, x.b. x.a
# ispisuje: 88, 77, 89, 67, 23
x.e i x.d uspijevaju u prvom koraku prvog procesa traženja, jer su ’e’ i ’d’ ključevi u x.__dict__. Zato potraga ne ide dalje, nego vraća 88 i 77. Ostale tri reference moraju doći na 2. korak prvog procesa i gledati u x.__class__ (tj. u C). x.c i x.b uspijevaju u 1. koraku drugog procesa potrage, jer su ’c’ i ’b’ ključevi u C.__dict__. Zato potraga ne ide dalje, nego vraća 89 i 67. Konačno, x.a dospijeva skroz do 2. koraka drugog procesa, gledajući u C.__bases__[0] (tj. u B). ’a’ je ključ u B.__dict__, tako da x.a napokon uspijeva i vraća 23. Proces potrage atributa događa se samo onda, ako se odnosi na atribute, a ne ako se atributi povezuju. Kada se poveže ili odveže atribut čije ime nije posebno, specijalno, mijenja se samo ulaz u __dict__. Drugim riječima, u slučaju povezivanja atributa nema procesa potrage.
7.6
Metode povezivanja i odvezivanja
Prvi korak procesa potrage reference atributa zapravo čini dodatnu zadaću kada je pronađena vrijednost funkcija. U ovom slučaju, referenca atributa ne vraća funkcijski objekt izravno, nego pakira funkciju u nepovezani objekt metode (engl. unbound method object) ili povezani objekt metode (engl. bound method object). Ključna razlika između povezanih i nepovezanih metoda je da nepovezana metoda nije pridružena s nikakvom instancom, dok povezana metoda jest. Atributi f, g, i h iz prethodnog primjera su funkcije, tako da referenca atributa na bilo koji od njih vraća objekt metode koji pakira odgovarajuću funkciju. Korisno je pogledati sljedeće: print x.h, x.g, x.f, C.h, C.g, C.f Ova naredba daje (vraća) tri povezane metode, koje su predstavljene stringom: > a onda tri nepovezane, predstavljene kao:
64
Python - objektni jezik
Povezane metode dobiju se kada je referenca atributa na instancu x, a nepovezane kada je referenca atributa na klasu C. Budući da je povezana metoda već pridružena određenoj instanci, metoda se poziva na sljedeći način: x.h(
)
# ispisuje: method h in class C
Klučna stvar koja treba ovdje primjetiti je to da se prvi argument metode (self), ne određuje uobičajenom sintaksom pridruživanja argumenata. Povezana metoda instance x implicitno povezuje parametar self s objektom x. Zato tijelo metode može pristupiti atributima instance kao atributima self, iako se ne prenosi eksplicitni argument metodi. Nepovezana metoda nije povezana s određenom instancom, pa se mora specificirati odgovarajuća instanca kao prvi argument kod pozivanja nepovezane metode. Na primjer: C.h(x)
# ispisuje: method h in class C
Nepovezane metode se pozivaju puno rjeđe nego povezane metode. Najveća korist nepovezanih metoda je za pristup premošćenim metodama. Povezane metode koriste se kad je referenca atributa na isntanci x, a nepovezane kad je referenca atributa na klasi C.
7.6.1
Detalji nepovezanih metoda
Kada se referenca atributa klase odnosi na funkciju, referenca na taj atribut vraća nepovezanu metodu koja obavija (eng. wrap) funkciju. Nepovezana metoda ima tri atributa uz one objekta funkcije koji obavija: im_class je objekt klase koji daje metodu, im_func je upakirana funkcija, a im_self je uvijek None. Ovi svi atributi su nepromjenljivi, read-only, što znači da njihov pokušaj re-povezivanja ili odvezivanja podiže iznimku. Nepovezana metoda se može pozvati isto kao pozivanje njene funkcije im_func, ali prvi argument u bilo kojem pozivu mora biti instanca od im_class ili potomak. Drugim riječima, poziv nepovezanoj metodi mora imati najmanje jedan argument, koji odgovara prvom formalnom parametru (konvencionalno imenovanom self).
7.7
Nasljeđivanje
Nasljeđivanje je mehanizam stvaranja novih klasa koje specijaliziraju ili mijenjaju ponašanje postojeće klase. Originalna klasa zove se temeljna klasa (bazna, eng. base class) ili nadklasa, superklasa (engl. superclass). Nova klasa se zove izvedena klasa ili podklasa (eng. subclass). Kada se klasa stvara putem nasljeđivanja, ona nasljeđuje atribute definirane u njenim temeljnim klasama. Međutim, izvedena klasa može redefinirati bilo koji od ovih atributa i dodati nove vlastite atribute. Nasljeđivanje se specificira s listom imena temeljnih klasa koje se odvajaju zarezom u class naredbi. Na primjer: class A: varA = 42 def method1(self): print "Class A : method1" class B: varB = 37 def method1(self): print "Class B : method1" def method2(self): print "Class B : method2" class C(A,B): # Inherits from A and B varC = 3.3 def method3(self): print "Class C : method3"
7.7. Nasljeđivanje
65
class D: pass class E(C,D): pass Ako se traži atribut definiran u temeljnoj klasi, onda se koristi algoritam u dubinu (eng. depth-first search) za pretraživanje i to u temeljnim klasama kako su navedene u poretku prilikom definicije klase. Na primjer, u klasi E u prethodnom primjeru, temeljne klase se pretražuju redoslijedom C, A, B, D. U slučaju da višestruke temeljne klase definiraju isti simbol, uzet će se prvi simbol kojeg procs traženja nađe. Na primjer: c = C() c.method3() c.method1() c.varB
# # # #
Create Invoke Invoke Access
a ’C’ C.method3(c) A.method1(c) B.varB
Ako izvedena klasa definira atribut s istim imenom kao atribut u temeljnoj klasi, onda će instance od izvedene klase koristiti atribute izvedene, a ne temeljne klase. Ako se ipak želi koristiti originalni atribut, onda se mora napisati puno ime do tog atributa, tj. ime_temeljne_klase.atribut, kao na primjer: class D(A): def method1(self): print "Class D : method1" A.method1(self)
# poziva baznz class metodu
Jedna posljedica ove činjenice nalazi se u inicijalizaciji klasnih instanci. Kad se instanca stvara, onda se ne poziva metoda __init__() temeljnih klasa. To znači, da je u izvedenoj klasi nužno načiniti ispravnu inicijalizaciju temeljne klase, ako je to potrebno. Na primjer: class D(A): def __init__(self, args1): # Initialize the base class A.__init__(self) # Initialize myself ... Slični koraci mogu također biti nužni kad se definiraju akcije čišćenja (brisanja objekata) u __del__() metodi. Kada se koristi referenca atributa C.name na objekt klase, i ’name’ nije ključ u C.__dict__, potraga se implicitno proslijeđuje na svaki objekt klase koji je u C.__bases__, po redoslijedu navođenja. C-ove bazne klase mogu imati i vlastite bazne klase. U ovom slučaju, potraga rekurzivno prosljeđuje naviše, po drvetu naslijeđa, zaustavljajući se kada je ’name’ nađeno. Potraga je po dubini, što znači da pregledava pretke svake bazne klase od C prije pregleda sljedeće bazne klase od C. Slijedi primjer: class Base1: def amethod(self): print "Base1" class Base2(Base1): pass class Base3: def amethod(self): print "Base3" class Derived(Base2, Base3): pass aninstance = Derived( ) aninstance.amethod( )
# ispisuje: "Base1"
U ovom slučaju potraga za metodu započinje u Derived. Ako tamo nije pronađena, potraga se nastavlja na Base2. Ako ni tamo atribut nije nađen, potraga ide na pretka Base2, tj. na Base1, gdje je atribut napokon nađen. Tako se pretraga zaustavlja na toj točki i nikada ne uzima u obzir Base3, gdje bi se taj atribut također našao.
66
Python - objektni jezik
7.7.1
Premošćujući (engl. overriding) atributi
Potraga za atributom, kako je objašnjeno, ide naviše po drvetu naslijeđa (prema precima), te se zaustavlja kada je atribut pronađen. Potomačke klase pregledavaju se prije predaka, što znači da kada podklasa definira atribut s istim imenom kao i onaj na superklasi, pretraga nalazi definiciju na podklasi i tu se zaustavlja. Ovo je poznato kao premošćivanje definicije u superklasi koje obavlja podklasa: class B: a = 23 b = 45 def f(self): def g(self): class C(B): b = 67 c = 89 d = 123 def g(self): def h(self):
print "method f in class B" print "method g in class B"
print "method g in class C" print "method h in class C"
U ovom kodu, klasa C premošćuje atribute b i g od njene superklase B.
7.7.2
Posluživanje metoda superklase
Kada podklasa C premosti metodu f svoje superklase B, tijelo C.f često želi predati neki dio svoje operacije implementaciji metode superklase. Ovo se može napraviti koristeći nepovezanu metodu, kako slijedi: class Base: def greet(self, name): print "Welcome ", name class Sub(Base): def greet(self, name): print "Well Met and", Base.greet(self, name) x = Sub( ) x.greet(’Alex’) Predaja superklasi, u tijelu Sub.greet, koristi nepovezanu metodu dobivenu referencom atributa Base.greet na superklasi, i zato prenosi sve atribute normalno, uključujući self. Predaja ili posluživanje implementaciji superklase je glavna korist nepovezanih metoda. Jedno vrlo često korištenje takvog posluživanja događa se pomoću posebne metode __init__. Kada je instanca stvorena u Pythonu, metode __init__ baznih klasa nisu automatski pozvane, jer se mogu naći i u nekim drugim objektno orijentiranim jezicima. Zato je na podklasi da obavi adekvatnu inicijalizaciju koristeći posluživanje po potrebi. Na primjer: class Base: def __init__(self): self.anattribute = 23 class Derived(Base): def __init__(self): Base.__init__(self) self.anotherattribute = 45 Ako __init__ metoda klase Derived nije implicitno pozvala metodu klase Base, instanca Derived bi promašila taj dio njihove inicijalizacije, te zato takve instance ne bi imale atribut anattribute.
7.7. Nasljeđivanje
7.7.3
67
"Brisanje" atributa klasa
Nasljeđivanje i premošćivanje pružaju jednostavan i učinkovit način dodavanja ili modifikacije atributa klasa (metoda) ne-invazivno (tj. bez modificiranja klase u kojoj su atributi definirani), dodavanjem ili premošćivanjem atributa u podklasama. Međutim, nasljeđivanje ne podržava direktno slične načine brisanja (skrivanja) atributa baznih klasa bez direktnog pristupa. Ako podklasa jednostavno ne uspije definirati (premostiti) atribut, Python nalazi definiciju bazne klase. Ako je potrebno izvršiti takvo brisanje, mogućnosti uključuju: Premošćivanje metode i podizanje iznimke na tijelo metode Izbjegavanje nasljeđivanja, držanje atributa na drugom mjestu osim podklasnog __dict__, i definacija __getattr__ zbog selektivne predaje ili posluživanja Korištenje objektnog modela novog stila i premošćivanje __getattribute__ sa sličnim učinkom.
7.7.4
Višeobličje (eng. polymorphism)
Višeobličje ili polimorfizam, ili dinamičko povezivanje potpuno se obražuje kroz ’lookup’ proces traženja atributa opisanog prethodno u nasljeđivanju objekata. Kad god se metodi pristupa sa obj.method(), prvo se method locira traženjem __dict__ atributa instance, pa instancine klasne definicije, pa temeljnih klasa. To traženje uvijek ide u tom redoslijedu. Prvi uspješni pronalazak koristi se kao tražena metoda.
7.7.5
Skrivanje informacije (engl. information hiding)
Pretpostavlja se da su svi atributi javni (’public’). To znači da su svi atributi klasne instance dohvatljivi bez ikakvog ograničenja. To također povlači da sve što je definirano u temeljnoj klasi nasljeđuje se i dohvatljivo je u izvedenoj klasi. Takvo ponašanje je često nepoželjno u objektu orjentiranim primjenama jer to otkriva nutarnju strukturu objekta i može voditi konfliktima prostora imena između objekata definiranih u izvedenoj klasi i onih definiranih u temeljnoj klasi. Da bi se riješio ovaj probleem, uvedeno je da sva imena u klasi koja počinju s dvostrukom donjom crtom (__) , kao što je __Foo, što se pretvara u oblik _Classname __Foo. To pruža rješenje za klasu da ona ima privatne atribute, budući da privatna imena u izvedenoj klasi neće kolidirati s imenima u temeljnoj klasi jer su imena klasa nužno različita, a dolaze ispred imena atributa. Na primjer: class A: def __init__(self): self.__X = 3
# Pretvara se u self._A__X
class B(A): def __init__(self): A.__init__(self) self.__X = 37
# Pretvara se u self._B__X
Iako ovakva shema daje iluziju sakrivanja podataka, ne postoji stvarni mehanizam da bi se spriječio pristup "privatnim" atributima neke klase. To znači da, ako su poznati klasa i njen atribut, onda se mogu dohvatiti s gore opisanim punim imenom iz bilo koje instance.
7.7.6
Operatorsko punjenje
Korisnički objekti mogu se načiniti da rade sa svim Python-ovim ugrađenim operatorima dodajući posebne metode. Na primjer, sljedeća klasa nadopunja kompleksne brojeve sa standardnim matematičkim operatorima i prisilnim tipovima kako bi se ostvarilo miješanje kompleksnih brojeva s cijelim i realnim brojevima. class Complex: def __init__(self,real,imag=0): self.real = float(real) self.imag = float(imag)
68
Python - objektni jezik
def __repr__(self): return "Complex(%s,%s)" % (self.real, self.imag) def __str__(self): return "(%g+%gj)" % (self.real, self.imag) # self + other def __add__(self,other): return Complex(self.real + other.real, self.imag + other.imag) # self - other def __sub__(self,other): return Complex(self.real - other.real, self.imag - other.imag) # -self def __neg__(self): return Complex(-self.real, -self.imag) # other + self def __radd__(self,other): return Complex.__add__(other,self) # other - self def __rsub__(self,other): return Complex.__sub__(other,self) # Coerce other numerical types to complex def __coerce__(self,other): if isinstance(other,Complex): return self,other try: # See if it can be converted to float return self, Complex(float(other)) except ValueError: pass U ovom primjeru, postoji nekoliko zanimljivih detalja: • Prvo, normalno ponašanje od __repr__() je stvaranje stringa koji će se izvršiti kako bi se ponovno načinio objekt. U ovom slučaju stvara se string oblika "Complex(r,i)". U drugom slučaju, metoda __str__() stvara string koji je namijenjen za lijepi formatirani izlaz (to je string koji će se ispisati s pomoću print naredbe). • Drugo, da bi se radilo s operatorima u kojima se kompleksni brojevi pojavljuju i na lijevoj i na desnoj strani operatora, moraju se koristiti __op__() i __rop__() metode. • Konačno, __coerce__ metoda koristi se u dohvaćanju operacija koje uključuju mijeašne tipove podataka. U ovom slučaju, drugi numerički tipovi pretvaraju se u kompleksne brojeve tako da se mogu koristiti u metodama kompleksne aritmetike.
7.8
Testovi pripadnosti klasa i tipova
Trenutačno, postoji odijeljenost između tipova i klasa. To konkretno znači, da se ugrađeni tipovi poput lista i rječnika ne mogu specijalizirati preko nasljeđivanjem, jer ono za njih ne postoji. Isto tako niti klase ne mogu definirati nove tipove. Ustvari, sve klasne definicije imaju tip ClassType, dok sve klasne instance imaju tip InstanceType. Zbog toga je izraz type(a) == type(b) istinit, za bilo koja dva objekta koja su instance klase (čak i ako su stvorena iz različitih klasa). Provjera pripadnosti klasi provodi se upotrebom ugrađene funkcije isinstance(obj,cname). Ova funkcija vraća istinu, ako objekt obj pripada klasi cname ili bilo kojoj klasi izvedenoj iz cname. Na primjer:
7.8. Testovi pripadnosti klasa i tipova
class A: pass class B(A): pass class C: pass a = A() b = B() c = C()
# Instanca od ’A’ # Instanca od ’B’ # Instanca od ’C’
print isinstance(a,A) print isinstance(b,A) print isinstance(b,C)
# Vra\’{c}a True # Vra\’{c}a True, B je izveden iz A # Vra\’{c}a False, C nije izveden iz A
Slično, ugrađena funkcija issubclass(A ,B ) vraća istinu ako je A podklasa klase B. Na primjer: issubclass(B,A) issubclass(C,A)
# Vra\’{c}a True # Vra\’{c}a False
Funkcija isinstance() može se koristiti za izvršavanje provjere tipa s obzirom na bilo koji ugrađeni tip: import types isinstance(3, types.IntType) isinstance(3, types.FloatType)
# Vra\’{c}a True # Vra\’{c}a False
Ovo je preporučen način provjere tipa među ugrađenim tipovima, jer će razlika između tipova i klasa možda isčeznuti u budućim inačicama Python-a.
69
POGLAVLJE
Moduli i paketi Veliki Python programi često se organiziraju kao paketi modula. Nadalje, veliki broj modula već je uključen u Python-ovu knjižnicu.
8.1
Moduli
Moguće je uključiti u modul bilo koji valjanu datoteku s izvornim kôdom, i pozvati ga s naredbom import. Na primjer, neka je sljedeći kôd spremljen u datoteku ’spam.py’: # file : spam.py a = 37 # Varijabla def foo: # Funkcija print "I’m foo" class bar: # Klasa def grok(self): print "I’m bar.grok" b = bar() # Tvorba instance Pozvati u memoriju ovakav kôd kao modul, postiže se naredbom import spam. Prvi put kad se import koristi da se modul napuni u memoriju, događaju se tri stvari: 1. On stvara novi prostor imena koji služi svim objektima definiranim u pripadnoj izvornoj datoteci. Ovaj prostor imena dohvaća se kad funkcije i metode definirane unutar modula koriste naredbu global. 2. On izvršava kod koji je sadržan u modulu unutar novonastalog prostora imena. 3. On izvršava ime unutar pozivatelja koji se odnosi na prostor imena modula. Ovo ime podudara se s imenom modula i korisiti se kako slijedi: import spam print spam.a spam.foo() c = spam.bar() ...
# Loads and executes the module ’spam’ # Accesses a member of module ’spam’
Uvlačenje, uvoz (eng. import) višestrukih modula izvodi se tako da se iza naredbe import dopišu imena modula, odijeljenih zarezom, ovako: 71
8
72
Moduli i paketi
import socket, os, regex Moduli se mogu uvući (importirati ) koristeći alternativna imena, upotrebom poveznice as. Na primjer: import os as system import socket as net, thread as threads system.chdir("..") net.gethostname() Naredba from koristi se za specifične definicije unutar modula s trenutačnim prostoru imena. Ova naredba je identična naredbi import osim što se stvara ime koje se odnosi na novo stvoreni modul prostora imena, te referenca na jedan ili više objekata definiranih u modulu koji se smjestio u trenutačnom prostoru imena: from socket import gethostname # Stavlja gethostname u trenuta\v{c}ni prostor imena
print gethostname() # Koristi se bez imena modula socket.gethostname() # Pogre\v{s}ka imena (NameError: socket) Naredba from tako{\dj}er prihva\’{c}a zarezom odvojena imena objekata. Zvjezdica (engl. asterisk from socket import gethostname, socket from socket import * # Puni sve definicije u trenuta\v{c}ni prostor imena Moduli se mogu preciznije upravljati skupom imena koji se učita s from module import * definiranjem liste __all__. Na primjer: # module: foo.py __all__ = [ ’bar’, ’spam’ ]
# Imena koja \’{c}e se uvu\’{c}i sa *
Nadalje, poveznica as može se koristiti da se promijeni ime posebnih objekata koji se u memoriju učitaju s naredbom from. Na primjer: from socket import gethostname as hostname h = hostname() Naredba import može se pojaviti na bilo kojem mjestu u programu. Međutim, kod u svakom modulu izvodi se samo jednom, bez obzira kako često se naredba import izvršava. Iduće import naredbe jednostavno stvaraju referencu na prostor imena modula koji je stvoren s prethodnom import naredbom. U varijabli sys.modules može se naći rječnik koji sadrži imena svih trenutačno napunjenih modula. On preslikaa imena modula na njihove objekte. Sadržaj rječnika se koristi za određivanje je li import napunio svježu kopiju modula ili se isti modul poziva drugi put. Naredba from module import * može se koristiti samo na vrhu modula. Drugim riječima, nije dopušteno koristiti ovaj oblik import naredbe unutar tijela funkcije, zbog njegove interakcije s pravilima funkcijskog dosega (engl. scoping rules). Svaki modul definira variable __name__ koja sadrži ime modula. Programi mogu ispitivati ovu varijablu da se odredi modul u kojem se naredbe izvršavaju. Gornji (top-level) modul interpretera zove se __main__. Programi zadani na naredbenoj liniji ili unešeni interaktivno, uvijek se izvode unutar __main__ modula. Ponekad program može promijeniti ovo ponašanje, ovisno o tomu je li uvučen iz modula ili je izveden u __main__ okolišu. To se može postići na ovaj način: # provjera je li se vrti kao program if __name__ == ’__main__’: # Da naredbe else: # ne, uvucen je kao modul Naredbe
8.1. Moduli
8.1.1
Modulski put traženja (engl. Search Path)
Kad se učitaju moduli, interpreter traži listu imenika, foldera u sys.path. Tipična vrijednost sys.path može izgledati ovako: [’’, ’/usr/local/lib/python2.0’, ’/usr/local/lib/python2.0/plat-sunos5’, ’/usr/local/lib/python2.0/lib-tk’, ’/usr/local/lib/python2.0/lib-dynload’, ’/usr/local/lib/python2.0/site-packages’] Prazan string ” odnosi se na trenutačni imenik, folder. Novi imenici dodaju se u put traženja vrlo jednostavno - dodavanjem člana (stringa puta) u ovu listu.
8.1.2
Učitavanje, punjenje (engl. import) modula i compilacija
Do sada su moduli prikaani kao datoteke koje sadrže Python kod. Međutim, moduli uvučeni s naredbom import stvarno pripadaju nekoj od četiri opće kategorije: • Programi pisanii u Pythonu (.py datoteke) • C ili C++ proširenja koja su compilirana u zajedničkim (shared) knjižnicama ili DLL-ovima. • Paketima koji sadrže skupove modula • Ugrađene module pisane u C-u i povezane u Python interpreter Kad se traži modul foo, interpreter pretražuje svaki od direktorija u sys.path za sljedeće datoteke (navedene po redoslijedu pretraživanja): 1. Imenik ili folder foo koji je definiran u paketu 2. foo.so, foomodule.so, foomodule.sl, ili foomodule.dll (compilirana proširenja) 3. foo.pyo (samo ako je -O ili -OO opcija korištena) 4. foo.pyc 5. foo.py Za .py datoteke, kad se modul prvi put uvuče, importira, on se prevede, compilira u međukod (eng. bytecode) i zapisuje na disk u datoteku s proširenjem .pyc. U idućim učitanjima, interpreter puni ovaj priređeni međukod, osim ako ne dođe do promjene originalne .py datoteke (pa se .pyc datoteka mora regenerirati. Datoteke koje završavaju na .pyo koriste se u svezi sa interpreterskom -O opcijom. Ove datoteke sadrže međukod s izbačenim brojevima linija i drugim informacijama potrebnim za traženje pogrešaka (eng. debugging). Kao rezultat toga, kod je nešto manji i dopušta interpretoru nešto brže izvođenje. U slučaju -OO opcije svi dokumentacijski stringovi se također izbacuju iz datoteka. Ovo brisanje dokumentacijskih stringova pojavljuje se samo kad se .pyo datoteke stvaraju, a ne kad se pune. Ako niti jedna od ovih datoteka ne postoji u niti jednom imeniku u sys.path, onda interpreter provjerava da li ime odgovara imenu nekog ugrađenog modula. Ako ono ne postoji, onda se podiže ImportError iznimka. Compilacija datoteka u .pyc i .pyo datoteke događa se samo u sprezi s naredbom import. Programi specificirani na naredbenoj liniji ili standardnom ulazu ne proizvode takve datoteke. Naredba import u traženju datoteka razlikuje mala i velika slova u njihovom imenu. Kod operacijskih sustava koji ne podržavaju tu razliku, potrebno je o tomu voditi računa.
73
74
Moduli i paketi
8.1.3
Ponovno punjenje modula (engl. reloading)
Ugrađena funkcija reload() koristi se da se ponovno napuni i izvrši kod sadržan unutar modula prethodno učitanog s naredbom import. Ona prima objekt modula kao pojedinačni argument. Na primjer: import foo ... some code ... reload(foo)
# Reloads foo
Sve operacije uključene u modul će nakon izvođenja naredbe reload() izvesti iz novo učitanog koda. Međutim, reload() neće retroaktivno obnoviti objekte koji su nastali iz starog modula. To znači da je moguće istodobno postojanje referenci na objekte i u staroj i u novoj verziji modula. Nadalje, compilirane ekstenzije pisane u C ili C++ ne mogu se ponovono puniti naredbom reload(). Kao opće pravilo, treba izbjegavati ponovno punjenje modula, osim za vrijeme razvitka programa i traženja pogreški u njemu.
8.2
Paketi
Paketi dopuštaju da se više modula skupi zajedno pod jednim zajedničkim imenom. Ova tehnika pomaže u razlučivanju sukoba u prostoru imena modula koji se koriste u različitim primjenama. Paket se definira stvaranjem imenika (engl. directory, folder ) s istim imenom kao paket i stvaranjem __init__.py datoteke u tom imeniku. Moguće je nakon toga dodati druge izvorne datoteke (tekstovne datoteeke s Python kodom), compilirana proširenja ili podpakete u istom imeniku. Na primjer, paket se može ovako organizirati: Graphics/ __init__.py Primitive/ __init__.py lines.py fill.py text.py ... Graph2d/ __init__.py plot2d.py ... Graph3d/ __init__.py plot3d.py ... Formats/ __init__.py gif.py png.py tiff.py jpeg.py Naredba import koristi se za punjenje modula iz paketa na nekoliko načina: import Graphics.Primitive.fill Ovo učitava, uvlači, podmodul Graphics.Primitive.fill. Sadržaj tog modula mora se eksplicitno imenovati, ka na primjer: Graphics.Primitive.fill.floodfill(img,x,y,color). from Graphics.Primitive import fill
8.2. Paketi
75
Ovo učitava podmodul fill i čini ga raspolživim i bez paketnog prefiksa, na primjer: fill.floodfill(img,x,y,color). from Graphics.Primitive.fill import floodfill Ovo učitava podmodul fill i čini floodfill funkciju direktno primjenljivom; na primjer, floodfill(img,x,y,color). Kad god se neki dio paketa učita, importira, kod u datoteci __init__.py se izvršava. U najmanjem slučaju ova datoteka može biti i prazna, ali također može sadržavati kod kojim se izvode inicijalizacije koje su specifične za paket. Sve nađene datoteke __init__.py za vrijeme učitavanja, automatski se izvršavaju. Tako će naredba import Graphics.Primitive.fill pokazana ranije izvršiti __init__.py datoteke i u Graphics imeniku i u Primitive imeniku. Jedan poseban problem s paketima je obradba ovakve naredbe: from Graphics.Primitive import * Željeni rezultat ove naredbe je uvući, importirati, sve module pridružene u paketu sa trenutačnim prostorom imena. Međutim, s obzirom da dogovori oko imena datoteka (pogotovo u smislu razlikovanja velikih i malih slova) variraju od sustava do sustava, Python ne može točno odrediti koje module točno treba uključiti. Kao rezultat, ova naredba samo importira sve reference koje su definirane u __init__.py datoteci u Primitive imeniku. Ovo se ponašanje može promijeniti definiranjem liste __all__ koja sadrži sva imena modula pridružena s paketom. Ova lista treba biti definirana unutar paketa u __init__.py datoteci, kao ovo: # Graphics/Primitive/__init__.py __all__ = ["lines","text","fill",...] Ako korisnik pokrene naredbu from Graphics.Primitive import * onda se svi navedeni podmoduli učitaju, kako se i očekuje. Učitavanje samo imena paketa neće automatski učitati sve podmodule koji se nalaze u paketu. Na primjer, sljedeći kod neće raditi: import Graphics Graphics.Primitive.fill.floodfill(img,x,y,color)
# Pogresno!
Međutim, budući da importGraphics naredba izvršava __init__.py datoteku u Graphics imeniku, moguće ju je promijeniti kako bi se automatski učitali svi podmoduli: # Graphics/__init__.py import Primitive, Graph2d, Graph3d # Graphics/Primitive/__init__.py import lines, fill, text, ... Na ovaj način importGraphics naredba učitava sve podmodule i čini ih raspoloživima za pozive koristeći njihova potpuna imena. Moduli koji su sadržani unutar istog imenika paketa, mogu referencirati jedan drugog bez navođenja punog imena paketa. Na primjer, modul Graphics.Primitive.fill može učitati Graphics.Primitive.lines modul jednostavno koristeći naredbu import lines. Međutim, ako je modul smješten u drugom imeniku, onda se mora koristiti puno ime paketa. Na primjer, ako plot2d iz modula Graphics.Graph2d traži upotrebu lines iz modula Graphics.Primitive, mora se koristiti puna staza imena: from Graphics.Primitive import lines. Ako je potrebno, modul može ispitati svoju __name__ varijablu da nađe potpunu stazu svog imena. Na primjer, sljedeći kod učitava modul iz sestrinskog podpaketa znajući samo ime tog podpaketa (a ne i ime s vrha paketa): # Graphics/Graph2d/plot2d.py # Determine the name of the package where my package is located import string base_package = string.join(string.split(__name__,’.’)[:-2],’.’) # Import the ../Primitive/fill.py module exec "from %s.Primitive import fill" % (base_package,)
76
Moduli i paketi
Konačno, kad Python učitava paket, on definira specijalnu varjablu __path__ koja sadrži listu imenika koji se pretražuju, kad se se traže paketni submoduli. (Varijabla __path__ je posebna inačica sys.path varijable.) __path__ je dohvatljiv za kod sadržan u datoteci __init__.py i inicijalno sadrži jedan član s imenom foldera (imenika) paketa. Ako je potrebno, paket može dodati dodatne imenike u __path__ listu da bi se promijenila staza koja se koristi u traženju podmodula.
POGLAVLJE
Ulaz i izlaz Pod pojmom ulaz/izlaza razmatraju se opcije naredbene linije, varijable okoline, rad s datotekama, naredba print i očuvanje objekta.
9.1
Čitanje opcija i varijabli okoliša
Kad interpreter započne s radom, opcije naredbene linije spremaju se u listu sys.argv. Prvi element liste je ime programa. Idući elementi su opcije predstavljene na naredbenoj liniji iza programskog imena. Sljedeći program pokazuje kako pristupiti opcijama naredbene linije: # printopt.py # Print all of the command-line options import sys for i in range(len(sys.argv)): print "sys.argv[%d] = %s" % (i, sys.argv[i]) Izvođenjem programa proizvodi se sljedeće: % python printopt.py foo bar -p sys.argv[0] = printopt.py sys.argv[1] = foo sys.argv[2] = bar sys.argv[3] = -p % Varijable okoliša dohvaćaju se u rječniku os.environ. Na primjer: import os path = os.environ["PATH"] user = os.environ["USER"] editor = os.environ["EDITOR"] ... etc ... Promjena varijabli okoliša provodi se postavljanjem os.environ varijable. Druga je mogućnost pozivom funkcije os.putenv() function. Na primjer: os.environ["FOO"] = "BAR" os.putenv("FOO","BAR") 77
9
78
Ulaz i izlaz
9.2
Datoteke (engl. files)
Ugrađena funkcija open(name [,mode ]) otvara i stvara datoteke, kao što sljedi: f = open(’foo’) f = open(’foo’,’w’)
# Otvara ’foo’ za citanje # Otvara za pisanje
Načini otvaranja datoteke su ’r’ za čitanje (eng. read ), ’w’ za pisanje (engl. write), ili ’a’ za dodavanje sadržaja u već postojeću datoteku (eng. append ). Binarni podatci spremaju se u datoteku s oznakom ’b’, pa vrijedi ’rb’ kao način čitanja binarnih podataka, a ’wb’ kao način spremanja inarnih podataka. To je opcionalno u UNIX-u, ali nužno na Windows-ima, gdje se treba uključiti kako bi se postigla prenosivost s jednog sustava na drugi. Uz to, datoteka se može otvoriti za ažuriranje (eng. update) koristeći znak (+) character, pa vrijedi ’r+’ ili ’w+’. U slučaju otvaranja datoteke za ažuriranje, moguće je izvršiti i ulaz i izlaz podataka, dok god svaka izlazna operacija sprema iz memorije (engl. flush) svoje podatke u datoteku, prije bilo koje ulazne operacije. Ako je datoteka otvorena sa ’w+’ onda se na početku njena duljina pretvara u nulu (briše se sadržaj). open() vraća objekt datoteke (eng. file object) koji podržava methode prikazane u tablici 9.1: Tablica 9.1: Metode s datotekama Metode f.read([n]) f.readline([n]) f.readlines() f.xreadlines() f.write(s) f.writelines(l ) f.close() f.tell() f.seek(offset [, where ]) f.isatty() f.flush() f.truncate([size]) f.fileno() f.readinto(buffer,nbytes )
Opis Čita najviše n okteta (engl. bytes) Čita jednu ulaznu liniju do najviše n znakova. Ako se n iizostavi, onda čita cijelu liniju. Čita sve linije i vraća listu. Returns an opaque sequence object where each iteration reads a new line from the file. Upisuje u datoteku string s . Upisuje u datoteku sve stringove iz liste l . Zatvara datoteku. Vraća trenutačno kazalo (brojilo znakova) datoteke. Traži novu poziciju u datoteci. Vraća 1 ako je f interactivni terminal. Sprema (eng. flushes) izlazni mem. bufer u datoteku. Skraćuje datoteku na najviše size okteta. Vraća cjelobrojni identifikator datoteke. Učitava nbytes podataka iz memorijskog buffer objekta.
Metoda read() vraća čitavu datoteku kao jedan string, osim ako je zadan jedan proizvoljan parametar length kojim se odrežuje maksimalna duljina učitanih okteta. Metoda readline() vrća sljedeću liniju ulaza, uključujući i znak završetka linije (eng. newline terminator ); metoda readlines() vraća sve ulazne linije kao listu stringova. Metoda readline() dodatno prhvaća makismalnu duljinu linije n. Ako je linija duža od n okteta, frunkcija vraća samo n učitanih okteta. Ostatak podataka na liniji se ne briše, već se učitava u idućim čitanjima. Obje metode: readline() i readlines() ovise o operacijskom sustavu te obrađuju na različite načine završetke linija (na primjer, ’ n’ u odnosu na ’ r n’). Metoda xreadlines()vraća poseban objekt koji omogućuje učitavanje linija datoteke iteracijskim postupkom, umjesto cjelokupnog učitavanja linija odjednom u memoriju, kao što to radi readlines() metoda. Na primjer:
9.3. Standardni ulaz, izlaz i pogreška (engl. Input, Output, Error)
for line in f.xreadlines(): # Naciniti nesto s linijom ... Metoda write() upisuje string u datoteku, a metoda writelines()upisuje listu stringova u datoteku. U svim ovim slučajima, string može sadržavati binarne podatke, uključujući umetnute null znakove. Metoda seek()koristi se za direktan pristup nekom mjestu u datoteci, definiranom zadanim offset parametrom, koji se nadovezuje na vrijednost parametra where. Ako je where jednak 0 (što je pretpostavljena vrijednost), seek() pretpostavlja da je vrijednost offset relativna s obzirom na početak datoteke; ako je vrijednost parametra where jednaka 1, pozicija se računa relativno s obzirom na trenutačnu poziciju, a ako je jednaka 2, pomak se računa od kraja datoteke. Metoda fileno() vraća cjelobrojno kazalo datoteke i ponekad se koristi u ulazno/izlaznim operacijama niske razine u stanovitim knjižničkim modulima. Na strojevima koji podržavaju velike datoteke (veće od 2 GB) metode seek()i tell() koriste duge cijele brojeve (long integers). Objekti datoteke ima također atribute prikazane u sljedećoj tablici 9.2: Tablica 9.2: Atributi datoteka Atributi f.closed f.mode f.name
f.softspace
9.3
Opis Boolova vrijednost koja pokazuje stanje datoteke:0 ako je datoteka otvorena, a 1 ako je zatvorena. Ulazno/izlazni mod (I/O) za datoteku. Ime datoteke, ako je otvorena s open(). Inače, atribut predstavlja string koji pokazuje izvorni kod datoteke. Boolova vrijednost koja pokazuje da li se praznina treba ispisivati ispred druge vrijednosti kad se koristi print naredba.
Standardni ulaz, izlaz i pogreška (engl. Input, Output, Error)
Python interpreter raspolaže s tri standardna objekta datoteka, poznata kao standard input, standard output i standard error, koji se nalaze u sys modulu i pozivaju sa sys.stdin, sys.stdout i sys.stderr. Stdin je objekt datoteke, koji odgovara tijeku (engl. stream) ulaznih znakova koji dolaze od interpretera. Stdout je objekt datoteke koja prima izlaz kojeg proizvodi naredba print. Stderr je datoteka koja prima poruke o pogreškama. Najčešće je stdin preslikan tj. odgovara korisničkoj tipkovnici, dok su stdout i stderr preslikavaju na ispis na zaslon računala. Metode opisane u prethodnom odlomku, mogu se korisititi i za izvođenje sirovog ulaza/izlaza (eng. I/O) u komunikaciji s korisnikom. Na primjer, sljedeća funkcija čita ulaznu liniju sa standardnog ulaza: def gets(): text = "" while 1: c = sys.stdin.read(1) text = text + c if c == ’\n’: break return text Alternativno, ugrađena funkcija raw_input(prompt) može čitati liniju teksta sa standardnog ulaza stdin: s = raw_input("type something : ") print "You typed ’%s’" % (s,)
79
80
Ulaz i izlaz
Konačno, nasilni prekid preko tipkovnice (najčešće generiran sa Ctrl+C) rezultira u KeyboardInterrupt izuzetku koji se može dohvatiti koristeći potporu izuzetaka (eng. exception handler ). Ako je potrebno vrijednosti od sys.stdout, sys.stdin i sys.stderr mogu se zamijeniti s ostalim objektima datoteke. U tom slučaju naredba print i funkcije raw_input koriste nove vrijednosti. Originalne vrijednosti od sys.stdout, sys.stdin i sys.stderr na početku rada interpretera su također dohvatljive u sys.__stdout__, sys.__stdin__ i sys.__stderr__. Dobro je primjetiti da se u nekim slučajima sys.stdin, sys.stdout i sys.stderr mogu promijeniti od strane integriranog razvojnog okruženja (eng. integrated development environment - IDE ). Na primjer, kad se Python izvod pod Idle-om, onda se sys.stdin zamjenjuje s objektom koji se ponaša kao datoteka, iako je on stvarno objekt razvojnog okruženja. U ovom slučaju, stanovite metode niske razine kao što su read() i seek() ne mogu se izvoditi.
9.4
Naredba print
Naredba print daje izlaz u datoteku koja se pridružena objektu sys.stdout. Ta naredba prihvaća listu zarezima odvojenih objekata, kao na primjer: print "Vrijednosti varijabli su: ", x, y, z Za svaki se objekt poziva funkcija str() kako bi proizvela string na izlazu.. Ovi izlazni stringovi se onda povezuju i međusobno odjeljuju prazninama, kako bi se proizveo konačni izlazni string. Izlaz se zaključuje znakom za novi red, osim u slučaju kad se print naredba završava zarezom. U tom slučaju, ispisuje se samo dodatna praznina na koncu stringa, ali ne i novi red. Na primjer: print "Vrijednosti varijabli su: ", x, y, z, w # ispisuje isti tekst, koriste\’{c}i dvije print naredbe print " Vrijednosti varijabli su: ", x, y, # Ne ispisuje novi redak print z, w Upotrebom string formatirajućeg operatora (%) dobiva se formatirani izlaz. Na primjer: print "Vrijednosti su: %d %7.5f %s" % (x,y,z) # Formatirani UL/IZL (I/O) Moguće je promijeniti odredište print naredbe dodajući specijalni »file modifikator, gdje je file datoteka objekta u koju korisnik piše. Na primjer: f = open("izlaz","w") print >>f, "Ovdje Python!" ... f.close() Kombinacijom formatiranog ulaz/izlaza stringova s trostrukim navodnicima i rječnika, dobiva se snažna pomoć u pisanju kompjutorski generiranih tekstova, kakva su, na primjer, cirkularna pisma. Obično se u takvim pismima trebaju opća imena, adrese i neki brojni iznosi zamijeniti stvarnima, kao na primjer ovdje : Dragi gosp. Miki, Molim Vas vratite mi moj bicikl ili mi platite 150 Eura. S po\v{s}tovanjem, Python Mla{\dj}i Da bi se to načinilo, prvo se formira string s trostrukim navodnicima koji sadrži tekst, a onda rječnik, koji sadrži stvarne vrijednosti varijabli:
9.5. Otpornost
81
form = """\ Dragi %(ime)s, Molim Vas vratite mi moj %(vlasnistvo)s ili mi platite $%(iznos)0.2f Eura. S po\v{s}tovanjem, Python Mla{\dj}i """ print form % { ’ime’: ’gosp. Miki’, ’vlasnistvo’: ’bicikl’, ’iznos’: 150, } Za ovakve obrasce koji imaju puno linija i članova koji se trebaju zamijeniti, puno je jasnije napisati jednu print naredbu s popisom članova u rječniku, nego svaki tekst pisati pojedinačno.
9.5
Otpornost
Često je potrebno spremiti objekt u datoteku i poslije ga iz datoteke pročitati. Jedan način je da se načini niz funkcija za spremanje objekta u datoteku i isto tako funkcije za čitanje. Tu mogu nastati različiti pristupi, ovisno o sklonostima i razmišljanju programera. Jedan ugrađeni pristup ovom problemu je serijalizacija objekta koja se postiže upotrebom pickle i shelve modula. Modul pickle serijalizira objekt u tok okteta (eng. stream of bytes) koje se mogu zapisati u datoteku. Na primjer, sljedeći kôd zapisuje objekt u datoteku: import pickle object = someObject() f = open(filename,’w’) pickle.dump(object, f) # Sprema objekt Ponovno obnavljanje objekta posti\v{z}e se sljede\v{c}im kôdom: import pickle f = open(filename,’r’) object = pickle.load(f) # Obnavlja objekt Modul shelve je sličan, ali objekte sprema u bazu podataka sličnu rječniku: import shelve object = someObject() dbase = shelve.open(filename) dbase[’key’] = object ... object = dbase[’key’] dbase.close()
# Otvara bazu # Sprema objekt u bazu # Vra\’{c}a objekt iz baze # Zatvara bazu
U oba slučaja, samo se serijalizirani objekti mogu spremiti u datoteku. Većina Python objekata se može serijalizirati, ali objekti posebne vrste, kao što su na primjer datoteke, ne mogu se spremati i obnavljati na ovaj način.
Literatura [1]
Wesley J. Chun, Core Python Programming, Prentice-Hall, Inc., 2001.
[2]
Alex Martelli, Python in a Nutshell, O’Reilly, 2003.
[3]
David M Beazley , Python Essential Reference, New Riders Publishing , 2001.
[4]
Rashi Gupta, Making Use of Python, Wiley Publishing, Inc., 2002.
[5]
Allen B. Downey; Jeffrey Elkner; Chris Meyers, How to Think Like a Computer Scientist, Green Tea Press, 2005.
[6]
David Ascher; Alex Martelli; Ravenscroft, Python Cookbook, O’Reilly, 2005.
[7]
Magnus Lie Hetland, Beginning Python: From Novice to Professional, Apress, 2005.
[8]
Dave Brueck; Stephen Tanner, Python 2.1 Bible, Hungry Minds, 2001.
[9]
Chris Vehily, Python: Visual QuickStart Guide, Peachpit Press, 2001.
[10]
Brad Dayley, Python Phrasebook: Essential Code and Commands, Sams, 2006.
83
Indeks N-terac, 17 Python, 7 varijabla, 25
84