Rješenja nekih zadataka, koje ste rješavali u C-u, pomoću pythona¶
Zadaća 1 (map()
, lambda
, math.sin()
, sum
)¶
Zadatak 3b¶
import math N = input() L = range(0,N+1) L = map( lambda x: x*math.pi/float(N), L ) L = map( math.sin, L ) print sum(L)Pokrenemo program i unesemo npr.
10
, rezultat je:6.31375151468U interaktivnom modu možemo pratiti izvršavanje:
>>> import math >>> N = 10 >>> L = range(0,N+1) >>> L [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] >>> L = map( lambda x: x*math.pi/10., L ) >>> map( lambda x: "%.2f" % x, L ) # ispis samo 2 decimale ['0.00', '0.31', '0.63', '0.94', '1.26', '1.57', '1.88', '2.20', '2.51', '2.83', '3.14'] >>> L = map( math.sin, L ) >>> map( lambda x: "%.2f" % x, L ) # ispis samo 2 decimale ['0.00', '0.31', '0.59', '0.81', '0.95', '1.00', '0.95', '0.81', '0.59', '0.31', '0.00'] >>> sum(L) 6.31375151468
Zadaća 2 ([ ... for ... in ...], string.join()
)¶
Zadatak 1b¶
L = [x * 0.1 for x in range(31,41)] print "Tablica mnozenja 1b:" for i in L: print "%5.2f" % (i*L[0]), for j in L[1:]: print "|%5.2f" % (i*j), printTablica mnozenja 1b: 9.61 | 9.92 |10.23 |10.54 |10.85 |11.16 |11.47 |11.78 |12.09 |12.40 9.92 |10.24 |10.56 |10.88 |11.20 |11.52 |11.84 |12.16 |12.48 |12.80 10.23 |10.56 |10.89 |11.22 |11.55 |11.88 |12.21 |12.54 |12.87 |13.20 10.54 |10.88 |11.22 |11.56 |11.90 |12.24 |12.58 |12.92 |13.26 |13.60 10.85 |11.20 |11.55 |11.90 |12.25 |12.60 |12.95 |13.30 |13.65 |14.00 11.16 |11.52 |11.88 |12.24 |12.60 |12.96 |13.32 |13.68 |14.04 |14.40 11.47 |11.84 |12.21 |12.58 |12.95 |13.32 |13.69 |14.06 |14.43 |14.80 11.78 |12.16 |12.54 |12.92 |13.30 |13.68 |14.06 |14.44 |14.82 |15.20 12.09 |12.48 |12.87 |13.26 |13.65 |14.04 |14.43 |14.82 |15.21 |15.60 12.40 |12.80 |13.20 |13.60 |14.00 |14.40 |14.80 |15.20 |15.60 |16.00Naredba
python print without newline space
na google-u, i to je koristitisys.stdout.write
.import sys L = [x * 0.1 for x in range(31,41)] print "Tablica mnozenja 1b:" for i in L: sys.stdout.write( "%5.2f" % (i*L[0]) ) for j in L[1:]: sys.stdout.write( "|%5.2f" % (i*j) ) printTablica mnozenja 1b: 9.61| 9.92|10.23|10.54|10.85|11.16|11.47|11.78|12.09|12.40 9.92|10.24|10.56|10.88|11.20|11.52|11.84|12.16|12.48|12.80 10.23|10.56|10.89|11.22|11.55|11.88|12.21|12.54|12.87|13.20 10.54|10.88|11.22|11.56|11.90|12.24|12.58|12.92|13.26|13.60 10.85|11.20|11.55|11.90|12.25|12.60|12.95|13.30|13.65|14.00 11.16|11.52|11.88|12.24|12.60|12.96|13.32|13.68|14.04|14.40 11.47|11.84|12.21|12.58|12.95|13.32|13.69|14.06|14.43|14.80 11.78|12.16|12.54|12.92|13.30|13.68|14.06|14.44|14.82|15.20 12.09|12.48|12.87|13.26|13.65|14.04|14.43|14.82|15.21|15.60 12.40|12.80|13.20|13.60|14.00|14.40|14.80|15.20|15.60|16.00Za rješavanje ovog zadatka može poslužiti funkcija
string.join()
.print "-između-".join(["100","200"," ","abc"])100-između-200-između- -između-abcPočnemo tako da generiramo tablicu množenja kao dvodimenzionalnu listu
L2
.L = [x * 0.1 for x in range(31,41)] L2 = [["%5.2f"%(i*j) for j in L] for i in L] print L2[0] print "..." print L2[-1][' 9.61', ' 9.92', '10.23', '10.54', '10.85', '11.16', '11.47', '11.78', '12.09', '12.40'] ... ['12.40', '12.80', '13.20', '13.60', '14.00', '14.40', '14.80', '15.20', '15.60', '16.00']Zatim povežemo unutarnju listu znakom
"|"
, a vanjsku listu znakom za novi red"\n"
.L = [x * 0.1 for x in range(31,41)] L2 = ["|".join(["%5.2f"%(i*j) for j in L]) for i in L] print "Tablica mnozenja 1b:" print "\n".join(L2)Tablica mnozenja 1b: 9.61| 9.92|10.23|10.54|10.85|11.16|11.47|11.78|12.09|12.40 9.92|10.24|10.56|10.88|11.20|11.52|11.84|12.16|12.48|12.80 10.23|10.56|10.89|11.22|11.55|11.88|12.21|12.54|12.87|13.20 10.54|10.88|11.22|11.56|11.90|12.24|12.58|12.92|13.26|13.60 10.85|11.20|11.55|11.90|12.25|12.60|12.95|13.30|13.65|14.00 11.16|11.52|11.88|12.24|12.60|12.96|13.32|13.68|14.04|14.40 11.47|11.84|12.21|12.58|12.95|13.32|13.69|14.06|14.43|14.80 11.78|12.16|12.54|12.92|13.30|13.68|14.06|14.44|14.82|15.20 12.09|12.48|12.87|13.26|13.65|14.04|14.43|14.82|15.21|15.60 12.40|12.80|13.20|13.60|14.00|14.40|14.80|15.20|15.60|16.00
Zadaća 3 (zip
, input
, math.sqrt()
)¶
Zadatak 4¶
Promotrimo ovaj primjer:
>>> zip( [100,200], [3,4] ) [(100, 3), (200, 4)] >>> [i+j for i,j in zip([100,200],[3,4])] [103, 204]Vidimo kako je moguće jednostavno raditi operacije nad dvjema listama, tako da se uzima prvi (100) s prvim (3), drugi (200) s drugim (4), itd. To iskoristimo za rješavanje zadatka.
import math N = input() a = [] b = [] for i in range(0,N): a.append( input() ) for i in range(0,N): b.append( input() ) ab = [i*j for i,j in zip(a,b)] a2 = [i*i for i in a] b2 = [i*i for i in b] ab = sum(ab) a2 = math.sqrt(sum(a2)) b2 = math.sqrt(sum(b2)) print "cos(theta) je", ab/a2/b2Unesemo
2 1 0 1 1
kao input. Rezultat je:cos(theta) je 0.707106781187
Zadaća 4¶
Problemi opisani u zadaći 4 ne javljaju se u pythonu jer u pythonu “nema” pointera, a i provjerava se da indeks polja bude unutar trenutno dopuštenog opsega. [U CPythonu možemo doznati adresu pomoću funkcijeid()
, ali na adrese ne možemo upisivati direktno.]
Zadaća 5 (string.replace()
)¶
Zadatak 3¶
Trivijalno jer python podržava rad s proizvoljno dugim cijelim brojevima.
Zadatak 4¶
Trivijalno jer već postoji takva funkcija u pythonu.
print "1456".replace("1","123")123456
Zadaća 6 (itertools.groupby()
)¶
Zadaci 2a i 2b¶
Za rješavanje ovog zadatka dobro može poslužiti funkcija
groupby
iz modulaitertools
. Ta funkcija razdvaja listu ili string na dijelove:>>> import itertools >>> [k for k,v in itertools.groupby("aaabbcd")] ['a', 'b', 'c', 'd'] >>> [list(v) for k,v in itertools.groupby("aaabbcd")] [['a', 'a', 'a'], ['b', 'b'], ['c'], ['d']] >>> [len(list(v)) for k,v in itertools.groupby("aaabbcd")] [3, 2, 1, 1] >>> [k*len(list(v)) for k,v in itertools.groupby("aaabbcd")] ['aaa', 'bb', 'c', 'd']Koristeći to, lako je napraviti
rle.py
iunrle.py
.#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import itertools def rle(src,dest): str = src.read() str = "".join( ["%d%s" % (len(list(v)),k) for k,v in itertools.groupby(str)] ) dest.write(str) with open(sys.argv[1],"r") as src: with open(sys.argv[2],"w") as dest: rle(src,dest)#!/usr/bin/env python # -*- coding: utf-8 -*- import sys def unrle(src,dest): str = src.read() assert len(str) % 2 == 0 ponavljanja = str[0::2] #svaki drugi parni ponavljanja = map(int,ponavljanja) znakovi = str[1::2] #svaki drugi neparni str = [z*p for z,p in zip(znakovi,ponavljanja)] str = "".join(str) dest.write(str) with open(sys.argv[1],"r") as src: with open(sys.argv[2],"w") as dest: unrle(src,dest)Da bi se ti programi mogli pokretati kao samostalni, potrebno je dodati pravo izvršavanja.
$ chmod +x rle.py $ chmod +x unrle.pyKad datoteku
z6src.py
aaaabbbbaaaaccccdefkomprimiramo
$ ./rle.py z6src.txt z6out.txt
dobijemo
4a4b4a4c1d1e1fKad taj rezultat dekomprimiramo
$ ./unrle.py z6out.txt z6out2.txt
dobijemo nazad početni sadržaj
aaaabbbbaaaaccccdefNaravno, ovdje se pretpostavljalo, kako je rečeno u zadatku, da se znakovi neće ponavljati više od 9 puta.
Zadaća 7¶
Zadatak 2¶
Rješenje je:
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys import struct import os def isprint(c): return 0x20<=ord(c)<=0x7e def konverzija(c): if isprint(c): return c else: return "[%02x]" % ord(c) D, P, N, T = sys.argv[1:5] P = int(P) N = int(N) rjecnik = {} rjecnik["c"] = "c" rjecnik["d"] = "i" rjecnik["ld"] = "l" rjecnik["f"] = "f" rjecnik["lf"] = "d" with open(D,"rb") as f: fmt = '%d%s' % (N,rjecnik[T]) duljina = struct.calcsize(fmt) f.seek( P, os.SEEK_SET ) byteovi = f.read( duljina ) print >>sys.stderr, "s pozicije %d procitati %d procitano %d. " % (P,duljina,len(byteovi)), repr(byteovi) assert len(byteovi) == duljina vrijednosti = struct.unpack( fmt, byteovi ) if T == "c": vrijednosti = map( konverzija, vrijednosti ) s = "".join(vrijednosti) else: vrijednosti = map( str, vrijednosti ) s = " ".join(vrijednosti) print s
Tu smo koristili pythonov dictionary i time smo izbjegli potrebu za velikim brojem if-ova. Funkcija isprint
ne postoji u pythonu, ali možemo pogledati kako je napravljena u C-u pa taj kôd prevesti u python. Gornju datoteku nazovemo rr.py
.
Krećemo od datoteke iz jednog od prethodnih primjera:
hexdump -C bin1.bin
00000000 74 65 6b 73 74 00 00 00 00 00 00 00 0a 00 00 00 |tekst...........| 00000010 9a 99 99 99 99 99 b9 3f |.......?| 00000018
Kad postavimo flag izvršavanja datoteci rr.py
možemo radi testiranja pokrenuti program nad podacima u bin1.bin
.
chmod +x rr.py ./rr.py bin1.bin 0 10 c ./rr.py bin1.bin 12 1 d ./rr.py bin1.bin 16 1 lftekst[00][00][00][00][00] 10 0.1
Zaključujemo da postoji prazan prostor (zbog alignmenta) u byteovima redni broj 10 i 11.
Zadaća 8 (try
... except
... else
, raise
)¶
Zadatak 2¶
U pythonu postoji funkcija read
slična traženoj. Python se brine oko dealokacije. Duljina N
nam nije potrebna jer uvijek možemo koristiti len
. Prikazat ćemo dva rješenja prvo jednostavno koje je malo nepotpuno, a zatim potpuno rješenje.
Za obradu grešaka je u pythonu prirodno koristiti tzv. try..except
konstrukciju. Izvršavanje krene u try
blok i izvršava se red po red ali ako dođe do greške odmah se nepovratno napušta try
blok i prelazi u prvi kompatibilan except
blok. (U except
blok se ulazi samo ako se dogodi greška u try
bloku koji mu prethodi. U else
blok se ulazi samo ako se čitav prethodni try
blok izvršio bez greške.)
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys def readfile( fn ): with open( fn, "r" ) as f: s = f.read() return s try: p = readfile( sys.argv[1] ) print "datoteka je uspjesno procitana, i sadrzi %d byteova" % len(p) errcode = 0 except Exception as e: print "greska ", e errcode = 1 sys.exit(errcode)
Ako bismo baš htjeli da povratne vrijednosti budu diferencirane kao što se traži u zadatku potrebno je dodati još provjera.
#!/usr/bin/env python # -*- coding: utf-8 -*- import sys class Gr(Exception): pass class GrOtvaranje(Gr): pass class GrRezMem(Gr): pass class GrCitanje(Gr): pass class GrNepoznata(Gr): pass def readfile( fn ): try: try: f = open( fn, "r" ) except IOError as e: raise GrOtvaranje(e) else: try: with f: s = f.read() except IOError as e: raise GrCitanje(e) except MemoryError as e: raise GrRezMem(e) except Gr as e: raise except Exception as e: raise GrNepoznata(e) return s try: p = readfile( sys.argv[1] ) print "datoteka je uspjesno procitana, i sadrzi %d byteova" % len(p) errcode = 0 except GrOtvaranje as e: print "greska prilikom otvaranja datoteke", e errcode = 1 except GrRezMem as e: print "greska prilikom rezerviranja memorije", e errcode = 2 except GrCitanje as e: print "greska prilikom citanja datoteke", e errcode = 3 except GrNepoznata as e: print "nepoznata greska u readfile", e errcode = 4 except: print "neocekivana greska", sys.exc_info() errcode = 5 sys.exit(errcode)
Isprobajmo sad oba primjera. Pogledajmo output sljedećih naredbi upisanih u terminal:
chmod +x readfile.py chmod +x readfile2.py ./readfile.py bin1.bin ./readfile2.py bin1.bindatoteka je uspjesno procitana, i sadrzi 24 byteova datoteka je uspjesno procitana, i sadrzi 24 byteova
Isprobajmo kako rade kad im se zada pogrešno ime datoteke odnosno ime datoteke koja ne postoji:
./readfile.py nepostojeca.datoteka echo $? ./readfile2.py nepostojeca.datoteka echo $?greska [Errno 2] No such file or directory: 'nepostojeca.datoteka' 1 greska prilikom otvaranja datoteke [Errno 2] No such file or directory: 'nepostojeca.datoteka' 1
Isprobajmo što se događa u slučaju kad im se zada ime postojeće datoteke za koju je ukinuto pravo čitanja:
chmod u-r bin1.bin ./readfile.py bin1.bin echo $? ./readfile2.py bin1.bin echo $? chmod u+r bin1.bingreska [Errno 13] Permission denied: 'bin1.bin' 1 greska prilikom otvaranja datoteke [Errno 13] Permission denied: 'bin1.bin' 1