1 / 26

Čo objaví Pascalista v Pythone

Čo objaví Pascalista v Pythone. Peter Borovansk ý, KAI, I-18, borovan (a)ii.fmph.uniba.sk. Cie ľom prednášky: je ukázať zaujímavé jazykové konštrukcie jazyka Python ( procedurálny, objekt ový a funkc ionálny štýl , list-comprehension, generátory, ... )

sasson
Télécharger la présentation

Čo objaví Pascalista v Pythone

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Čo objaví Pascalista v Pythone Peter Borovanský, KAI, I-18, borovan(a)ii.fmph.uniba.sk Cieľom prednášky: • je ukázať zaujímavé jazykové konštrukcie jazyka Python (procedurálny, objektový a funkcionálny štýl, list-comprehension, generátory, ...) • neurobiť ďalší tutorial, ani prehľad metód akejkoľvek triedy • skúsenosti s jazykom (čo ma zaujalo a prekvapilo) Literatúra: • Python docshttp://docs.python.org/py3k/ • Python in Educationhttp://www.python.org/community/sigs/current/edu-sig/ • Learning with Python (2.x) http://openbookproject.net//thinkCSpy • Programovací jazyk Pythonhttp://www.py.cz (http://howto.py.cz/index.htm) Cvičenie: • malá pythoniáda - jednoduché pythonovské programy • interpreter konečného automatu/Turingového/Minského stroja

  2. Guido van Rossum v roku 1996 napísal: "Pred šiestimi rokmi, v decembri 1989, som hľadal zábavný programátorský projekt, ktorý by ma zamestnal cez týždeň počas Vianoc. Moja kancelária … bola zavretá, ale mal som domáci počítač a nič iného na práci. Rozhodol som sa, že napíšem interpreter pre nový skriptovací jazyk, o ktorom som už skôr premýšľal: nasledovníka jazyka ABC, ktorý by zaujal programátorov v Unixe/C. Ako pracovný názov som zvolil Python, lebo som bol v nevážnej nálade (a tiež som veľkým fanúšikom Monty Pythonovho Lietajúceho cirkusu)." http://sk.wikipedia.org/wiki/Guido_van_Rossum

  3. Rozdiel medzi dynamicky a staticky typovaným jazykom Jednoduché typy • interpretovaný jazyk • poskytuje typy podobné int, long, float, complex, bool, str(ing), … • implicitné číselné konverzie až na konverziu z/do string (1j*1j+1 == 0) • dynamicky typovaný jazyk • každá hodnota je asociovaná s typom, avšak typ premennej/konštrukcie nie je známy počas kompilácie, ale je známy až v čase výpočtu def dynatest(flag): if flag: var = 1234 else: var = "retazec" print(var,':',type(var)) if flag: var = 3.4 else: var = flag print(var,':', type(var)) dynatest(True) dynatest(False) 1234 : <class 'int'> 3.4 : <class 'float'> retazec : <class 'str'> False : <class 'bool'> Analógia null a void z C++ None : <class 'NoneType'>

  4. ...toto sme nechceli robiť, ale niečo z toho môže byť na rozcvičke Operácie nad základnými typmi pozri si poriadne http://docs.python.org/library/stdtypes.html ani Pascal ani C... Pascal: • x and y, x or y, not z, True, False • predsa pozná <> ako anachronizmus • int(x), float(x), long(x), str(x) sú typové konverzie à la Pascal C: • case sensitive, True != true • ==, !=, = ((ne)rovnosť, priradenie) • +, -, *, /, //, %, ** sú operátory sčítania, ... , celočíselné delenie, modulo, umocnenie • nepozná i++, --i, len i += 1, i -= 1 • bitové operácie |, &,^,~,>>,<< • indexujeme C-éčkovsky, od 0 po size-1 Nápady tretích strán: • divmod(x,y) vráti dvojicu (div,mod) • math.ceil(x), math.floor(x)à la Java

  5. analógia kolekcií napr. z Java Kolekcie - sekvencie • heterogénne zoznamy (môžu obsahovať objekty rôznych typov) • [1,2,3] – trojprvkový zoznam s prvkami 1,2,3 • [] – prázdny zoznam • [[1,2,3]] – jednoprvkový zoznam, ktorého jediný prvok je trojprovkový zoznam • [1,3.1415,['a','b']]: <class 'list'>- typ zoznamu • reťazce – "retazec", 'string': <class 'str'> • n-tice - (True, 3.1415, "retazec", [1,2,3,4]), (), (1,): <class 'tuple'> • for-cyklus cez sekvencie: for elem in sekvencia: # elem je premenná prebiehajúca sekvenciou … for e in [1,3.1415,['a','b']]:for chr in"retazec": print(e,':',type(e)) print(chr,’:’,type(chr)) 1 : <class 'int'> r : <class 'str'> 3.1415 : <class 'float'> e : <class 'str'> ['a', 'b'] : <class 'list'> t : <class 'str'> …

  6. Operácie so sekvenciami(najbežnejšie) • x in s, x not in s nachádza/nenachádza sa v sekvencii • len(s) dĺžka sekvencie • min(s), max(s) minimálny/maximálny prvok • s.index(i) prvý výskyt i v sekvencii s, inak -1 • s.count(i) počet výskytov i v sekvencii s • s + t zreťazenie dvoch sekvencií • s * n, n * s s+s+s+…+s a to presne n-krát • s[i] i-ty prvok s • s[i:j] podsekvencia s[i,i+1,…,j-1] • s[i:j:k] podsekvencia s[i,i+k,…,???] Príklady: 't' in 'retazec‘True 't' not in 'retazec‘False len('retazec')7 min('retazec')'a' 'retazec'.index('t')2 'r'*10'rrrrrrrrrr' 2*'r'*3'rrrrrr' 4 in [0,1,2,3,4,5] True 4 not in range(6) False len(range(10)) 10 max(range(10)) 9 [0]*10 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (0,)*3 (0, 0, 0)

  7. Indexovanie sekvencia[indexOdVrátane:indexPo:krok] ktorýkoľvek z parametrov môžeme vynechať: "retazec"[3] == 'a' "retazec"[3:] == 'azec' "retazec"[3::2] == 'ae' "retazec"[:5] == 'retaz' "retazec"[-1] == 'c' "retazec"[::-1] == 'cezater' "retazec"[-1:-6:-2] == 'czt‘ • reťazce 'retazec'.upper() == 'RETAZEC' 'stav,pismenko,novepismenko,novystav'.split(',') == ['stav', 'pismenko', 'novepismenko', 'novystav'] ': '.join(["janko","marienka"]) == 'janko:marienka'

  8. v jave Map<K,V> Zložitejšie kolekcie – slovník slovníkový typ s kľúčom Key a hodnotou Value je zobrazenie Key→Value Príklad: ilustrujeme slovník typu str → int, aj keď slovník tiež môže byť hetero • vytvorenie slovníka slovnik = dict({"janko":1, "marienka":2, "jezibaba":10}): <class 'dict'> • indexovanie kľúčom: slovnik["marienka"] • modifikácia: slovnik["janko"]=99 • odstránenie prvku: del slovnik["jezibaba"] • tlač: print(slovnik) {'marienka': 2, 'janko': 99} • cyklus cez kolekciu: for k,v in slovnik.items(): print(k,v)

  9. dovolí programovať: • procedurálne (štruktúrovane), • objektovo, • funkcionálne Multiparadigmový(štruktúrovane) • unikátnosť: indetovanie (odsadenie začiatku riadku od ľavého okraja) je dôležité a nahrádza blok {…}/begin…end • riadiace príkazy (if…elif…elif…else, for, while, break a continue) • nepozná repeat…until/do…while, ani case/switch • má výnimky (try…except…except…except:) • if cond: • ... • elif cond: • ... • else: • … • while cond: • ... • for var in sekvencia: • ... # funnySort  zoznam= [4,3,2,5,3,1,2,4,6,8,9,2] size = len(zoznam) for i in range(size): # i = 0, 1, …, size-1 for j in range(1, size): # j = 1, …, size-1 if zoznam[j] < zoznam[j-1]: zoznam[j-1], zoznam[j] = zoznam[j], zoznam[j-1] # paralelné :=

  10. def rekurzivny(m, n): if m == 0: return n + 1 if n == 0: return rekurzivny(m - 1, 1) return rekurzivny(m - 1, rekurzivny(m, n - 1)) riešenie anonymného študenta Prémia Ackerman fromcollectionsimportdeque# z modulu collection zober triedu deque def acker(m, n): """ riešenie ... - dokumentačný reťazec, ktorý sa patrí napísať """ parametre, vysledky = deque(), deque() # dva zasobníky na držanie stavu parametre.append( (m, n,) ) # vloženie (m, n) do zásobníka whilelen(parametre): m, n = parametre.pop() # vyber(m, n) zo zásobníka if n is None: n = vysledky.pop() # tretie pravidlo – časť 2 if m == 0:# prvé pravidlo vysledky.append(n + 1) continue if n == 0:# druhé pravidlo parametre.append( (m - 1, 1,) ) continue parametre.append( (m - 1, None,) ) # tretie pravidlo – časť 1 parametre.append( (m, n - 1,) ) return vysledky.pop()

  11. S jedným zásobníkom n m A(m,n) … … def ackermann(m,n): """ idea: zasobnik [zvysok,m,n<-] sa časom zmení na [zvysok,A(m,n)<-] """ stack = [m,n,] while len(stack) > 1:# pokiaľ sú na zásobníku 2 argumenty n = stack.pop() # vyber ich ... m = stack.pop() # ... v správnom poradí if m == 0:# [zvysok,0,n<-] => [zvysok,n+1<-] stack.append(n+1) elif m > 0 and n > 0: # [zvysok,m,n<-] => ([zvysok,m-1,m,n-1<-] stack.extend([m-1,m,n-1]) else:# [zvysok,m,0<-] => [zvysok,m-1,1<-] stack.extend([m-1,1]) return stack.pop()# na zásobníku zostal už len výsledok http://en.wikipedia.org/wiki/Ackermann_function

  12. Neštruktúrovane(goto in Python) • goto a comefrom boli pridané ako rozšírenia importované z modulu goto (1.apríla 2004) from goto import comefrom, label def bigFunction(): setUp() if not doFirstTask(): label .failed if not doSecondTask(): label .failed if not doThirdTask(): label .failed comefrom .failed cleanUp() from goto import goto, label for i in range(1, 10): for j in range(1, 20): for k in range(1, 30): print i, j, k if k == 3: goto .end label .end print "Finished\n" http://mail.python.org/pipermail/python-announce-list/2004-April/002982.html

  13. Stratila sa idea C,Java…, žefunkcie/ procedúry/metódy sa definujú rovnako, ako sa aplikujú. Tu sa dokonca volajú inak... Objektovo • triedy, • objekty, • preťažovanie operátorov • dedenie (aj viacnásobne) Definícia triedy a konštruktora: class BinTreeNode: """ definícia triedy s lokálnymi (triednymi) premennými """ left, right, value = None, None, None def __init__(self, left, value, right): # jediný konštruktor BinTreeNode self.value = value# volanie konštruktora self.left = left# tree = BinTreeNode(None,5,None) self.right = right prvý argument metódy je • v definícii explicitne self, t.j. objekt (self), na ktorý sa metóda aplikuje • pri volaní implicitne objekt (self), na ktorý sa metóda aplikuje

  14. Preťažovanie operátorov Niektoré operátory sú naviazané na metódy s preddefinovanými menami tvaru __xyz__ a tie môžeme predefinovať, napr.: def __str__(self):# textová reprezentácia objektu self return str(self.value)+"("+str(self.left)+","+str(self.right)+")" Vyhľadávanie v binárnom vyváženom strome: def__contains__(self, elem):# elem in self ifself.value == elem: # deep compare – porovná celé štruktúry return True# našiel sa elifself.value < elem:# musí byť v pravo ifself.right == None:# ak vpravo nie je nič return False else: return elem in self.right # rekurzia vpravo else:# musí byť vľavo ifself.left == None:# ak vľavo nie je nič return False else: return elem inself.left # rekurzia vľavo

  15. If it looks like a duck and quacks like a duck, it must be a duck Duck typing pes macka je forma dynamického typovania, dynamická náhrada virtuálnych metód class pes(): # definujeme dve triedy bez akejkoľvek defičnosti def zvuk(self): # obe definujú metódu zvuk() return "haw-haw" class macka(): def zvuk(self): return "mnau-mnau" def zvuk(zviera):# otázkou (statického programátora) je, akého typu je print(zviera.zvuk())# premenná zviera, keď na ňu aplikujeme .zvuk() # odpoveď: uvidí sa v RT podľa hodnoty premennej farma = [pes(), macka()]# heterogénny zoznam objektov for zviera in farma: zvuk(zviera) haw-haw mnau-mnau

  16. Ako by to pascalista s dedičnosťou animal dog cat cow class animal(): # nadtrieda def zvuk(self):# náznak virtuálnej metódy return "no sound" # neviem aký zvuk, resp. pass class dog(animal): # dog ako podtrieda animal def zvuk(self):# override metódy zvuk z animal return "haw-haw" class cat(animal): # cat ako podtrieda animal def zvuk(self): # override metódy zvuk z animal return "mnau-mnau" class cow(animal): # cow ako podtrieda animal pass# nemá vlastnú metódu zvuk # pass znamená prázdny príkaz for animal in [dog(), cat(), cow()] : print(animal.zvuk()) haw-haw mnau-mnau no sound

  17. List comprehension(množinová notácia) Táto téma sa ešte objaví v Haskelli V Pythone definujeme zoznam: [2*x for x in range(1,100)] [x*x for x in range(1,100) if x%2==0] [(x,x*x) for x in range(1,10)] [ [i for i in range(1,n+1)] fornin range(1,10)] V matematike definujeme množinu: M1= { 2x | x ε [1;100) } M2= { x2 | x ε [1;100), 2|x } M3= { (x, x2) | x ε [1;10) } M4= { {1..n} | n ε [1;10) }= { {1}, {1,2}, {1,2,3},… {1,2,3,4,…,9} } M5 = { (a,b,c) | a ε [1;n), b ε [1;n), c ε [1;n), a+b+c<=n, a2+b2=c2 } """ pythagorejske trojuholniky s obvodom najviac n """ [(a,b,c) for a in range(1,n) for b in range(1,n) for c in range(1,n) if a+b+c <= n if a*a + b*b == c*c ] [(3, 4, 5), (4, 3, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 6, 10), (8, 15, 17), (9, 12, 15), (9, 40, 41), (10, 24, 26),…

  18. Použitie list-comprehension(príklad Quicksort) list-comprehension je veľmi expresívna syntaktická konštrukcia, keďže v (matematikovi) blízkej notácii ukrýva jeden, resp. viacero vnorených cyklov s podmienkami. Dá sa bez nej žiť, avšak dostaneme rozsiahlejší a textovo menej prehľadný kód, ktorý používa rekurzívne/cyklické procedúry namiesto list-comprehension. Preto ju používajte ... ;-) Príklad (elegantného použitia list-comprehension): def quicksort(L): if len(L) <= 1: return L else: pivot = L[0] # prvý prvok triedeného zoznamu bude pivot ostatne = L[1:] # zvyšné triedené prvky okrem pivota return quicksort([x for x in ostatne if x<pivot])+\ # lilliputs [pivot]+\ # pivot quicksort([x for x in ostatne if x >= pivot]) # maxiputs print(quicksort([4,3,2,5,7,4,5,6,3,1,2,3,5]))

  19. Funkcionálne Python je inšpirovaný funkciami a funkcionálmi à la Haskell Python má lambda konštrukciu: dovolí definovať anonymné funkcie v tvare lambda <argumenty>:<telo>, napr.lambda x:x*x, t.j. x→x2 Je anonymná podoba pomenovanej funkcie def square(x): return x*x Rozdieľ (pre Pascalistu) spočíva v tom, že funkcie môžeme tvoriť v run-time, dynamicky, teda ich môžeme vytvoriť ľubovoľný počet... Funkcia je regulárna hodnota v jazyku, ktorú môžeme napr. • aplikovať (na argumenty) (lambda x:x*x)(5) 25 • mapovať (aplikovať fciu na každý element sekvencie) list(map(lambda n : n*n, [1,2,3,4,5,6,7,8,9,10])) [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] • filtrovať (vybrať zo sekvencie len prvky spĺňajúce daný predikát) list(filter(lambda n: n%2>0, [1,2,3,4,5,6,7,8,9,10])) [1, 3,5,7,9]

  20. matrix = [ [1,2,3], [4,5,6], [7,8,9] ] map & filter(príklady) • list(map(f,data)) znamená [f(x) for x in data] symetrie matice reprezentovanej ako zoznam riadkov matrix[::-1] [ [7,8,9], [4,5,6], [1,2,3] ] list(map(lambda row:row[::-1],matrix)) [ [3,2,1], [6,5,4], [9,8,7] ] • list(filter(p,data)) == [x for x in data if p(x)] prvočísla list( filter( (lambda n:0== sum( (1 for i in range(2,n) if n % i == 0) ) ), range(2,100) ) ) list(map(lambda i: n%i, range(2,n))).count(0),

  21. Closures(len pre fajnšmeckerov) def addN(n): # výsledkom addN je funkcia, return (lambda x:n+x) # ktorá k argumentu pripočína N add5 = addN(5) # toto je jedna funkcia x→5+x add1 = addN(1) # toto je iná funkciay→1+y # … môžem ich vyrobiť neobmedzene veľa print(add5(10))# 15 print(add1(10))# 11 def iteruj(n,f):# výsledkom je funkcia fn if n == 0: return(lambda x:x)# identita else: return(lambda x:f(iteruj(n-1,f)(x)))# f(fn-1) = fn add5SevenTimes = iteruj(7,add5)# +5(+5(+5(+5(+5(+5(+5(100))))))) print(add5SevenTimes(100)) # 135

  22. Python sa snaží byť lenivý Ale skutočná lenivosť príde až Haskellom Generátory(coroutiny) Generátor je procedúra/funkcia, ktorá má v istom bode prerušený (a odložený) zvyšok svojho výpočtu. Generátor odovzdáva výsledky volajúcej procedúre pomocou príkazu yield hodnota. Na obnovenie výpočtu (a pokračovanie v ňom) generátora slúži funkcia next(gener) def gen(n):# generátor generuje postupne čísla 0,1,2,...,n-1 for i in range(n):# cyklus pre i z intervalu yield i# yield vždy preruší výpočet cyklu a urobí return i print([x*x for x in gen(5)]) # for cyklus beží nad generátorom, [0,1,4,9,16] print(sum(gen(5)))# agregátor sum nad generátorom 10 print(list(gen(5)) # list nad generátorom pozbiera jeho výsledky g = gen(5) print(next(g)),print(next(g)),print(next(g)),print(next(g)),print(next(g)),print(next(g)),… 0 1 2 3 4 Exception

  23. Nekonečné generátory def integers(n):# generuje nekonečne veľa výsledkov tvaru while True:# n, n+1, n+2, … yield n n += 1 print(list(integers(1))) # toto nemôže nikdy vytvoriť celý zoznam print(min(integers(1))) # hoc minimum je zrejmé, ani toto nedobehne [n*2 for n inintegers(1)]# tu by už Haskell niečo dal, ale Python nie ... def take(n,g):# zober prvých n generovaných hodnôt gen. g for i in range(n): yield next(g)# next(g) vyprovokuje výpočet ďalšej hodnoty g print(list(take(10,integers(1)))) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

  24. Eratosten s nekonečnom sa dá pracovať len lenivo def sieve(d, sieved):# osievací generátor for x in sieved:# z generátora sieved prepúšťa len if (x % d != 0):# hodnoty nedeliteľné d yield x def eratosten(ints):# eratostenovo sito (prvočísla :-) while True: # zober generátor ints=integers(2) first = next(ints) # prvé číslo predstavuje prvočíslo yield first# toto sa reportuje výsledok eratosten ints = sieve(first, ints)# preosejeme čísla tak, že vyhádžeme # všetky deliteľné týmto prvočíslom # a pokračujeme v cykle print(list(take(100,eratosten(integers(2))))) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541]

  25. Fibonacci def zip(gen1, gen2): # zipovač dvoch nekonečných generátorov while True: # do nekonečna pýtaj výsledok gen1 a gen2 yield next(gen1), next(gen2) # a vráť dvojicu týchto výsledkov ako # výsledok generatora zip print(list(take(10,zip(integers(1), integers(2))))) def tail(gen): # tento generátor vracia hodnoty rovnaké next(gen) # gen, akurát prvý výsledok zahodí, ignoruje... while True: # potom už vráti, to čo od gen dostane yield next(gen) def fib(): # netradičná generátorová definícia Fibonacciho čísel yield 1 # prvý prvok postupnosti yield 1 # druhý prvok postupnosti for (x,y) in zip(fib(),tail(fib())):# zozipujeme fib a fib okrem prvého prvku yield x+y # z každej dvojice vyrobíme súčet a ten # prezentujeme ako ďalšie fib číslo print(list(take(20,fib())))

  26. exec& eval exec reťazec - je príkaz, ktorý z reťazca vykoná príkaz v ňom uložený eval(reťazec) - je funkcia, ktorá z reťazca vyhodnotí výraz Táto funkcionalita sa podľa očakávania nachádza v interpreteri. >>>exec('a=1; print("hodnota a=",a)')# hurá, pascalovská ; je tu späť hodnota a= 1 >>>eval('a*a+a') 2

More Related