Loeng 8: Sisseehitatud funktsioonide ülevaade, funktsiooni sulund, dekoraator ja @
operaator, lausend assert
, moodul ja faililaiend .py, programmi käivitamine käsurealt konsoolis, integreeritud arenduskeskkonna tutvustus ja kasutamine, kursusetöö juhend ja näidis¶
Koodinäited¶
Sisseehitatud funktsioonide ülevaade (Built-in functions)¶
Siiamaani oleme tutvunud muuseas sellega kuidas defineerida ja kasutada funktsioone, protseduure ja generaatoreid. Me oleme selleks kasutanud erinevaid tüüpe argumente (positsionaalsed, vaikeväärtusega, args- ja kwargs-tüüpi argumendid), lausendeid def
ja lambda
, ning lausendeid return
ja yield
, jne.
Nagu me juba teame tuleb Pythoniga kaasa hulk sisseehitatud funktsioone, järgnev on lühike ülevaade olulisematest. Osad nenedest funktsioonidest on meile juba tuttavad.
Valik sisseehitatud funktsioone:
range(stop)
range(start, stop[, step])
input([prompt])
len(s)
max(iterable[, key])
max(arg1, arg2, *args[, key])
min ...
id(object)
hash(object)
int(x, base=10)
float([x])
complex([real[, imag]])
str(object='')
list([iterable])
tuple([iterable])
dict(**kwarg)
dict(mapping, **kwarg)
dict(iterable, **kwarg)
set([iterable])
frozenset([iterable])
bool([x])
divmod(a, b)
pow(x, y[, z])
abs(x)
round(number[, ndigits])
chr(i)
bin(x)
ord(c)
hex(x)
all(iterable)
any(iterable)
reversed(seq)
sorted(iterable[, key[, reverse]]])
map(func, iterable, ...)
filter(func, iterable)
sum(iterable[, start])
zip([iterable, ...])
enumerate(sequence[, start=0])}
dir([object])
locals()
globals()
eval(expression[, globals[, locals]])
exec(source[, globals[, locals[, closure]]])
repr(object)
isinstance(object, classinfo)
issubclass(class, classinfo)
callable(object)
iter(object[, sentinel])
Kõigi sisseehitatud funktsioonide järgivaatamiseks kasuta funktsiooni dir
:
import builtins # Lausendist importi räägime tulevastes loengutes.
#dir(builtins) # Vt. iseseisvalt
round?
Signature: round(number, ndigits=None) Docstring: Round a number to a given precision in decimal digits. The return value is an integer if ndigits is omitted or None. Otherwise the return value has the same type as the number. ndigits may be negative. Type: builtin_function_or_method
NB! Viiega lõppevaid murdarve ümardame lähima paarisarvu suunas või lähima küsitud paarisarvulise komakohani, mitte suurema arvu suunas nagu õpetati enamustes põhikoolides:
round(4.5) # Tutvu iseseisvalt ja vt alla: Nn. "odd-even rounding rule".
4
print(round(0.125, 2)) # Ümarda kahe komakohani kasutades odd-even rounding rule'i.
print(round(0.005, 2)) # Ümarda kahe komakohani.
0.12 0.01
Uurides ülemise raku rida 2 tundub, et Python rikub enda reegleid mille kohaselt $0.005 \approx 0.00 \equiv 0$ mitte $0.005 \approx 0.01$ nagu just juhtus. Kuidas seda seletada? See juhtus kuna ujuvkomakohaga arvu ei saa arvutis üldjuhul täpselt esitada. Loe lisaks: https://docs.python.org/3.13/library/functions.html#round
round(2.87678, 3) # Ümarda kolmanda komakohani.
2.877
Pythoni reegli kus me ümardame lähime paarisarvuni (odd-even rounding rule) kasutamise põhjendus:
print('Arv --> Ümardatud arv')
lst0, lst = [], []
for i in range(10):
arv = i + 0.5
round_arv = round(arv) # Pythoni funktsioon round.
print(arv, ' --> ', round_arv)
lst0.append(arv)
lst.append(round_arv)
print(f'Algandmete keskmine: {sum(lst0) / 10}')
print('Ümardatud arvude keskmine:', sum(lst) / 10)
Arv --> Ümardatud arv 0.5 --> 0 1.5 --> 2 2.5 --> 2 3.5 --> 4 4.5 --> 4 5.5 --> 6 6.5 --> 6 7.5 --> 8 8.5 --> 8 9.5 --> 10 Algandmete keskmine: 5.0 Ümardatud arvude keskmine: 5.0
Võrdluseks: Kui kasutada põhikoolis õpetatud valet reeglit kus ümardatakse alati ülesse kui pole muid juhendeid antud, siis saame:
import math # Lausendist importi räägime tulevastes loengutes.
print('Arv --> Ümardatud arv')
lst0, lst = [], []
for i in range(10):
arv = i + 0.5
round_arv = math.ceil(arv) # Ümardame ülesse.
print(arv, ' --> ', round_arv)
lst0.append(arv)
lst.append(round_arv)
print(f'Algandmete keskmine: {sum(lst0) / 10}')
print('Ümardatud arvude keskmine:', sum(lst) / 10)
Arv --> Ümardatud arv 0.5 --> 1 1.5 --> 2 2.5 --> 3 3.5 --> 4 4.5 --> 5 5.5 --> 6 6.5 --> 7 7.5 --> 8 8.5 --> 9 9.5 --> 10 Algandmete keskmine: 5.0 Ümardatud arvude keskmine: 5.5
Funktsioon sorted
¶
Iteraatortoega objektide sorteerime. Funktsiooni kasutamise süntaks on järgmine:
sorted(<iterable>, /, *[, key [, reverse]])
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
sorted?
Signature: sorted(iterable, /, *, key=None, reverse=False) Docstring: Return a new list containing all items from the iterable in ascending order. A custom key function can be supplied to customize the sort order, and the reverse flag can be set to request the result in descending order. Type: builtin_function_or_method
L = ['cccc4','b3','dd2','aaa1'] # Lisaks numberitle järjestame ka tähestikulises järjekorras.
sorted(L)
['aaa1', 'b3', 'cccc4', 'dd2']
it = iter([3, 2, 1])
sorted(it) # Iteraator on iteaatortoega objekt.
[1, 2, 3]
sorted(L, key=len) # Võtmesõna key, sotrteerimisel kasuta funktiooni len.
['b3', 'dd2', 'aaa1', 'cccc4']
sorted(L, key=len, reverse=True)
['cccc4', 'aaa1', 'dd2', 'b3']
sorted(L, key=lambda x: float(x[-1])) # Enda loodud sorteerimisefunktsiooni kasutus.
['aaa1', 'dd2', 'b3', 'cccc4']
Sarnane listi meetodiga sort
mis omad samu argumente. DocStringis tähendab IN-PLACE, et algne mälus olnud list muudetakse sorteeritud listiks või teisisõnu asendatakse sorteeritud listiga. Eelmainitud funktsioon sorted
loob uue iteraatortoega objekti.
L.sort?
Signature: L.sort(*, key=None, reverse=False) Docstring: Sort the list in ascending order and return None. The sort is in-place (i.e. the list itself is modified) and stable (i.e. the order of two equal elements is maintained). If a key function is given, apply it once to each list item and sort them, ascending or descending, according to their function values. The reverse flag can be set to sort in descending order. Type: builtin_function_or_method
L.sort(key=len, reverse=True)
L
['cccc4', 'aaa1', 'dd2', 'b3']
Funktsioon map
¶
Funktsioon map
rakendab meelevaldselt valitud funktsiooni iga iteraatortoega objekti elemendile ja väljastab tulemused iteraatorisse. Meeldetuletus: Üle iteraatori saab itererida, iteraator mäletab enda viimast väljakutset ning sellele saab rakendada funktsiooni next
järgmiste väljakutsete genereerimiseks, vt. Loeng 7. Funktsiooni kasutamise süntaks on järgmine:
map(<func>, *<iterables>)
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
map?
Init signature: map(self, /, *args, **kwargs) Docstring: map(func, *iterables) --> map object Make an iterator that computes the function using arguments from each of the iterables. Stops when the shortest iterable is exhausted. Type: type Subclasses:
a = map(len, ('abc', 'cd', 'efgh'))
print(next(a)) # Esimene iteraat.
print(list(a)) # Funktsioon list itereerib üle iteraatori ammendumiseni.
3 [2, 4]
Kahe argumendiga funktsioonid:
a = map(pow, [2, 2, 2], [1, 2, 3]) # Funktsioon pow eeldab kahte argumenti.
list(a)
[2, 4, 8]
b = map(lambda x, y: x ** y, [2, 2, 2], [1, 2, 3])
list(b)
[2, 4, 8]
c = map(lambda x, y: x ** y, [2, 2, 2], (1, 2, 3))
for i in c: # Itereerin üle iteraatori c.
print(i)
2 4 8
Funktsioon filter
¶
Funktsioon filter
tagastab iteraatortoega jada elemendid, mille korral meelevaldselt valitud funktsioon(element) == True
. Väljastatud tulemuse andmetüüp on iteraator. Funktsiooni kasutamise süntaks on järgmine:
filter(<function> or <None>, <iterable>)
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
filter?
Init signature: filter(self, /, *args, **kwargs) Docstring: filter(function or None, iterable) --> filter object Return an iterator yielding those items of iterable for which function(item) is true. If function is None, return the items that are true. Type: type Subclasses:
iteraator = filter(bool, [True, 1, (1,), False, [], 0])
print(list(iteraator))
[True, 1, (1,)]
def positive(x):
if x > 0:
return True
else:
return False
a = filter(positive, [-1, 0, 1, 2])
print(list(a))
[1, 2]
def f(x):
if x > 0:
return x # Positiivne arv = mittetriviaalne täisarv.
print(list(filter(f, [-1, 0, 1, 2]))) # Mittetriviaalse objekt tõeväärtus on True.
[1, 2]
Anonüümne funktsioon ja funktsioon filter
:
a = filter(lambda x: x % 2 == 0, range(11))
list(a)
[0, 2, 4, 6, 8, 10]
a = filter(bool, 'Juulius on maskott.')
for i in a:
print(i, end=' ')
J u u l i u s o n m a s k o t t .
print(list(filter(None, 'Juulius')), end=' ')
['J', 'u', 'u', 'l', 'i', 'u', 's']
Funktsioon zip
¶
Funktsioon zip
seob iteraatortoega jadade elemendid elementhaaval korteeži. Väljastatud tulemus edastatakse iteraatorisse. Funktsiooni kasutamise süntaks on järgmine:
zip(*<iterables>)
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
zip?
Init signature: zip(self, /, *args, **kwargs) Docstring: zip(*iterables, strict=False) --> Yield tuples until an input is exhausted. >>> list(zip('abcdefg', range(3), range(4))) [('a', 0, 0), ('b', 1, 1), ('c', 2, 2)] The zip object yields n-length tuples, where n is the number of iterables passed as positional arguments to zip(). The i-th element in every tuple comes from the i-th iterable argument to zip(). This continues until the shortest argument is exhausted. If strict is true and one of the arguments is exhausted before the others, raise a ValueError. Type: type Subclasses:
a = zip('abc', 'ABC')
print(list(a))
[('a', 'A'), ('b', 'B'), ('c', 'C')]
Maatriksi transponeerimine:
M = [(1, 2), (3, 4)] # Tõlgenda 2x2 maatriksina.
MT = zip(*M) # Transponeeritud M.
print(list(MT))
[(1, 3), (2, 4)]
Funktsioon enumerate
¶
Funktsioon enumerate
nummerdab iteraatortoega jada elemendid ja väljastab tulemuse korteeži. Väljastatud tulemuse andmetüüp on iteraator. Funktsiooni kasutamise süntaks on järgmine:
enumerate(<iterable> [, start])
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
enumerate?
Init signature: enumerate(iterable, start=0) Docstring: Return an enumerate object. iterable an object supporting iteration The enumerate object yields pairs containing a count (from start, which defaults to zero) and a value yielded by the iterable argument. enumerate is useful for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ... Type: type Subclasses:
a = enumerate(['a', 'b', 'c'])
list(a)
[(0, 'a'), (1, 'b'), (2, 'c')]
a = enumerate(['a', 'b', 'c'], start=2)
list(a)
[(2, 'a'), (3, 'b'), (4, 'c')]
Kasutame sageli itereerimisega koos:
for i, c in enumerate('AUTO'): # Operaator in pakib korteežid lahti.
print(i, c)
0 A 1 U 2 T 3 O
Funktsioon isinstance
¶
Funktsioon isinstance
kontrollib objekti kuuluvuse andmetüüpi ning väljastab vastava booli tõeväärtuse. Funktsiooni kasutamise süntaks on järgmine:
isinstance(<obj>, class_or_tuple)
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
isinstance?
Signature: isinstance(obj, class_or_tuple, /) Docstring: Return whether an object is an instance of a class or of a subclass thereof. A tuple, as in ``isinstance(x, (A, B, ...))``, may be given as the target to check against. This is equivalent to ``isinstance(x, A) or isinstance(x, B) or ...`` etc. Type: builtin_function_or_method
isinstance(2, int) # Proovi ka klasse list, tuple, jne.
True
isinstance(2.0, float)
True
num_type = (int, float, complex)
print(isinstance('Python', num_type))
print(isinstance(2.0, num_type))
print(isinstance(2, num_type))
False True True
Funktsioon int
¶
Teatavasti meile juba tuttav konstruktorfunktsioon int
loob või teisendab avaldisi või muid andmetüüpe täisarvudeks. Funktsiooni int
saab kasutada ka arvude teisendamiseks erinevatest numbrisüsteemidest kümnendsüsteemi. Funktsiooni taolise kasutamise süntaks on järgmine:
int(<x>[, base=10])
kus positsionaalne vaikeväärtusega 10
argument base
on teisendatava arvu baas. Sama info koos funktsiooni DocStringiga ehk abiinfoga:
int?
Init signature: int(self, /, *args, **kwargs) Docstring: int([x]) -> integer int(x, base=10) -> integer Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero. If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int('0b100', base=0) 4 Type: type Subclasses: bool, IntEnum, IntFlag, _NamedIntConstant
a = int('0b10', 0) # Tõlgendab kui täisarvu. Töötab ka 10.
b = int('0b10', base=2) # Töötab ka 10.
c = int('0o123', 8) # Töötab ka 123.
d = int('0x121b', 16) # Töötab ka 121b.
e = int('10', 10)
print(a, b, c, d, e)
2 2 83 4635 10
Funktsioon int
toetab arvude aluseid vahemikus 2 kuni 36:
def example_vali_alus(b):
if 2 <= b <= 36:
arv = b - 1
print(f'Alusega {b} arv {arv} on kümnendsüsteemis {int(str(arv), b)}.')
else:
print('Alus peab olema vahemikus [2, 36]')
example_vali_alus(36) # Aluseks valiti 36.
Alusega 36 arv 35 on kümnendsüsteemis 113.
Funktsioon eval
¶
Funktsioon eval
interpreteerib sellele sõnena esitatud avaldise ja väljastab selle väärtuse. Funktsiooni kasutamise süntaks on järgmine:
eval(<source>[, global[, locals]])
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
eval?
Signature: eval(source, globals=None, locals=None, /) Docstring: Evaluate the given source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it. Type: builtin_function_or_method
eval('2 + 3')
5
eval("print('2 + 3')") # NB! Kui avaldis sisaldab jutumärke, kasuta erinevaid.
2 + 3
eval("abs(-1)", {"__builtins__": None}) # Eemaldati globaalsest skoobist sisseehitatud objektid.
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[45], line 1 ----> 1 eval("abs(-1)", {"__builtins__": None}) File <string>:1 TypeError: 'NoneType' object is not subscriptable
eval("abs(-1)", {"__builtins__": None}, {"abs": abs}) # Lisame tagasi ainult funktsioooni abs.
1
Lihtne kalkulaatoriprogramm kirjutatud kasutades funktsioone input
ja eval
:
tehe = input('Sisesta tehe:')
print(f'Tulemus: {tehe} = {eval(tehe)}.')
Tulemus: 1 + 2 = 3.
Funktsioon exec
¶
Funktsioon exec
interpreteerib sellele sõnes edastatud Pythoni koodi. Funktsiooni kasutamise süntaks on järgmine:
exec(<source>[, global[, locals]])
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
exec?
Signature: exec(source, globals=None, locals=None, /, *, closure=None) Docstring: Execute the given source in the context of globals and locals. The source may be a string representing one or more Python statements or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it. The closure must be a tuple of cellvars, and can only be used when source is a code object requiring exactly that many cellvars. Type: builtin_function_or_method
exec('print("Hello World!")') # NB! Kui avaldis sisaldab jutumärke, kasuta erinevaid.
Hello World!
code = 'a = 5 \nb = 10 \nprint("Sum =", a + b)'
exec(code)
Sum = 15
program = '''
for i in range(3):
print("Hello World!")
'''
exec(program)
Hello World! Hello World! Hello World!
Funktsioonid all
ja any
¶
Funktsioonid all
ja any
itereerivad üle iteraatortoega jada elementide ja rakendavad järjest paarikaupa operaatoreid and
funktsioonis all
ja or
funktsioonis any
nii kaua kuni leitakse vastus või kuni jada ammendub. Funktsioon all
väljastab True
kui kõik elemendid on tõesed või mittetriviaalsed ning funktsioon any
väljastab True
kui vähemelt üks element on tõene või mittetriviaalne.
Funktsioonide all
ja any
kasutamise süntaks on järgmine:
all(<iterable>)
any(<iterable>)
Sama info koos funktsiooni DocStringiga ehk abiinfoga:
all?
Signature: all(iterable, /) Docstring: Return True if bool(x) is True for all values x in the iterable. If the iterable is empty, return True. Type: builtin_function_or_method
any?
Signature: any(iterable, /) Docstring: Return True if bool(x) is True for any x in the iterable. If the iterable is empty, return False. Type: builtin_function_or_method
all([1, '', False])
False
all([1, 'a', True])
True
any([1, '', False])
True
any([0, '', False, [], {}, None])
False
Pesastatud funktsioon ja funktsiooni sulund (function closure)¶
Meeldetuletus: Kõrgemat järku funktsioonid võimaldavad vastuvõtta või väljastada funktsioone.
Tavaline pesastatud funktsioon. Väljastame pesastatud funktsiooni väärtuse teostades funktsiooni väljakutse peale lausendit return
. Seega tegu pole kõrgemat järku funktsiooniga:
def väline():
sõnum = 'Tere'
def sise(): # Pesastatud funktsiooni definitsioon.
print(sõnum) # LEGB reegel.
return sise() # NB! Funktsiooni väärtus.
väline()
Tere
Funktsiooni sulund võimaldab siduda või sulustada andmeid pesastatud funktsiooniga. Hilisemad pesastatud funktsiooni väljakud omavad juurdepääsu sulustatud andmetele. Selline käitumine järeldub otseselt muutujate skoobist ja LEGB reeglist:
def väline():
sõnum = 'Tere' # Sulustatud andmed: sõne 'Tere'.
def sise():
print(sõnum) # LEGB reegel.
return sise # NB! Väljastan funktsiooni, funk. on esimese klassi kodanik.
print(väline()) # Väljakutse väljastab funksiooni.
my_func = väline() # my_func <-- sise
print(my_func)
print(my_func.__name__) # Dunder atribuut.
my_func() # Kapseldava skoobi sõne 'Tere' pole funktsiooni sise osa aga tuli sellega kaasa.
<function väline.<locals>.sise at 0x1277a8e00> <function väline.<locals>.sise at 0x1277a8e00> sise Tere
Sulustatud sõne asub kapseldavas skoobis seega saame selle sulustada ka järgmiselt:
def väline(sõnum): # Kaspeldav skoop.
def sise():
print(sõnum) # LEGB reegel.
return sise # NB! Väljastan funktsiooni.
func = väline('Tere tudeng!') # Sulustan kapseldavasse skoopi 'Tere tudeng!'.
func()
Tere tudeng!
def tervitus(tervita):
def meenutus(keda): # LEGB reegel.
print(f'{tervita} {keda}') # LEGB reegel.
return meenutus
viisakus = tervitus('Tere') # Sulustan 'Tere'.
viisakus('seltsimees') # Edastan argumendi pesastatud funktsioonile meenutus.
Tere seltsimees
Näide: Funktsiooni sulundi kasutamine HTML koodi genereerimiseks. HTML dokumendi koodi kujul:
<h4>Juuliuse elu</h4>
<p>Juulius Tipikas sai eksamil viie.</p>
automatiseeritud loomine. Selline kood genereerib veebilehele järgmise väljundi mis sisaldab ühte neljanda astme pealkirja ja ühe lõiku teksti:
Juuliuse eluJuulius Tipikas sai eksamil viie. |
def html_tag(tag):
def wrap_text(text):
print('<{0}>{1}</{0}>'.format(tag, text))
return wrap_text
pealkiri = html_tag('h4') # Pealkirja tag.
par = html_tag('p') # Teksti lõigu tag.
pealkiri('Juuliuse elu')
par('Juulius Tipikas sai eksamil viie.')
<h4>Juuliuse elu</h4> <p>Juulius Tipikas sai eksamil viie.</p>
Funktsiooni dekoraator ja @
operaator¶
Dekoraator võimaldab olemasoleva funktsiooni käitumist muuta ilma funktsiooni definitsiooni ehk sisu muutmata. Dekoraator teeb seda sulundades funktsiooni.
Näide: Dekoraator mis muudab kaheargumendilise jagamistehtet teostava funktsiooni tehte järjekorda kui nimetaja on suurem lugejast:
def dekoraator(func):
def sise(a, b): # Pesastatud funktsioon.
if a < b:
a, b = b, a
return func(a, b) # Sulustatud funktsiooni väljakutse.
return sise # Väljastame pesastatud funktsiooni mis omakorda väljastab sulustatud funktsiooni väärtuse.
def jaga(a, b):
return a / b # Lugeja / nimetaja.
print(dekoraator)
print(dekoraator(jaga))
jaga = dekoraator(jaga) # NB! Dekoreerin funktsiooni jaga.
print(jaga(2, 4)) # Nimetaja on suurem.
<function dekoraator at 0x1277a9760> <function dekoraator.<locals>.sise at 0x11106bd80> 2.0
jaga(4, 2) # Nimetaja ei ole suurem.
2.0
@
operaator¶
@
operaator võimaldab eelolevat kirjapilti lühendada:
# Syntactic sugar, lühem kirjapilt.
@dekoraator # Asendab rida: jaga = dekoraator(jaga).
def jaga(a, b):
return a / b
jaga(2, 4) # Nimetaja on suurem.
2.0
Rakenduse näide: puhvermälu (memoization)¶
Rekursiivse Fibonacci jada liikmeid $F(n)$, kus $n$ on järjekorranumber, leidva funktsiooni optimeerimine. Aeglane rekursiivne funktsioon on kujul:
def rec_F(n):
'''Leiab n-da fibonacci jada liikme rekursiivselt.'''
if n <= 2:
return 1
return rec_F(n - 2) + rec_F(n - 1)
rec_F(6) # Aeglane ja sisuliselt kasutu kui n >> 1.
8
Mäletatavasti võtab see funktsioon palju aega tulemuste leidmiseks kuna sisemiste funktsioonide väljakutsete arv suure $n$ puhul kasvab röögatult. Programm teostab $2 F(n) - 1$ rekursiivset funktsiooni väljakutset $n$-da jada liikme $F(n)$ arvutamiseks, vt. vrd. Joonis 1.
Joonis 1. Rekursiivne Fibonacci jada liikme $F(n)$, kus $n$ on täisarv, leidmine. |
Kuna rekursiivne funktsioon teeb korduvaid funktsiooni väljakutseid (vt. Joonis 1) on kasulik eelnevalt leitud väljakutsete tulemused ajutiselt salvestada ning neid taaskasutada.
cache = {} # Tühi sõnaraamat.
def puh_F(n):
# Kui väärtus on mälus kasutame.
if n in cache:
return cache[n] # Edasi ei lähe kui tulemus leitud.
# Arvutame väärtuse.
if n <= 2:
tulem = 1
else:
tulem = puh_F(n - 2) + puh_F(n - 1) # Rekursioon.
# Salvesta tulem ja väljasta vastus.
cache[n] = tulem # Omistan sõnaraamatu võtmele n leitud väärtuse.
return tulem
puh_F(35)
9227465
Üldistame eeltoodud lahenduse luues dekoraatori. Eelnevalt leitud arvutustulemused saame sulustada funktsiooni sulundisse, ehk kasutada dekoraatorit kujul:
def cacheit(func):
cache = {} # Tühi sõnaraamat.
def sisemine(n):
tulem = cache.get(n) # Kontrollin kas sõnaraamatus on tulem.
if tulem is None:
tulem = cache[n] = func(n) # Lisan puuduva tulemuse sõnaraamatusse.
return tulem
return sisemine # Väljastan funktsiooni.
dec_rec_F = cacheit(rec_F) # Dekoreerin.
dec_rec_F(35)
9227465
Sama tulemus kasutades @
operaatorit:
@cacheit # Dekoreerin loodud dekoraaatoriga.
def alp_dec_rec_F(n): # Uus funktsiooni definitsioon.
if n <= 2:
return 1
return alp_dec_rec_F(n - 2) + alp_dec_rec_F(n - 1)
alp_dec_rec_F(146)
1454489111232772683678306641953
Kui palju kiiremaks me funktsioonid tegime? Teostame analüüsi leides aja mis kulub 200 funktsiooni väljakutse teostamiseks. Leiame näiteks Fibonacci jada 30-da liikme:
import timeit # Lausendit import pole veel õppinud.
def my_timeit(stmt,
setup='from __main__ import rec_F, puh_F, dec_rec_F, alp_dec_rec_F',
number=200):
aeg = timeit.timeit(stmt, setup=setup, number=number)
print ('Calling {:>18} took\t {:.2f} us/execution'.format(stmt, 1e6*aeg/number))
my_timeit('rec_F(30)') # rekursiivne,
my_timeit('puh_F(30)') # bufferdatud, dekoreerimata.
my_timeit('dec_rec_F(30)') # bufferdatud, dekoreeritud.
my_timeit('alp_dec_rec_F(30)') # bufferdatud, dekoreeritud @ operaatoriga.
Calling rec_F(30) took 60314.52 us/execution Calling puh_F(30) took 0.08 us/execution Calling dec_rec_F(30) took 293.36 us/execution Calling alp_dec_rec_F(30) took 0.07 us/execution
Jupiteri koodirakus ja iPythoni konsoolis saab interpreteerimisele kuulunud aega mõõta maagiliste käskudega %%timeit
ja %%time
:
%%timeit
rec_F(30)
58 ms ± 151 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
puh_F(30)
43 ns ± 0.0211 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
%%timeit
dec_rec_F(30)
57.2 ns ± 1.83 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
%%timeit
alp_dec_rec_F(30)
52.6 ns ± 0.275 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
Lausend assert
ja erisus AssertionError
¶
Lausend assert
kontrollib kas etteantud tingimuse tõeväärtus on True
. Juhul kui tingimus ei ole tõene peatatakse programm ja tõstatakse erisus AssertionError
.
tingimus1 = True # Ei juhtu midagi.
tingimus2 = False # Tõstatakse erisus.
assert tingimus1, 'Teade 1.'
assert tingimus2, 'Teate 2.'
--------------------------------------------------------------------------- AssertionError Traceback (most recent call last) Cell In[75], line 5 2 tingimus2 = False # Tõstatakse erisus. 4 assert tingimus1, 'Teade 1.' ----> 5 assert tingimus2, 'Teate 2.' AssertionError: Teate 2.
a = 1
b = 2
assert a < b, 'Muutuja b peab a-st suurem olema.' # Programm ei peatu.
Programmi käivitamine konsoolis käsurealt¶
Pythoni programmifaili ehk mooduli (skripti) laiend on .py. Me saame enda koodi kirjutada mistahes tekstiredaktorisse ning salvestada loodud tekstifaili faililaiendiga ".py". Loodud tekstifaili saab edastada Pythoni interpretaatorile kasutades konsooli.
Ava Anaconda prompt (Windows) või terminal (macOS, UNIX ja Linux) leia enda loodud Pythoni moodul ehk programmifaili (.py fail). Käivita programm järgmise käsuga:
python <mooduli nimi>.py
Konsooli kasutamiseks piisab kõigest kolme käsu teadmisest. Konsoolis navigeerid failisüsteemi järgmiselt:
ls
(MacOS, UNIX, Linux) võidir
(Windows) - Kausta sisu järgivaatamine;cd <alamkausta nimi>
- Liigu alamkausta;cd ..
- Liigu tagasi, eelmine kaust.
Integreeritud arenduskeskkond, IDE (Integrated Development Environment)¶
IDE on tarkvara mis võimaldab programmeerijal enda tööd paremini organiseerida ja juhtida. IDEd on tavaliselt varustatud koodiredaktoriga, koodi kompileerimis- ja/või interpreteerimistööriistadega ning siluriga (degugger).
Siiamaani oleme koodi kirjutanud suhtelistel lihtsates arenduskeskkondades nimega Jupyter Notebook või Jupyter Lab (iPython). Integreeritud arenduskeskkonna tarkvara võimaldab kirjutada pikemaid programme mugavamalt. IDE lubab meil avada ja salvestada .py programmifaile ehk Pythoni mooduleid, omada paremat ülevaadet muutujate väärtustest, jpm.
Spyder integreeritud arenduskeskkonna tutvustus¶
Joonis 2 kujutab Spyder IDE graafilist kasutajaliidest. Koodiredaktroisse kirjutatud koodi saab interpreteerida kasutades graafilist liidest (nupud ekraanuil) või kasutades klaviatuuri: (Ctrl + Enter = interpreteeri kood ja jää koodiblokki või Shift + Enter = interpreteeri kood ja liigu järgmisesse koodiblokki. Spyderis defineerime uue koodibloki alguse kasutades #%%
.
Joonis 2. Spyder IDE graafiline kasutajaliides, koodiredaktor, iPythoni konsool, abiinfo aken. |
Juurdepääs projektifailidele on tagatud läbi failihalduri mis on kujutatud Joonisel 3.
Joonis 3. Spyder IDE graafiline kasutajaliides, failihaldur. |
Loodud muutujate ja objektide väärtusi saab järgi vaadata muutujate lehitseja aknas mis on kujutatud Joonisel 4.
Joonis 4. Spyder IDE graafiline kasutajaliides, muutujate väärtuste aken. |
Spyder projekti koduleht: https://www.spyder-ide.org/
Juhuslik Spyderi IDEd tutvustav video: https://www.youtube.com/watch?v=zYNRqVimU3Q
Teised integreeritud arenduskeskkonnad¶
Kui sa soovid või oled harjunud mõnda muud IDEd kastama võid loendutes ja ka eksami praktilise osa ajal seda kasutada. TalTechi tudengite seas on polulaarsed IDEd näiteks Visual Studio (info: https://visualstudio.microsoft.com) ja PyCharm (info ja TalTech tudengile pro versiooni litsents: https://www.jetbrains.com/student/).
Kursusetööst¶
Kursusetöö juhend ja näidis¶
Kursusetöö juhend ja näidis on leitav kursuse kodulehelt ja Moodlest. Viidatud näidis demonstreerib muuhulgas kursusetöö vähimat vastuvõetavat mahtu.
Tudengite hindamisest kursusel YFX0500 ja eksamist¶
Esimese loengu jooksul mainiti, et kursusehinne koosneb kolmest osast: kursusetööst mis on eksamile pääsemise eelduseks ja kaheosalisest eksamist:
- Kursusetöö moodustab 5% kursusehindest, maksimaalselt on võimalik teenida kuni 5 pt.
- Eksam moodustab 95% kursusehindest, maksimaalselt on võimalik saada kuni 95 pt.
- Teoreetiline osa moodustab 45% kursusehindest, maksimaalselt on võimalik saada kuni 45 pt. Test toimub Moodles, testi saad võtta terve sessi jooksul. Testi sisu ja vormiga saab enne testi alustamist tutvuda.
- Praktiline osa moodustab 50% kursuse hindest, maksimaalselt on võimalik saada kuni 50 pt. Toimub kohapeal. Kodulehelt ja Moodlest leiad praktiline osa näidise. Näidiseksam lahendatakse läbi viimase nädala praktikumis.
- Ülesanne 1, süntaksireeglite peast tundmine: maksimaalselt kuni 5 pt.
- Ülesanne 2, silumine ja koodi analüüs: maksimaalselt kuni 10 pt.
- Ülesanne 3, algoritmi kasutus, andmete töötlus ja visualiseerimine: maksimaalselt kuni 35 pt.
Osa tudengitest teenivad ka lisapunkte või nn. brownie punkte loengutes ja praktikumides aktiivse osalemise eest. Need punktid (maksimaalselt kuni 10 p tudengi kohta) lisatakse kursusehinde punktisummale. Seega maksimaalselt on võimalik teenida kuni 100 + 10 = 110 p. Teenitud punktisummale vastava kursusehinde määratakse vastavalt kursuse kodulehel avaldatud hindamisskaalale.