Nakon što smo prešli osnove Python pravila i sintakse kodiranja u Poglavlju 2. (Osnovni elementi Python-a), vreme je da pogledamo kako Python funkcioniše na Symbian-u. Ovo poglavlje opisuje kako pristupiti informacijama uređaja i aplikacija, kako izvršavati sistemske operacije i kako raditi sa fajlovima i vremenskim vrednostima.
Ovo poglavlje predstavlja sysinfo i e32, module koje pružaju informacije o uređaju i o trenutnoj aplikaciji respektivno. Modul e32 sadrži i utilities za izvršavanje sistemskih operacija, poput izvršavanja i pauziranja skripti i podešavanje vremena na uređaju.
Konačno, u ovom poglavlju će biti reči o funkcionalnosti jezgra nasleđenoj od standardnog Python-a, npr. kako izvršavati operacije vezane za vreme i kako manipulisati fajlovima. Pokriva imenovanje fajlova u Symbian-u i pravila rada, te pokazuje kako Python radi sa fajlovima slično drugim programskim jezicima.
Metode opisane u ovom poglavlju su često korišćene u Python aplikacijama za Symbian uređaje.
Modul sysinfo se može koristiti za pristup sledećim informacijama o uređaju:
Ovaj modul se koristi lako. Na primer, naredne dve linije koda u interaktivnoj PyS60 konzoli vraćaju IMEI uređaja:
>>>import sysinfo |
Naredni delovi koda prikazuje metode koje se koriste za nabavljanje informacija i njihove povratne tipove:
# Pribavi snagu baterije kao integer. Vrednost je u opsegu od 0 (prazna) i 100 (puna). |
Symbian uređaju obično imaju interni disk (C:) i memorijsku karticu (E:). Ukoliko postoji RAM drive, on je mapiran na D:, a Z: je ROM drive. Postoje izuzeci: neki uređaju koriste E drive za 'unutrašnju' memoriju, a neki imaju dodatne drajvove. Količina RAM, ROM i disk drive prostora zavise od uređaja.
sysinfo može vratiti informacije i o memoriji uređaja, na sledeći način:
# Pribavi količinu slobodnog RAM-a u byte-ovima |
Napomena: e32 modul obezbeđuje drive_list() da bi dobili listu svih drajvova, o tome je reč u narednom delu.
Modul e32 sadrži korisnu, raznovrsnu kolekciju utilities. Sve od metoda koje vraćaju informacije o uređaju i trenutnoj aplikaciji do metoda koje pauziraju trenutnu skriptu ili resetuju tajmer neaktivnosti uređaja (device inactivity timer). Dostupne su i metode za operacije sa fajlovima, poput kopiranja fajlova i foldera.
Modul e32 pruža, uz ono što pruža sysinfo, sledeće 'sistemske' informacije:
Delovi koda prikazuju metode koje se koriste za dobijanje navedenih informacija:
# Pribavi verziju Python runtime-a - tuple broja verzije: major, minor, micro i release tag. |
Funkcija set_home_time() postavlja sistemsko vreme uređaja na zadato vreme. Sistemsko vreme uređaja se može dobiti preko vremenskog (time) modula.
import e32 |
Funkcija file_copy() se može koristiti za kopiranje fajlova iz jednog direktorijuma u drugi.
>>> source_path=u"C:\\Python\\myimage.jpg" |
Za kopiranje svih fajlova u source direktorijumu, dodati '*.*' u source putanju.
>>> source_path=u"C:\\Python\\*.*" |
Ovo kopira sve fajlove iz direktorijuma C:\Python u direktorijum C:\Data.
Za pokretanje određenog izvršnog fajla (.exe), može se koristiti start_exe() metod, na sledeći način:
>>> e32.start_exe(exe_filename, command,wait_time) |
Parametar command prosleđuje argumente komandne linije u izvršne. Ukoliko argumenti nisu potrebni, može biti podešeno na NULL ili prazan string. Parametar wait_time je opcioni parametar, kao što je opisano ispod.
Sledeća izjava se koristi za pokretanje Web browser-a sa default URL-om, i command parametar se prosleđuje kao prazan string.
>>> application_exe='BrowserNG.exe' |
Da bismo otvorili Web browser sa određenim URL-om, prosleđujemo ga kao command na sledeći način:
>>> url="http://developer.symbian.org" |
U oba prethodna primera, browser se pokreće asinhrono. Možemo koristiti opcioni wait_time integer parametar da bismo pokrenuli aplikaciju sinhrono.
Ukoliko se ne-nula vrednost postavi za wait_time, onda start_exe() pokreće aplikaciju i čeka da se aplikacija završi. Onda vraća 0 ako se aplikacija završi normalno ili 2 ako aplikacija završi 'abnormalno'.
>>> wait_time=1 |
Prefiks '4' u url parametru je naznaka da browser treba da pokrene napomenuti url. Drugi predefinisani prefiksi za ovaj parametar su prikazani ispod (Tabela 3):
Tabela 3 . – Predefinisani parametri za url parametar
Prefiks |
Parametar |
Opis |
Bez |
<bilo koji tekst> |
Pokreni (ili nastavi) rad browser-a bez određenog sadržaja |
1 |
”<Space>“+”<Uid of a bookmark>” |
Pokreni (ili nastavi) rad browser-a sa određenim bookmark-om |
2 |
”<Space>“+”<Uid of a saved deck>” |
Pokreni (ili nastavi) rad browser-a sa određenim saved deck |
3 |
”<Space>“+”<URL>” |
Pokreni (ili nastavi) rad browser-a sa određenim URL-om |
4 |
”<Space>“+”<Url>”+”<Space>“+”<Uid of AP>” |
Pokreni (ili nastavi) rad browser-a sa određenim bookmark-om i Access Point-om (AP) |
5 |
<bilo koji tekst> |
Pokreni (ili nastavi) rad browser-a sa početnom stranicom (Home Page) – Koristi se kada se dugo drži taster 0 u neutralnom stanju telefona (Idle state) |
6 |
” <Space>“+”<Uid of bookmark folder>” |
Pokreni (ili nastavi) rad browser-a sa određenim direktorijumom bookmark-a |
Funkcija start_exe() se može koristiti i za drugih native ili thrid party aplikacija.
Python skripta može biti pokrenuta u pozadini (kao server skripta) pomoću start_server() funkcije.
>>> server_script.py=u"C:\\Data\\Python\\myscript.py" |
Metod reset_inactivity se može koristiti za resetovanje tajmera neaktivnosti programski.
>>> e32.reset_inactivity() |
Resetovanje tajmera neaktivnosti u regularnim intervalima sprečava uređaj da uđe u low power mode tokom perioda neaktivnosti korisnika. Ovo može biti korisno ako aplikacija mora ostati vidljiva kada korisnik „ne radi ništa“ – na primer, kada se koristi hands-free navigacijski sistem u autu. inactivity() vraća trenutnu vrednost tajmera neaktivnosti.
Metod ao_sleep() se može koristiti da se uvede kašnjenje između izvršavanja izjava, ili da pozove određeni metod nakon zadatog vremenskog intervala. Upotreba ao_sleep() se podstiče više nego upotreba time.sleep() metoda, zato što ao.sleep() ne blokira aktivni planer (scheduler), što znači da UI može ostati aktivan (responsive).
Na primer, sledeći kod primorava skriptu na čekanje od dve sekunde.
print "Waiting for 2 seconds" |
Callback funkcija se može zadati kada pozivamo ao_sleep(). U sledećem primeru, funkcija foo() se poziva nakon tri sekunde.
def foo(): |
Pozivanje ao_yield() vraća kontrolu aktivnom planeru (active scheduler), omogućavajući tako izvršavanje bilo kom aktivnom objektno-zasnovanom kodu (object-based code) sa prioritetom iznad normalnog. U praksi, ovo održava aplikaciju responsivnom na meni i softkey unose, čak i za vreme izvršavanja dugo izvršavajućih događaja (long running events). Na primer, sledeći deo koda prikazuje napomene unutar trajne while petlje. Upotreba e32.ao_yield() osigurava mogućnost izlaska iz petlje (i aplikacije) pritiskajući desni soft taster. Bez e32.ao_yield() u petlji, aktivni planer (active scheduler) nikad ne bi mogao pokrenuti kod za rukovanje događajima.
def quit(): |
Metod ao_callgate() kreira aktivni omotač objekta oko Python funkcije koja se može pozvati i vraća drugi objekat funkcije koji se takođe može koristiti da pokrene aktivni objekat. Originalna Python funkcija će biti pozvana u nekom trenutku, nakon što omotačka funkcija bude pozvana kad se njegov povezani aktivni objekat izvrši od strane aktivnog planera. Omotački objekat se može koristiti za pozivanje funkcije iz bilo koje Python thread (nit); funkcija se izvršava 'u kontekstu niti (thread-a) gde je ao_callgate() kreiran'.
Sledeći primer pokazuje kako funkcija fun() biva registrovana sa callgate da vrati omotački objekat foo(). Metod fun() se izvršava od strane aktivnog planera u nekom trenutku nakon što foo() bude pozvan.
import e32 |
Dve bitne klase definisane u e32 modulu su: Ao_lock i Ao_timer. One su klase, za razliku od navedenih operativnih funkcija, pa se mogu koristiti tek nakon što se instanciraju.
Ao_lock je aktivni objektno-zasnovani sinhronizacioni servis (active object-based synchronization service), koji je u srcu UI strukture Python aplikacija. Ao_lock objekat se koristi stvarajući instancu od Ao_lock, dodavajući broj aktivnih objekata i onda pozivanje wait()-a na nit (thread), kao što je pokazano u sledećem primeru:
#Kreiranje instance od Ao_lock |
Python zadržava izvršavanje skripte kod wait()-a, ali će svi tekući aktivni objekti biti opsluženi. Python implementira menije kao aktivne objekte, pa oni ostaju pozivani i UI ostaje responsivan (odzivan). Kada smo spremni za nastavak izvršavanja skripte, pozovemo signal(). Međutim, s obzirom da je izvršavanje skripte zaustavljeno kod wait()-a, moramo ga signal-ovati da ponovo započne preko menu callback-a. Sporazum je da se čekajuća skripta oslobodi u quit() funkciji:
#Signals the lock and releases the "waiter" |
Zapamtite da se wait() može pozvati samo u niti koja je kreirala lock objekat i samo je „waiter“ dozvoljen, pa pazite kada ga koristite u petlji.
Ao_timer je Symbian active object-based timer service. Poput Ao_lock, može se koristiti u glavnoj niti, bez blokiranja rukovanja UI događaja. Sledeći deo koda kreira instancu Ao_timer i prikazuje upotrebu njegovih after() i cancel() metoda:
#Kreiranje instance Ao_timer |
Callback function parametar after() metoda je opcionalan; ako nije određen, nit jednostavno 'spava' određeno vreme. Metod cancel() se može koristiti za poništavanje čekajućeg (pending) after() zahteva. Važno je poništiti čekajuće pozive tajmera pre izlaska aplikacije.
Python-ov koncept vremena dolazi od Unix OS-a. Unix meri vreme kao broj sekundi od epohe, koja je započela 1. januara 1970. u 00:00:00 po Griniču. Na primer, ponoć 1. januara 2010. je bila 1,262,304,000 sekundi od Unix epohe.
Postoji nekoliko sistemskih funkcija koje prikazuju i rukuju sa sistemskim vremenom. Pre nego što ih pogledamo, međutim, trebali bismo pregledati moguće vrednosti koje se prihvataju za vrednosti vremena. Postoje dva skupa vrednosti:
Tabela 4 . – Prikaz vremenskih komponenti za struktuirane vremenske vrednosti
Python ime |
Opis |
tm_year |
Četvorocifrena vrednost koja određuje godinu |
tm_mon |
Integer u rasponu od 1 do 12, određuje mesec |
tm_mday |
Integer u rasponu od 1 do 31, određuje dan |
tm_hour |
Integer u rasponu od 0 do 23, određuje sat |
tm_min |
Integer u rasponu od 0 do 59, određuje minut |
tm_msec |
Integer u rasponu od 0 do 61, određuje sekundu (60. i 61. vrednost važe za skok i dupli skok sekundi) |
tm_wday |
Integer u rasponu od 0 do 6, određuje dan (Ponedeljak ima vrednost 0) |
tm_yday |
Integer u rasponu od 0 do 365, određuje dan u godini (prikladan i prestupnim godinama) |
tm_isdst |
Integer u rasponu od 0 do 1, određuje boolean vrednost za određivanje Daylight Savings Time (može biti -1, vidi mktime() ispod) |
Na primer, pogledajmo sledeći kod, gde time.localtime() vraća strukturne vrednosti time-a kao tuple:
import time |
Da se ovaj kod izvršio na 8. septembar 2009., u 9:15:38 časova prepodne, promenljive bi imale sledeće vrednosti:
a = 2009 |
Pogledajmo kratko funkcije time modula:
Funkcije strftime() i strptime() koriste specijalne direktive ugnježdene u format string. Ove direktive su prikazane ispod (Tabela 5):
Tabela 5 . – Direktive funkcija strftime() i strptime()
Direktiva |
Opis |
%a |
Broj dana u nedelji (skr.) |
%A |
Broj dana u nedelji – puno ime |
%b |
Ime meseca (skr.) |
%B |
Ime meseca – puno ime |
%c |
Predstavljanje vremena i datuma prikladno regionu |
%d |
Dan u mesecu kao integer |
%H |
Sat kao integer u obliku 24h sata |
%I |
Sat kao integer u obliku 12h sata |
%j |
Dan godine kao integer |
%m |
Mesec kao integer |
%M |
Minut kao integer |
%p |
AM ili PM kao string |
%S |
Sekunde kao integer |
%U |
Broj sedmice u godini kao integer (nedelja se smatra prvim danom sedmice) |
%w |
Dan u nedelji kao integer (nedelja je 0) |
%W |
Broj sedmice godine kao integer (ponedeljak se smatra prvim danom sedmice) |
%x |
Predstavljanje datuma kao string |
%X |
Predstavljanje vremena kao string |
%y |
Godina kao integer bez veka |
%Y |
Godina kao integer sa vekom |
%Z |
Ime vremenske zone (nema karaktera ako ne postoji vremenska zona) |
Evo nekoliko primera:
time.strftime("Now is %a, %d %b %Y at %H:%M:%S", time.gmtime()) |
Ovaj string kombinuje regularni tekst sa specifikatorima vremena. Takođe pribavlja 'vrednost' vremena pomoću time.gmtime(). Kod daje sledeći izlaz:
Now is Wed, 09 Sep 2009 at 13:58:37 |
Pogledajmo sada sledeći kod:
thedate = "31 Dec 08" |
U navedenom primeru, rezultat je pokazao da 2008. godina jeste bila prestupna, jer je dan „31 Dec 08“ bio dan broj 366 u godini.
Postoje neke varijacije u vremenskom modulu. To su:
Ovaj opis je opis sistema vremenskog (time) modula. Postoje i drugi moduli koji pružaju manje primitivne, više objektno-orijentisan pristup datumima i vremenu:
Konačno, moramo se osvrnuti na još jednu sistemsku funkciju: e32.set_home_time(). Ovaj poziv dolazi iz e32 modula i koristi se za podešavanje trenutnog vremena za uređaj. Potrebni parametar je vreme, podešeno u format Unix-ovih „sekundi nakon epohe“. Na primer:
import e32 |
Ovaj kod podešava globalno vreme uređaja na ponoć, 1. januar 2010.
Kao što smo već spominjali, fajl je ugrađeni tip podataka u Python-u. Python rukuje fajlovima slično drugim programskim jezicima. No, postoje i neke dodatne operacije fajlovima u modulima jedinstvenim za Python na Symbian platformi.
Počećemo sa konverzijom imena fajlova za Symbian platformu. Symbian koristi konverziju sličnu onoj koju koristi Microsoft Windows. Slova drajvova („C: \” itd.) se koriste da naznače memorijske jedinice poput memorijske ili SD kartice, postoji hijerarhija direktorijuma, i komponente putanje se odvajaju backslash-ovima („\“).
Sledeća tabela prikazuje listu najčešće korištenih operacija sa fajlovima u Python-u (Tabela 6).
Tabela 6 – Najčešće operacije sa fajlovima u Python-u
Operacije |
Opis |
log=open("C:\logfile2.txt", "w") |
Kreira novi fajl („w“ flag je za za pisanje) |
inlog = open("C:\images\logfile.txt") |
Otvara fajl za čitanje („r“ flag, za čitanje, je default |
contents = inlog.read() |
Učitaj čitav sadržaj fajla u jednu string promenljivu |
bytes = inlog.read(count) |
Učitaj „count“ bajtova u string |
line = inlog.readline() |
Učitaj jedan red u string (uključuje end-of-line marker) |
linelist = inlog.readlines() |
Učitaj čitav sadržaj fajlova u listu string-ova, tako da svaki sadrži jedan red |
log.write(someContent) |
Upiši string u fajl |
log.writeLines(stringList) |
Upiši sekvencu string-ova u fajl (ne uključuje end-of-line marker) |
log.flush() |
Isprazni buffer koji sadrži podatke o fajlu u taj fajl |
log.truncate() |
Odseci fajl na trenutno poziciji, zanemarujući sve što sadrži nakon ove pozicije |
log.seek(position) |
Pomeri trenutnu poziciju u fajlu na „position“ |
log.close() |
Zatvori fajl |
Većina ovih operacija je slična onim koje se koriste u drugim jezicima i platformama. Neke su kvalitetnije, poput readlines() ili writelines() funkcija, koje dosta olakšavaju čitanje ili pisanje velike količine sadržaja, zbog načina na koji Python organizuje data objects.
Pogledajmo sledeći kod:
html = ["<HEAD>"] |
Jezici poput Java-e bi zahtevali da svaka linija HTML-a bude napisana zasebno u fajl, verovatno koristeći for petlju. Međutim, ovde jedna izjava piše sve linije u fajl.
Primetimo da se podaci uvek vade iz fajlova kao string – čak i nečitljivi (non-readable) podaci. To znači da ukoliko nam trebaju podaci u drugom obliku, npr. brojevima, moramo konvertovati podatke iz string-a u oblik koji nam treba. Takođe, pisanje podataka u fajl se uvek radi koristeći string-ove. Čak iako želimo upisati integer ili float, moramo ih prvo formatirati u string, pa onda taj string upisati u fajl. Na primer:
line = str(10) + "," + str(data) + "," + str(value) + "\n" |
Ovaj kod spaja tri podatka u jedan string za pisanje u fajl. Slično tome, mogli bismo pročitati ove podatke ovako:
line = input.readline() |
Ovde čitamo red razdvojen zarezima, podelimo ga u delove i konvertujemo pojedinačne string-ove u vrstu podataka koja nam je potrebna.
Možemo takođe koristiti i formatiranje string-a da bi konstruisali liniju koja nam je potrebna za fajl. Razmotrimo sledeći primer, koji prepisuje (overwrite) prethodni kod:
line = "%d,%d,%f\n" % (10, data, value) |
Ovaj kod je funkcionalan za jednostavne tipove podataka, ali native Python objekti se malo teže konvertuju u string-ove i obratno. Ovde na scenu stupa pickle modul. Modul sadrži metode koje dozvoljavaju skoro svim objektima Python-a da se upišu u fajl (na S60 su podržani samo tuples, lists i dictionaries), bez konverzije u i iz string-a. Pogledajmo sledeći kod:
import pickle |
Ovaj kod skladištene podatke u dictionary-ju dict da se skladište u fajl 'dictfile' kao native Python dictionary. Dictionary vraćamo nazad koristeći sledeći kod:
infile = open('dictfile') |
Sada promenljive dict i newdict imaju istu vrednost.
Kao dodatak ovim osnovnim operacijama sa fajlovima, os modul ima mnogo operacija dekripcije fajlova i direktorijuma (file descriptor and directory operations). Operacije dekripcije fajlova otkrivaju metodu rada sa fajlovima Unix OS-a.
Mnoge operacije sa direktorijumima u os modulu takođe rukuju sa manipulacijom fajl sistema na sistemskom nivou, ali neki mogu biti korisni i u opštoj upotrebi, uključujući sledeće:
Postoji nekoliko dodatnih sistemski povezanih poziva za fajlove dostupnih u e32 i sysinfo modulima koji mogu biti korisni (Tabela 7).
Tabela 7 – Dodatni sistemski povezani pozivi za e32 i sysinfo module
Sistemski poziv |
Modul |
Opis |
drive_list() |
e32 |
Vraća listu vidljivih, dostupnih drajvova |
file_copy(target_name, source_name) |
e32 |
Kopira fajl iz target_name u source_name |
free_drivespace() |
sysinfo |
Vraća količinu slobodnog prostora na drajvovima u obliku dictionary objekta koristeći parove drajv/prostor |
Više informacija se može pronaći na http://pys60.garage.maemo.org/doc/s60/node10.html i http://pys60.garage.maemo.org/doc/s60/module-sysinfo.html