Python
March 14, 2018 | Author: Miroslav Novta | Category: N/A
Short Description
Mario Essert, Domagoj Ševerdija, Ivan Vazler Digitalni udžbenik Python - osnove - Odjel za matematiku Sveučilišta Jos...
Description
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>> 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: + =,− =, ∗ =, / =, // =, % =, ∗∗ =, | =, >>=, = y x y x = x > 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
View more...
Comments