!!1. Standardteek ja moodulid
Õpiku esimeses peatükis sai uuritud @@math@@ moodulit ning selle funktsioone ja konstante. Pythonis on palju rohkem selliseid mooduleid erinevate probleemide lahendamiseks. 

Näiteks:

* Kuidas saada kätte homne kuupäev? Kuu lõpus võib muutuda küsimus väga keeruliseks, kui seda ise üritada arvutada. Mitu päeva on praeguses kuus? Veebruari lõpus: kas on liigaasta? 
* Kuidas panna elemendid juhuslikku järjekorda? 
* Kuidas uurida kausta sisu Pythoniga? 
* Kuidas muuta faili nimesid? 

Pythonisse sisse ehitatud moodulid teevad lahendused sellistele küsimustele lihtsaks. Selles peatükis vaatame mõne huvitavama mooduli kasutamise näited. Uurime, kuidas moodulid üldse töötavad ja kuidas teha enda lihtne moodul.

!!!Ettevalmistus
Selle peatüki läbimiseks piisab Pythoni installatsioonist ning õpiku esimese peatüki lugemisest. Väikesel määral käsitletakse andmestruktuure, mida pole veel tutvustatud. 

Et kõigest aru saada, on soovitatav tutvuda funktsioonidega ([[https://progeopik.cs.ut.ee/04_funktsioonid.html#funktsioonide-defineerimine | peatükk 4]]) ja järjenditega ([[https://progeopik.cs.ut.ee/07_listid.html#jarjendid | peatükk 7]]). 

!!!Moodulite importimine
Tuletame kõigepealt meelde, kuidas mooduleid importida. Seda saab teha @@import@@ lause abil:

(:codestart python gutter='false':)
>>> import math
>>> math.cos(math.pi)
-1.0
(:codeend:)

Moodulitele saab anda ka nimesid @@as@@ lausega. Seda tehakse pigem harva ja pikemate või väga sagedasti kasutatavate nimedega. Tavaks on lühendada @@pandas@@ moodul @@pd@@-ks ja @@numpy@@ moodul @@np@@-ks. 

(:codestart python gutter='false':)
>>> import math as m
>>> m.cos(m.pi)
-1.0
(:codeend:)

Moodulitest saab importida ainult vajalikud muutujad kasutades @@from@@ lauset. Tervet moodulit sellega ei impordita. Mitu muutujat saab eraldada komaga.

(:codestart python gutter='false':)
>>> from math import pi, cos
>>> pi
3.141592653589793
>>> cos(pi)
-1.0
>>> math.pi
NameError: name 'math' is not defined
(:codeend:)

Tärni abil saab importida kõik mooduli muutujad. 

(:codestart python gutter='false':)
>>> from math import *
>>> pi
3.141592653589793
>>> e
2.718281828459045
>>> tau
6.283185307179586
>>> cos(pi)
-1.0
(:codeend:)

!!!Standardteek
Pythoniga tuleb kaasa palju mooduleid, mida nimetatakse kollektiivselt standardteegiks. Nende täisnimekiri on saadaval [[https://docs.python.org/3/library/ | Pythoni dokumentatsioonis]], aga vaatame lähemalt mõnda huvitavamat. 

!!!!Moodul math
Selle mooduli abil saab ligi matemaatilistele funktsioonidele, mida Pythonis vaikimisi ei ole. Täisdokumentatsioon: [[https://docs.python.org/3/library/math.html | https://docs.python.org/3/library/math.html]] 

Importimine:

(:codestart python gutter='false':)
>>> import math
(:codeend:)

Kasulikud konstandid ja funktsioonid:

(:codestart python gutter='false':)
>>> math.pi  # pii
3.141592653589793
>>> math.inf  # lõpmatus (kõik arvud on võrdlemisel sellest väiksemad)
inf
>>> math.floor(1.7)  # alla ümardamine
1
>>> math.ceil(1.3)  # üles ümardamine
2
(:codeend:)

(:codestart python gutter='false':)
>>> math.sqrt(2)  # ruutjuur
1.4142135623730951
>>> math.factorial(6)  # faktoriaal
720
>>> math.log(128, 2)  # logaritmid
7.0
>>> math.cos(math.pi)  # trigonomeetria
-1.0
(:codeend:)

(:codestart python gutter='false':)
>>> math.isclose(1.45, 1.46, rel_tol=0.01)  # tõeväärtus, kas kaks arvu on lähestikku rel_tol piires
True
(:codeend:)

Mõned kasulikud matemaatilised funktsioonid on Pythonisse juba sisse ehitatud:

(:codestart python gutter='false':)
>>> round(1.7)  # ümardamine
2
>>> round(1.337, 2)  # kahe komakohani ümardamine
1.34
>>> abs(-5)  # absoluutväärtus
5
>>> 2**0.5  # ruutjuur ilma math moodulita
1.4142135623730951
(:codeend:)

!!!!Moodul random
Selle mooduliga saab genereerida [[https://www.computerhope.com/jargon/p/pseudo-random.htm | pseudojuhuslikke]] arve, et tuua programmidesse juhuslikkust. Täisdokumentatsioon: [[https://docs.python.org/3/library/random.html | https://docs.python.org/3/library/random.html]] 

Importimine:

(:codestart python gutter='false':)
>>> import random
(:codeend:)

Kasulikud funktsioonid:

(:codestart python gutter='false':)
>>> random.randint(1, 10)  # juhuslik täisarv kahe arvu vahel
7
>>> random.randint(1, 10)
10
(:codeend:)

(:codestart python gutter='false':)
>>> random.random()  # juhuslik ujukomaarv 0 ja 1 vahel
0.8426622092891721
>>> random.uniform(1.5, 3)  # juhuslik ujukomaarv kahe arvu vahel
1.9124507393369863
(:codeend:)

(:codestart python gutter='false':)
>>> pakk = ["ärtu", "ruutu", "poti", "risti"]
>>> random.choice(pakk)  # juhuslik valik järjendist
"ruutu"
>>> random.shuffle(pakk)  # järjendi segamine
>>> pakk
['ruutu', 'risti', 'poti', 'ärtu']
(:codeend:)

!!!!Moodul datetime
Selle mooduli abil saab käsitleda kuupäevi ja aegu. Siin näites luuakse objekte, millest räägitakse täpsemalt peatükis "Objektorienteeritud programmeerimine". Praeguseks olgu need lihtsalt keerulised muutujad, millega saab erinevaid asju teha. Täisdokumentatsioon: [[https://docs.python.org/3/library/datetime.html | https://docs.python.org/3/library/datetime.html]]

Importimine:

(:codestart python gutter='false':)
>>> import datetime
(:codeend:)

Datetime objekti loomine (aasta, kuu, päev, tund, minut, sekund):

(:codestart python gutter='false':)
>>> kuupäev = datetime.datetime(2020, 2, 29, 12, 34, 56)
>>> kuupäev
datetime.datetime(2020, 2, 29, 12, 34, 56)
>>> kuupäev.year
2020
>>> kuupäev.second
56
(:codeend:)

Praeguse ajahetke saamine:

(:codestart python gutter='false':)
>>> praegu = datetime.datetime.now()
>>> praegu
datetime.datetime(2020, 2, 29, 18, 20, 33, 30651)
(:codeend:)

Datetime objekti vormindamine sõneks:

(:codestart python gutter='false':)
>>> praegu.strftime("%Y-%m-%d %H:%M:%S")
'2020-02-29 18:20:33'
(:codeend:)

Vormindamise märgendite nimekiri: [[https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes | https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes]] 

Datetime objekti parsimine sõnest.

(:codestart python gutter='false':)
>>> datetime.datetime.strptime("2020-02-29 18:20:33", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2020, 2, 29, 18, 20, 33)
(:codeend:)

Aegadele saab kestusi juurde liita ja maha lahutada, mille kaudu tekib uus datetime objekt. Liidame enne loodud kuupäevale juurde 13 tundi ja 37 minutit:

(:codestart python gutter='false':)
>>> kestus = datetime.timedelta(hours=13, minutes=37)
>>> kuupäev + kestus
datetime.datetime(2020, 3, 1, 2, 11, 56)
>>> kuupäev - kestus  # lahutada saab ka
datetime.datetime(2020, 2, 28, 22, 57, 56)
(:codeend:)

Seega homse kuupäeva saab kätte nii:

(:codestart python gutter='false':)
>>> homme = praegu + datetime.timedelta(days=1)
>>> homme
datetime.datetime(2020, 3, 1, 18, 20, 33, 30651)
(:codeend:)

!!!!Moodul os
Selle mooduliga saab ligi operatsioonisüsteemi funktsionaalsusele, näiteks failide asukohtadele.

Täisdokumentatsioon: [[https://docs.python.org/3/library/os.html | https://docs.python.org/3/library/os.html]]

Importimine:

(:codestart python gutter='false':)
>>> import os
(:codeend:)

Praeguse tee (current working directory) saamine:

(:codestart python gutter='false':)
>>> os.getcwd()
'/home/kasutaja/Python/Moodulid/'
(:codeend:)

Failinimede järjendi saamine praeguses kaustas ja määratud kaustas:

(:codestart python gutter='false':)
>>> os.listdir()
['programm.py', 'pilt.jpg', 'Uus kaust', 'Lõputöö.pdf']
>>> os.listdir('/home/kasutaja/Python/Moodulid/Uus kaust')
['saladused.txt']
(:codeend:)

Failinime muutmine: 

(:codestart python gutter='false':)
>>> os.rename("pilt.jpg", "foto.jpg")
>>> os.listdir()
['programm.py', 'foto.jpg', 'Uus kaust', 'Lõputöö.pdf']
(:codeend:)

Kausta loomine:

(:codestart python gutter='false':)
>>> os.mkdir("Teine kaust")
>>> os.listdir()
['programm.py', 'foto.jpg', 'Uus kaust', 'Lõputöö.pdf', 'Teine kaust']
(:codeend:)

Proovi kirjutada programm, mis loeb sisse kausta kõik failid ja väljastab nende sisu. Siin tuleb kasuks [[https://progeopik.cs.ut.ee/07_listid.html#for-tsukkel | for-tsükkel]]. Katseta seda kaustaga, mis sisaldab tekstifaile. 

!!!!Moodul sys
Selle mooduliga saab ligi süsteemipõhisele funktsionaalsusele. Täisdokumentatsioon: [[https://docs.python.org/3/library/sys.html | https://docs.python.org/3/library/sys.html]] 

Importimine:

(:codestart python gutter='false':)
>>> import sys
(:codeend:)

Käsurea argumentidele saab ligi `sys.argv` muutujast:

(:codestart python gutter='false':)
>>> sys.argv
['programm.py', 'esimene', 'teine']
(:codeend:)

Selline väärtus tuleb, kui käivitada Thonnys `programm.py` järgmise käsuga:

(:codestart python gutter='false':)
>>> % Run programm.py esimene teine
(:codeend:)

Või käsurealt:

(:codestart python gutter='false':)
kasutaja@arvuti ~/Python/Moodulid$ python3 programm.py esimene teine
C:\Users\kasutaja\Python\Moodulid> python3 programm.py esimene teine
(:codeend:)

Täisarvu maksimaalne väärtus praeguses arvutis:

(:codestart python gutter='false':)
>>> sys.maxsize
9223372036854775807
(:codeend:)

Pythoni interpretaatori versiooni saamine:

(:codestart python gutter='false':)
>>> sys.version
'3.7.6 (default, Jan 19 2020, 22:34:52) \n[GCC 9.2.1 20200117]'
(:codeend:)

Programmi töö lõpetamine:

(:codestart python gutter='false':)
>>> sys.exit("Põhjus")
(:codeend:)

!!!!Moodul this
Selle mooduli importimine väljastab Pythoni põhimõtted (''The Zen of Python''). Proovi seda importida.

!!!!Moodul antigravity
Seda proovi ise importida. :)

!!!Kuidas moodulid töötavad?
Importisime palju erinevaid mooduleid ja kasutasime nende konstante ja funktsioone, aga kuidas need üldse töötavad? Kuidas luua ise üks moodul?

Mooduli importimine tegelikult otsib üles sellenimelise Pythoni faili ja käivitab selle. Kõiki mooduli failis defineeritud muutujaid saab importivas programmis kasutada.

!!!!Isetehtud moodul
Proovime ise mooduli teha. Kirjutame programmi @@minumoodul@@@@.py@@, kus defineerime ühe konstandi ja lihtsa funktsiooni. Lisame ka ühe print-lause, et tõestada, kuidas kogu programm käivitub.

(:codestart python gutter='false':)
konstant = "Tere"

def ruut(n):
    return n**2

print("Moodul imporditud!")
(:codeend:)

Nüüd avame samas kaustas interpretaatori või loome uue Pythoni faili ja proovime tehtud moodulit importida ning muutujaid kasutada.

(:codestart python gutter='false':)
>>> import minumoodul
Moodul imporditud!
>>> minumoodul.konstant
'Tere'
>>> minumoodul.ruut(17)
289
(:codeend:)

Kõik muutujad töötavad ning sõnum väljastatakse. Üldiselt välditakse moodulite importimisega millegi väljastamist. Teised moodulid ju seda ei teinud.

Mooduli kõikide muutujate loetlemiseks on olemas sisseehitatud funktsioon @@dir()@@. Kui sulud tühjaks jätta, näidatakse kõiki muutujaid, mis on kogu programmis, s.h imporditud moodulid. Kui sulgude sisse panna muutuja, siis loetletakse selle muutujaga seotud muutujaid.

(:codestart python gutter='false':)
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'math', 'minumoodul']
>>> dir(minumoodul)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'konstant', 'ruut']
>>> dir(math)  # kui on imporditud
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
(:codeend:)

Kui kunagi satub ette võõras muutuja, on mõistlik jooksutada selle peal @@dir()@@ funktsioon, et näha kõiki selle võimalusi. Katseta ka @@help()@@ funktsiooni.

Saame ka uurida erinevate objektide funktsioone ja muutujaid. Vaatame eelnevalt mainitud datetime objekti võimalusi.

(:codestart python gutter='false':)
>>> from datetime import datetime
>>> praegu = datetime.now()
>>> dir(praegu)
['__add__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__radd__', '__reduce__', '__reduce_ex__', '__repr__', '__rsub__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', 'astimezone', 'combine', 'ctime', 'date', 'day', 'dst', 'fold', 'fromisocalendar', 'fromisoformat', 'fromordinal', 'fromtimestamp', 'hour', 'isocalendar', 'isoformat', 'isoweekday', 'max', 'microsecond', 'min', 'minute', 'month', 'now', 'replace', 'resolution', 'second', 'strftime', 'strptime', 'time', 'timestamp', 'timetuple', 'timetz', 'today', 'toordinal', 'tzinfo', 'tzname', 'utcfromtimestamp', 'utcnow', 'utcoffset', 'utctimetuple', 'weekday', 'year']
>>> praegu.year
2020
(:codeend:)

Leia vastused küsimustele:

* Mida teeb @@help()@@ funktsioon?
* Millised funktsioonid ja konstandid on @@re@@ moodulil?
* Millised funktsioonid ja muutujad on @@timedelta@@ objektil?

!!!!Moodulite asukohad
Kirjutasime enda mooduli interpretaatoriga samasse kausta ja saime seda importida, aga muud moodulid ei asu selles kaustas ja neid saab ikka importida. Kus need asuvad?

Pythonil on erinevate moodulite asukohtadest nimekiri nimega @@path@@. Sellele saab ligi mooduli @@sys@@ muutujast. 

(:codestart python gutter='false':)
>>> import sys
>>> sys.path
['', '/usr/lib/python37.zip', '/usr/lib/python3.7', '/usr/lib/python3.7/lib-dynload', '/home/kasutaja/.local/lib/python3.7/site-packages', '/usr/local/lib/python3.7/dist-packages', '/usr/lib/python3/dist-packages', '/usr/lib/python3.7/dist-packages']
(:codeend:)

Mooduli importimisel otsitakse need kaustad järjest läbi, alustades esimesest. Esimene kaust on tühisõne ehk esimesena vaadatakse üle kaust, kus programm käivitati. 

Imporditud moodulite failide asukohta saab ka näha:

(:codestart python gutter='false':)
>>> import turtle
>>> turtle
<module 'turtle from '/usr/lib/python3.7/turtle.py'>
>>> turtle.__file__
'/usr/lib/python3.7/turtle.py'
(:codeend:)

Mõned moodulid on Pythoni lähtekoodi sisseehitatud ja nende lähtekoodile nii lihtsalt ligi ei pääse.

(:codestart python gutter='false':)
>>> import math
>>> math
<module 'math' (built-in)>
>>> math.__file__
AttributeError: module 'math' has no attribute '__file__'
(:codeend:)

Proovi uurida moodulite @@this@@ ja @@antigravity@@ lähtekoode. Kas need vastavad ootustele?

!!!!Kas programm käivitati või imporditi?
Igal programmil (ja seega moodulil) on muutuja @@__name__@@ (kaks alakriipsu ees ja taga), mille väärtuseks on mooduli nimi sõnena. See muutuja on ka käivitataval programmil, aga selle väärtus on siis hoopis @@"__main__"@@.

(:codestart python gutter='false':)
>>> __name__
'__main__'
(:codeend:)

Kui @@__name__@@ väärtuseks on mooduli nimi, siis järelikult programm imporditi. Kui selle väärtus on @@"__main__"@@, siis see käivitati.

Tihti lisatakse programmi ette if-lause kontrolliga, kas programmi käivitati. Nii saavad teised arendajad programmi importida ja selle funktsioone kasutada ilma, et programmi põhiosa käivitub. 

(:codestart python gutter='false':)
if __name__ == "__main__":
    print("Programm käivitati, ei imporditud!")
(:codeend:)

Proovi seda järele @@minumoodul.py@@ programmis.

!!!Enesekontrolliküsimused
(:includeurl https://courses.cs.ut.ee/LTAT.03.001/2020_fall/uploads/Main/silmaring1_1.html width=100% height="230px" border="0" :)
(:includeurl https://courses.cs.ut.ee/LTAT.03.001/2020_fall/uploads/Main/silmaring1_2.html width=100% height="230px" border="0" :)
(:includeurl https://courses.cs.ut.ee/LTAT.03.001/2020_fall/uploads/Main/silmaring1_3.html width=100% height="230px" border="0" :)

!!!Ülesanded
1. Muuda @@minumoodul.py@@ programmi nii, et see väljastab sõnumi ainult siis, kui see käivitatakse. Importimisel ei tohi midagi väljastada.

(:codestart python gutter='false':)
>>> %Run minumoodul.py
Programm käivitati, ei imporditud!
>>> import minumoodul
>>> 
(:codeend:)

2. Kirjuta programm, mis võtab käsurealt sisendiks päevade arvu ning väljastab kuupäeva ja aja pärast sisestatud päevade arvu. 

Näide:

(:codestart python gutter='false':)
>>> %Run ajaarvutaja.py 1337
Praegune aeg on 2020-02-29 18:20:33.
1337 päeva pärast on aeg 2023-10-28 18:20:33.
(:codeend:)

3. Google Mapsi koordinaatsüsteemi laiuskraadide piirid on -85 kuni +85 ning pikkuskraadide piirid on -180 kuni +180. Et minna Google Mapsi rakenduses mingitele koordinaatidele, saab minna veebilehitsejaga aadressile @@https://maps.google.com/?q=laiuskraad,pikkuskraad@@. Näiteks Delta hoone puhul [[https://maps.google.com/?q=58.385894,26.725829 | https://maps.google.com/?q=58.385894,26.725829]]. 

Kirjuta programm, mis genereerib juhusliku koordinaadipaari ja avab veebilehitsejaga selle asukoha Google Mapsis. Veebilehitseja peaks avama lehekülge samamoodi, nagu seda teeb @@antigravity@@ moodul. Programmi koodi kirjuta kommentaar huvitava asukohaga, kuhu see sind viis. 

4. Kirjuta programm, mis kasutab asjalikult kolme erineva mooduli funktsionaalsust. Võib kasutada mooduleid, mida materjalides ei ole käsitletud.
