Top Banner
Č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 docs http://docs.python.org/py3k/ Python in Education http:// www.python.org / community / sigs / current / edu-sig / Learning with Python (2.x) http:// openbookproject.net // thinkCSpy Programovací jazyk Python http://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
26

Čo objaví Pascalista v Pythone

Feb 25, 2016

Download

Documents

sasson

Č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, ... ) - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Č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, 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 docs http://docs.python.org/py3k/ Python in Education http://www.python.org/community/sigs/current/edu-sig/ Learning with Python (2.x) http://openbookproject.net//thinkCSpy Programovací jazyk Python http://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

Page 2: Čo objaví Pascalista v Pythone

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

Page 3: Čo objaví Pascalista v Pythone

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'>

Rozdiel medzi dynamicky a staticky typovaným jazykom

Page 4: Čo objaví Pascalista v Pythone

Operácie nad základnými typmi

pozri si poriadne http://docs.python.org/library/stdtypes.htmlani 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

...toto sme nechceli robiť, ale niečo z toho môže byť na rozcvičke

Page 5: Čo objaví Pascalista v Pythone

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'> …

analógia kolekcií napr. z Java

Page 6: Čo objaví Pascalista v Pythone

Operácie so sekvenciami(najbežnejšie) x in s, x not in snachá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,…,???]

4 in [0,1,2,3,4,5] True4 not in range(6) Falselen(range(10)) 10max(range(10)) 9[0]*10 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0](0,)*3 (0, 0, 0)

Príklady:'t' in 'retazec‘ True't' not in 'retazec‘ Falselen('retazec') 7min('retazec') 'a''retazec'.index('t')2'r'*10 'rrrrrrrrrr'2*'r'*3 'rrrrrr'

Page 7: Čo objaví Pascalista v Pythone

Indexovaniesekvencia[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'

Page 8: Čo objaví Pascalista v Pythone

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íkaslovnik = 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)

v jave Map<K,V>

Page 9: Čo objaví Pascalista v Pythone

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:)

dovolí programovať:

•procedurálne (štruktúrovane),•objektovo,•funkcionálne

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é :=

Page 10: Čo objaví Pascalista v Pythone

Prémia Ackerman

from collections import deque # z modulu collection zober triedu dequedef 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 while len(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()

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

Page 11: Čo objaví Pascalista v Pythone

S jedným zásobníkom

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

nm

A(m,n)

http://en.wikipedia.org/wiki/Ackermann_function

Page 12: Čo objaví Pascalista v Pythone

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 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"

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()

http://mail.python.org/pipermail/python-announce-list/2004-April/002982.html

Page 13: Čo objaví Pascalista v Pythone

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 = rightprvý 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

Stratila sa idea C,Java…, že funkcie/procedúry/metódy sa definujúrovnako, ako sa aplikujú. Tu sa dokonca volajú inak...

Page 14: Čo objaví Pascalista v Pythone

Preťažovanie operátorovNiektoré 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 if self.value == elem:# deep compare – porovná celé štruktúry return True# našiel sa elif self.value < elem:# musí byť v pravo if self.right == None: # ak vpravo nie je nič return False else: return elem in self.right # rekurzia vpravo else: # musí byť vľavo if self.left == None: # ak vľavo nie je nič return False else: return elem in self.left # rekurzia vľavo

Page 15: Čo objaví Pascalista v Pythone

Duck typingje 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 premennejfarma = [pes(), macka()] # heterogénny zoznam objektov

for zviera in farma: zvuk(zviera)

If it looks like a duck and quacks like a duck, it must be a duck

haw-hawmnau-mnau

pes macka

Page 16: Čo objaví Pascalista v Pythone

Ako by to pascalista s dedičnosťouclass 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íkazfor animal in [dog(), cat(), cow()] : print(animal.zvuk())

haw-hawmnau-mnauno sound

dog cat cow

animal

Page 17: Čo objaví Pascalista v Pythone

List comprehension(množinová notácia)

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 ]

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)]

for n in range(1,10)]

[(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),…

Page 18: Čo objaví Pascalista v Pythone

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]))

Page 19: Čo objaví Pascalista v Pythone

FunkcionálnePython 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 funkciedef square(x): return x*xRozdieľ (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]

Python je inšpirovaný funkciami a funkcionálmi à la Haskell

Page 20: Čo objaví Pascalista v Pythone

map & filter(príklady)

list(map(f,data)) znamená [f(x) for x in data] symetrie matice reprezentovanej ako zoznam riadkovmatrix[::-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číslalist( filter(

(lambda n:0== sum( (1 for i in range(2,n) if n % i == 0)

) ), range(2,100) ))

matrix = [ [1,2,3],

[4,5,6], [7,8,9] ]

list(map(lambda i: n%i, range(2,n))).count(0),

Page 21: Čo objaví Pascalista v Pythone

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á funkcia y→1+y

# … môžem ich vyrobiť neobmedzene veľaprint(add5(10)) # 15print(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

Page 22: Čo objaví Pascalista v Pythone

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 10print(list(gen(5)) # list nad generátorom pozbiera jeho výsledkyg = gen(5)print(next(g)),print(next(g)),print(next(g)),print(next(g)),print(next(g)),print(nex

t(g)),…0 1 2 3 4 Exception

Python sa snaží byť lenivýAle skutočná lenivosť príde až Haskellom

Page 23: Čo objaví Pascalista v Pythone

Nekonečné generátorydef 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ý zoznamprint(min(integers(1))) # hoc minimum je zrejmé, ani toto

nedobehne[n*2 for n in integers(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]

Page 24: Čo objaví Pascalista v Pythone

Eratostendef 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)))))

s nekonečnom sa dá pracovať len lenivo

[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]

Page 25: Čo objaví Pascalista v Pythone

Fibonaccidef 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 zipprint(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 čísloprint(list(take(20,fib())))

Page 26: Čo objaví Pascalista v Pythone

exec & evalexec 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