Povedali smo že: Python ima tisoče in tisoče funkcij, zato morajo biti urejene, postavljene tja, kjer jih bomo lahko našli.
Enega od principov smo že spoznali: metode. Metode so pripete na reči
(bolj učeno in pravilno: objekte) in počnejo stvari, tipične za te reči.
Nizi imajo metode, kot so lower
in split
,
slovarji pa get
in setdefault
.
Poleg metod ima Python tudi funkcije, ki ne spadajo k nobenemu
specifičnemu tipu. Primera sta input
in print
.
A teh je malo; privilegij ležati kar tako, na prostem, ima le nekaj zelo
splošno uporabnih funkcij.
Večina funkcij, ki niso metode, je pospravljenih v škatlice. Škatlicam se v Pythonu reče modul (angl. module). Najbrž boste slišali tudi izraz paket (package) in celo knjižnica (library). Zaradi njih se ne vznemirjajte: paket je hierarhična zbirka modulov, knjižnica pa neka zaokrožena celota različnih ... modulov, paketov ... česarkoli. Za nas so tule pomembni samo moduli. Izvedeli bomo, kako jih uporabljati in videli nekaj uporabnih reči v nekaj uporabnih modulih.
Da uporabimo funkcije v modulu, moramo modul najprej uvoziti.
Doslej smo uporabljali, na primer, funkcije iz modula
math
in uvažali smo jih s from math import *
.
Pri poučevanju programiranja se izogibam temu, da bi morali tipkati
kakšne fraze, ki jih ne razumete. from math import *
je
bila ena redkih in čas je, da izvemo, za kaj gre. Ter tudi čas, da se te
fraze odvadimo in se naučimo pisati kot se spodobi.
Modul z matematičnimim funkcijami, math
, pravilno
uvozimo tako:
import math
S tem v bistvu dobimo novo spremenljivko, math
.
math
<module 'math' from '/Users/janez/opt/miniconda3/envs/prog/lib/python3.11/lib-dynload/math.cpython-311-darwin.so'>
Tole je spremenljivka najbolj čudnega tipa doslej. Ni preprosto
število (int
, float
) ali niz
(str
) ali seznam ali terka (list
,
tuple
), temveč spremenljivka vrste "modul" ("module").
Funkcije pripadajo modulu, tako kot metode objektu. če imamo niz
ime
, bomo do njegove metode upper
prišli s
piko, ime.upper
. Tu pa je podobno: če imamo modul
math
, bomo do njegove funkcije sqrt
prišli z
math.sqrt
, do njegove spremenljivke pi
pa z
math.pi
.
math.pi
3.141592653589793
/ 4) math.sin(math.pi
0.7071067811865475
Uvozimo še en modul, os
.
import os
V os
so funkcije, s katerimi lahko ustvarimo direktorij
ali pobrišemo datoteko. Poleg tega pa vsebuje še nekaj zanimivega:
modul. Modul path
je modul znotraj modula os
.
Vsebuje, recimo, funkcijo splitext
, ki za podano ime
datoteke vrne osnovo in končnico.
= os.path.splitext("nek_film.avi") osnova, koncnica
osnova
'nek_film'
koncnica
'.avi'
Tako se uvaža module.
Če funkcije določenega modula kličemo velikokrat in predvsem, če to počnemo v aritmetičnih izrazih, to postane nepregledno.
= 2 * math.sin(math.radians(phi) + math.pi / 2) - 2 * math.cos(math.radians(alpha)) x
Boljše bi bilo imeti te funkcije pri roki brez ponavljajočega se
math
. Uvozimo jih z
from math import sin, cos, radians, pi
/ 4) cos(pi
0.7071067811865476
from math import sin, cos, radians, pi
uvozi naštete
funkcije in postanejo, pod temi imeni, dostopne programu. Imeli bomo
torej imena sin
, cos
, radians
in
pi
, ne pa tudi tan
in log
.
Predvsem pa ne math
.
Se pravi:
import math
, imamo math
in,
recimo math.cos
, ne pa cos
. Uvozili smo pač
math
, ne cos
.from math import cos
pa imamo
cos
in ne math
ali math.cos
.
Uvozili smo pač cos
in ne math
.Obstaja še "preprostejši" način uvažanja.
from math import *
Ta je podoben prejšnjemu, le da funkcij ne naštevamo. *
predstavlja vse, kar je v modulu.
Prvi način, uvažanje modula, ima to prednost, da je v vsakem klicu funkcije jasno, odkod ta funkcija prihaja. Slabost so precej daljši izrazi.
Drugi način, uvažanje posamičnih funkcij skrajša izraze. Odkod
prihaja kakšna funkcija, še vedno vidimo, vendar je potrebno za to
pogledati na začetek programa, v import
-e.
Tretji način je v splošnem slab. Izrazi so krajši, vendar za
posamične funkcije ne vemo, odkod so prišle. Na ta način uvažamo
kvečjemu modul math
in nobenega drugega. Posebej v večjih
projektih.
Sprememba: gornji odstavek sem napisal pred desetimi leti. V resnici že dolgo, dolgo nisem uvozil modula na takšnen način, razen v prvih tednih Programiranja 1. Tudi vam ga ni treba. To se ne dela.
Vedno na začetku programa. Ne kar tako, vmes.
Izjemoma: na začetku funkcije. To storimo, recimo, kadar ni jasno, ali bo modul možno uvoziti, oziroma je uvažanje počasno, potrebujemo pa ga le v neki funkciji. Druga situacija, kjer bi to prišlo prav, je, če se dva modula uvažata vzajemno, eden drugega. To razrešimo tako, da določen modul uvozimo šele, ko ga potrebujemo.
To ni zakon, samo dogovor.
Uvažanje modulov se v resnici zgodi samo enkrat. Če petkrat napišemo
import math
, se bo modul v resnici uvozil le prvič.
math
Ogledali si bomo nekaj uporabnih modulov. Python jih ima približno dvesto; še tisoče in tisoče jih najdete na internetu.
Prvi je math
, vendar o njem ne bomo povedali veliko. Ima
pač vse funkcije, ki si jih ima katerikoli kalkulator ... in še malo
več. :) Na primer največji skupni delitelj, fakulteto in binomske
koeficiente ...
Priložnost izkoristimo le za to, da omenimo dve posebnosti v zvezi s
števili. Podatkovni tip float
premore poleg normalnih
števil še dve posebni: neskončno (in minus neskončno) ter ni-število
(not a number).
math.inf
inf
-math.inf
-inf
math.nan
nan
Prvi dve sta lahko uporabni za kako iskanje minimuma ali maksimuma.
def min(s):
= math.inf
m for x in s:
if x < m:
= x
m return m
math.inf
je večji od vseh števil (razen od sebe) in
torej uporabna začetna vrednost pri iskanju minimuma.
nan
je zanimivejša reč. V nekaterih jezikih ga dobimo
kot rezultat napačnih argumentov za matematične funkcije, recimo, če
poskušamo izračunati koren ali logaritem negativnega števila. Pythonove
funkcije v tem primeru vrnejo napako, pač pa ga vrnejo nekatere funkcije
v knjižnicah (modulih), ki si jih bomo namestili dodatno, zato je prav,
da veste zanj.
nan
, not a number, je slepa ulica števil.
Karkoli počnemo z njim - ga seštevamo, odštevamo, množimo, celo množimo
z nič - vedno ostane nan
. Še huje: nan
ni ne
večji ne manjši od nobenega števila. Niti od neskončno ni manjši (in
seveda ne večji, pa tudi enak ne).
< math.inf math.nan
False
> math.inf math.nan
False
== math.inf math.nan
False
In, najhujše, enak ni niti sebi.
== math.nan math.nan
False
Kako potem preverimo, če ima neka spremenljivka vrednost
nan
- če je ne moremo primerjati niti z
nan
?
= math.nan
x
if x == math.nan:
print("Ojoj!")
else:
print("Vse je OK.")
Vse je OK.
Pač, izkoristimo njegovo neumnost proti njemu samemu.
= math.nan
x
if x != x:
print("Svet se podira!")
Svet se podira!
Lepši, pravilnejši način, da preverimo, ali ima neka spremenljivka
vrednost nan
, je funkcija math.isnan
.
if math.isnan(x):
print("Ojoj!")
Ojoj!
Na vse to se bo koristno spomniti, ko bomo delali z, na primer,
kakšnimi statističnimi knjižnicami, ki bodo takrat, ko česa ne bo možno
izračunati, vrnili nan
.
Mimogrede, tole čudno obnašanje, po katerem nan
ni enak
niti samemu sebi, ni kakšna Pythonova muha, temveč del standarda IEEE
754, ki določa zapis števil s plavajočo vejico (float) in njegovo
vedenje. Enako se vede vsak vzgojen jezik.
random
Modul random
vsebujejo funkcije, ki počnejo
(psevdo-)naključne stvari. (To je: videti so naključne, vendar niso, saj
je vse, kar naračunajo običajni računlniki, izračunano in ne izžrebano.)
Omenili jih bomo le nekaj.
random.random()
vrne naključno število med 0 in 1.
import random
random.random()
0.8088080148072502
random.random()
0.5502323145363647
random.uniform(a, b)
vrne naključno število med
a
in b
. Funkcija se imenuje
uniform
, ker gre za enakomerno porazdelitev - vsa števila
so enako verjetna.
10, 20) random.uniform(
11.801216989018465
10, 20) random.uniform(
10.786154792833283
Če potrebujemo celo naključno število, pokličemo
randint
.
10, 20) random.randint(
13
Če nas namesto enakomerne zanima kakšna druga porazdelitev: modul
random
jih pozna veliko: beta, gama, eksponentna ... in
seveda tudi Gaussova.
= random.gauss(100, 10)
iq
iq
87.46911052444023
Sestavimo seznam imen.
= ["Ana", "Berta", "Cilka", "Dani", "Ema", "Fanči"] imena
random.choice
vrne naključni element podanega
seznama.
random.choice(imena)
'Ana'
random.sample
izbere naključni vzorec podane
velikosti.
3) random.sample(imena,
['Cilka', 'Fanči', 'Berta']
random.choices
je podoben, vendar se izbrani primeri
lahko tudi ponavljajo. Velikost vzorca mora biti podana kot argument z
imenom k
.
=5) random.choices(imena, k
['Dani', 'Cilka', 'Cilka', 'Cilka', 'Cilka']
random.shuffle
premeša podani seznam.
imena
['Ana', 'Berta', 'Cilka', 'Dani', 'Ema', 'Fanči']
random.shuffle(imena)
imena
['Cilka', 'Berta', 'Ana', 'Fanči', 'Dani', 'Ema']
os
Modul os
vsebuje kop reči, povezanih z operacijskim
sistemom. Ker o operacijskih sistemih ne vemo dovolj, večine funkcij ne
bi razumeli. (Ta prva oseba množine velja tudi zame. Sicer večino
razumem, o mnogih pa bi moral prebrati malo več, da bi vedel, za kaj
pravzaprav gre.) Prgišče pa jih bomo vseeno redno uporabljali.
getcwd()
vrne trenutni direktorij. Torej direktorij, v
katerem bi funkcija open
iskala datoteko, če bi ji podali
le ime datoteke.chdir(path)
spremeni trenutni direktorij. Pot je lahko
absolutna (s /
na začetku) ali relativna.mkdir(path)
naredi nov direktorij.remove(filename)
pobriše datoteko s podanim imenom.
Brez milosti. Nobenega "ali res želite pobrisati".rename(name, newname)
preimenuje datoteko.listdir(path)
vrne seznam vseh imen datotek v podanem
direktoriju.Največkrat boste potrebovali slednjo. Podatke iz vremenskih postaj, recimo, sem dobil v obliki tisočev datotek, ki sem jih potem prebral in (seveda filtrirane) podatke zapisal v novo datoteko.
Tole je trenutna vsebina trenutnega direktorija (v katerem so tile zapiski).
import os
os.listdir()
['temperature.svg',
'08b Numpy - naslednji koraki.ipynb',
'vremenske-postaje.txt',
'xml - zapiski.md',
'Untitled1.ipynb',
'kolesa.txt',
'avtorji-na-b.md',
'.DS_Store',
'kolesa2.txt',
'03c Slovarji.ipynb',
'06 Mnozice.ipynb',
'temperature.txt',
'Untitled.ipynb',
'07 Pisanje datotek (in se malo branja).ipynb',
'tecajnica.json',
'06 Moduli.ipynb',
'04 seznami.ipynb',
'vreme',
'authors-b.html',
'03a Kako racunalnik shrani besedilo.ipynb',
'temperature.pdf',
'test.json',
'09 Analiza podatkov in risanje.ipynb',
'12 Python in Excel.ipynb',
'temperature.png',
'11 Markdown in Jupyter, HTML, regularni izrazi.ipynb',
'xml',
'08 Osnove numpyja.ipynb',
'test.pkl',
'02b logični izrazi.ipynb',
'tecajnica.pickle',
'.ipynb_checkpoints',
'02 datoteke, zanke, pogoji.ipynb',
'besedilo.txt',
'05 Zanka `while`.ipynb',
'04 Terke.ipynb',
'10 Branje podatkov v standardnih formatih.ipynb',
'x.html',
'december.txt',
'05 Funkcije.ipynb',
'03b Metode nizov.ipynb',
'kolesa-z-glavo.txt',
'07 Oblikovanje nizov.ipynb']
os.path
path
je modul znotraj modula os
. Tudi ta
ima marsikaj, nekaj funkcij pa je primernih tudi za nas.
os.path.exists(name)
vrne True
, če (v
trenutnem direktoriju) obstaja datoteka ali direktorij s podanim
imenom.os.path.isdir(name)
vrne True
, če je
podano ime direktorij (znotraj trenutnega direktorija).os.path.isfile(name)
vrne True
, če je
podano ime datoteka (znotraj trenutnega direktorija).os.path.splitext(name)
vrne osnovo in končnico podanega
imena datoteke.Ostale so očitne, za nas je posebej zanimiva zadnja.
Izpišimo imena vseh datotek s končnico .txt, ki se nahajajo v trenutnem direktoriju.
for ime in os.listdir():
= os.path.splitext(ime)
osnova, koncnica if os.path.isfile(ime) and koncnica == ".txt":
print(ime)
vremenske-postaje.txt
kolesa.txt
kolesa2.txt
temperature.txt
besedilo.txt
december.txt
kolesa-z-glavo.txt
collections
Med vsemi zanimivimi rečmi v collections
vsaj za zdaj
omenimo le dve.
defaultdict
defaultdict
je slovar, ki sproti dodaja neobstoječe
ključe, podati pa mu moramo funkcijo, s katero si bo izmišljal njihove
vrednosti. Primerne so le funkcije, ki ne sprejemajo argumentov,
oziroma, točneje, funkcije, ki jih lahko pokličemo (tudi) brez
argumentov. Najpogosteje bo to int
. Če jo pokličemo brez
argumentov namreč vrne 0
.
int()
0
from collections import defaultdict
= defaultdict(int)
d
"Ana"] = 5
d["Berta"] = 3
d[
d
defaultdict(int, {'Ana': 5, 'Berta': 3})
Doslej nič posebnega, le pri izpisu nam ne pokaže samo slovarja,
temveč doda še, da je to defaultdict
s funkcijo
int
. Zabava se začne, ko povprašamo po ključu, ki ne
obstaja. Tu pokliče podano funkcijo (int
) in vrne njeno
vrednost, novi par pa doda tudi v slovar.
"Cilka"] d[
0
d
defaultdict(int, {'Ana': 5, 'Berta': 3, 'Cilka': 0})
Smemo celo, recimo, povečati vrednost neobstoječemu ključu.
"Dani"] += 1
d[
d
defaultdict(int, {'Ana': 5, 'Berta': 3, 'Cilka': 0, 'Dani': 1})
Preštejmo, kolikokrat se je avtor datoteke kolesa.txt vozil s katerim kolesom in koliko je prevozil z njim. Spomnimo se: vrstice datoteke predstavljajo posamične poti in vsebujejo ime kolesa, razdaljo v kilometrih in še nekaj, kar nas tu ne zanima (višino).
= defaultdict(int)
uporaba = defaultdict(int)
pot
for vrstica in open("kolesa.txt"):
= vrstica.split(",")
kolo, razdalja, _ += 1
uporaba[kolo] += int(razdalja)
pot[kolo]
print(uporaba)
print(pot)
defaultdict(<class 'int'>, {'Nakamura': 22, 'Cube': 43, 'Canyon': 26, 'Stevens': 9})
defaultdict(<class 'int'>, {'Nakamura': 439, 'Cube': 3174, 'Canyon': 2766, 'Stevens': 607})
Enako bi lahko naredili tudi z običajnimi slovarji, vendar bi
zahtevalo nekaj if
-ov ali pa metod, kot sta
setdefault
ali get
.
Zdaj pa se posvetimo dražbi: radi bi sestavili slovar, katerega
ključi bodo predmeti, vrednosti seznami ponudb za ta predmet. Spet bomo
uporabili defaultdict
, vendar vrednosti ne bodo
int
-i, temveč seznami. Funkcija list
nam, če
jo pokličemo brez argumentov, prikladno vrne prazen seznam.
= defaultdict(list)
d
"foo"] d[
[]
V tak seznam lahko celo dodajamo z append
!
"bax"].append(12)
d["bax"].append(5) d[
d
defaultdict(list, {'foo': [], 'bax': [12, 5]})
Zdaj pa zares.
= defaultdict(list)
ponudbe
for vrstica in open("../domace-naloge/03-drazba-brez-anonimnosti/zapisnik.txt"):
= vrstica.split(",")
predmet, oseba, cena int(cena))
ponudbe[predmet].append(
for predmet, cene in ponudbe.items():
print(predmet, cene)
slika [31, 33, 35, 37, 40, 45]
pozlačen dežnik [29]
Meldrumove vaze [44, 46, 48, 53, 57, 60, 61, 63, 67, 71, 76, 78]
skodelice [50, 55, 60, 61, 62, 65, 68, 70, 74, 76, 80, 83]
kip [30, 32, 37, 39, 43, 44, 45, 50, 53, 55, 58, 61, 63, 68, 72, 76, 77, 81, 85, 86, 90, 92, 94, 97, 98, 99, 100, 103, 107]
čajnik [15]
srebrn jedilni servis [27, 30, 35, 39, 40, 45, 47, 49, 53, 55, 58, 59, 62, 63]
perzijska preproga [16, 21]
Kako lažje bi bile domače naloge, če bi že pred par tedni vedeli za
defaultdict
! Vendar se potem nikoli ne bi naučili zares
delati z datotekami, zankami, seznami... ;)
Counter
Counter
iz nekega razloga pišemo z veliko. (Razlog ni
posebej dober. Iz istega razloga bi lahko z veliko pisali tudi
defaultdict
.
Counter
je v sorodu z defaultdict
-om in ga
včasih nadomešča. Trenutno nimamo pri roki dobrega primera za njegovo
uporabo, oziroma, točneje, da bi ga učinkovito uporabljali, bi morali
znati nekaj, česar še ne znamo. Vseeno pa lahko pokažemo, kaj počne.
Recimo, da imamo seznam imen oseb, ki jim je nekdo telefoniral.
= ["Ana", "Ana", "Berta", "Cilka", "Ana", "Cilka", "Dani", "Ema"] klici
Seveda želimo prešteti, kolikokrat je poklical koga. To bi znali kar
trivialno narediti z defaultdict
-om, s Counter
pa je še trivialneje:
from collections import Counter
= Counter(klici)
stevci
stevci
Counter({'Ana': 3, 'Cilka': 2, 'Berta': 1, 'Dani': 1, 'Ema': 1})
Pogosto nas bo zanimalo, koga je klical največkrat - ali pa katere tri - in za to obstaja metoda.
3) stevci.most_common(
[('Ana', 3), ('Cilka', 2), ('Berta', 1)]
Tole je seznam, urejen po pogostosti.
csv
Tale vam bo všeč. Datoteke, ki vsebujejo podatke, ločene z vejicami,
tako kot jih je naš zapisnik.txt
, so kar pogoste. Tej
obliki zapisa rečemo comma separated values ali, s kratico,
csv. V to obliko zna shranjevati tudi Excel - ob opozorilu, da se bo ob
tem izgubilo vse oblikovanje in še kaj. (Enkrat sem obljubil, da se bomo
učili brati Excelove datoteke. To še ni to. Brali bomo tudi .xlsx. Ampak
še ne.) V tej obliki je bil tudi naš zapisnik dražbe in vse druge
datoteke.
Python ima zato modul csv, ki zna brati take reči.
reader
Nas zanimajo imena vseh udeležencev dražbe?
import csv
= set()
udelezenci for predmet, oseba, cena in csv.reader(open("../domace-naloge/04-analiza-drazbe/zapisnik.txt")):
udelezenci.add(oseba)
udelezenci
{'Ana', 'Berta', 'Cilka', 'Dani', 'Ema', 'Fanči', 'Greta', 'Helga'}
Funkciji csv.reader
podamo datoteko (ne le imena,
potrebno je poklicati tudi open
). Vrne nekaj, čez kar lahko
gremo z zanko for
, pa dobivamo podatke iz vrstic. Nobenega
split
.
csv.reader
privzame, da so podatki ločeni z vejico. Če
so s čim drugim, mu to povemo z dodatnim argumentom
delimiter
. Ločilo v datoteki "kolesa.txt" iz pete domače
naloge je bil -
.
= "../domace-naloge/05-druzabno-omrezje-drazbe/kolesa.txt"
ime_dat
for v in csv.reader(open(ime_dat), delimiter="-"):
print(v)
['Cube', '5031', '159', 'Janez', '2017']
['Stevens', '3819', '1284', 'Ana', '2012']
['Focus', '3823', '1921', 'Benjamin', '2019']
Poleg ločila ima datoteka lahko še kup drugih lastnosti. Recimo, da na dražbi prodajajo komplet žlica, nož in vilice Ludvika XIV. V datoteki bi tako dobili vrstico
žlica, nož in vilice Ludvika XIV,Ana,12945
in s.split(",")
bi vrnil štiri stvari, namesto treh, pač
zaradi vejice med žlico in nožem. Excel, recimo, bi v tem primeru
napisal nekaj v slogu
"žlica, nož in vilice Ludvika XIV",Ana,12945
S tem, ko bi zaprl prvo polje v narekovaje, bi povedal, da gre tu za
eno samo reč in da je potrebno vejico znotraj tega ignorirati. Različni
programi in sistemi imajo različna pravila; temu se v jeziku funkcije
csv.reader
reče dialect
. Privzeti dialekt je
"excel"
in ta bo za datoteke iz Excela navadno delal. Za
ostale lahko uporabite Sniffer
.
= csv.Sniffer() sniffer
Z metodo .read()
preberemo celotno vsebino datoteke.
open(ime_dat).read()
'Cube-5031-159-Janez-2017\nStevens-3819-1284-Ana-2012\nFocus-3823-1921-Benjamin-2019\n'
sniffer
ima metodo sniff
, ki ji kot
argument damo vsebino datoteke (ali vsaj dovolj velik kos, da je iz
njega razvidno, kako je datoteka oblikovana). Sniffer bo uganil, v
kakšnem slogu je napisana datoteka.
= sniffer.sniff(open(ime_dat).read()) dialect
Nato pokličemo csv.reader
in mu poleg datoteke podamo še
dialekt.
Da bo lažje vidno, naredimo vse še enkrat.
import csv
= "../domace-naloge/05-druzabno-omrezje-drazbe/kolesa.txt"
ime_dat = csv.Sniffer() # vrne novega "snifferja"
sniffer = sniffer.sniff(open(ime_dat).read()) # preberemo vsebino datoteke in jo damo posniffati :)
dialect for v in csv.reader(open(ime_dat), dialect):
print(v)
['Cube', '5031', '159', 'Janez', '2017']
['Stevens', '3819', '1284', 'Ana', '2012']
['Focus', '3823', '1921', 'Benjamin', '2019']
DictReader
Recimo, da bi imeli takšno datoteko s kolesi:
kolo,razdalja,višina,lastnik,leto nakupa
Cube,5031,159,Janez,2017
Stevens,3819,1284,Ana,2012
Focus,3823,1921,Benjamin,2019
Za razliko od prejšnjih datotek (in vseh, ki smo jih videli doslej)
ima ta datoteka v prvi vrstici imena stolpcev. Zato jo lahko namesto z
reader
beremo z DictReader
, ki za vsako
vrstico ne vrne seznama temveč slovar, katerega ključi so imena
stolpcev. To je imenitno.
import csv
for vrstica in csv.DictReader(open("kolesa-z-glavo.txt")):
print(vrstica["kolo"], ":", vrstica["leto nakupa"])
Cube : 2017
Stevens : 2012
Focus : 2019
Ker bodo imele vaše datoteke zelo pogosto glavo, boste pretežno
uporabljali DictReader
. To je praktično, saj je s slovarji
lažje delati kot s seznami. Imena stolpcev, kot so kolo,
lastnik in leto nakupa je lažje brati kot indekse 0, 3
in 4, pa še zmotili se ne bomo pri štetju.
statistics
O modulu statistics
se ne bomo preveč razgovorili.
Osebno ga nikoli ne uporabljam, saj se vse to in še veliko več najde v
modulih knjižnice numpy
, s katero se da tudi veliko
preprosteje narediti veliko več - a le če znaš. Python ima ta modul
zgolj zato, ker je numpy
pač ogromna dodatna knjižnica, ki
je ne dobimo s Pythonom. (Po drugi strani pa si vsak resen uporabnik
pythona namesti tudi numpy
.)
Skratka: statistics
vsebuje funkcije mean
,
median
, mode
, stdev
in še kup
drugih, ki znajo za podani seznam izračunati poprečje, mediano, modus,
standardno deviacijo in še kup drugega.
import statistics
= [185, 192, 160, 173, 180] visine
statistics.mean(visine)
178
statistics.stdev(visine)
12.227019260637483
Ve tudi za korelacijo in linearno regresijo, tu pa se neha. Kdor bi
rad izvedel več, naj pogleda v dokumentacijo
modula statistics
.
time
,
datetime
, calendar
Pri delu boste najbrž pogosto naleteli na razne datume, čase in podobno. Funkcije, povezane s tem, so razmetane po treh modulih. Vse skupaj je prilična zmešnjava. Zanjo niti ni toliko kriv Python, kot, predvsem, dejstvo, da se tu navezuje na različne standardizirane funkcije različnih sistemov. Nekatere stvari na Windows delujejo drugače kot na macOS ali na Linuxu in potem dobimo, kar imamo.
time
Modul time
(dokumentacija) se
ukvarja s trenutnim časom in drugimi časi in pretvarjanjem med
njimi.
Glavna funkcija je time
, ki vrne število sekundo,
minevših od 1. januarja 1970 po Greenwichu.
import time
time.time()
1707583016.433111
To je uporabno, če bi radi merili (realen) čas, ki je minil med dvema dogodkoma v programu. Vendar ... no, ne zelo. Za to obstajajo boljše funkcije.
Za naše potrebe sta morda bolj uporabni gmtime
in
localtime
.
print(time.gmtime())
print(time.localtime())
time.struct_time(tm_year=2024, tm_mon=2, tm_mday=10, tm_hour=16, tm_min=36, tm_sec=56, tm_wday=5, tm_yday=41, tm_isdst=0)
time.struct_time(tm_year=2024, tm_mon=2, tm_mday=10, tm_hour=17, tm_min=36, tm_sec=56, tm_wday=5, tm_yday=41, tm_isdst=0)
Obe vrnete čudo istega tipa. Imenuje se struct_time
.
Tako ime kot oblika izhajata iz jezika C. Ime ni pomembno, pomembna so
imena polj, ki vsebujejo trenutno leto, mesec in dan, uro, minute in
sekunda, pa dan v tednu in letu, za zraven pa še polje, ki pove, ali gre
za letni čas (1) ali ne (0).
= time.localtime()
zdaj
print("Danes je ", zdaj.tm_mday, ". ", zdaj.tm_mon, ". ", zdaj.tm_year, ".", sep="")
Danes je 10. 2. 2024.
Modul vsebuje tudi funkcijo za oblikovanje datumov. Uporabimo jo takole:
"Danes je %d. %m. %Y, ura pa je %H.%M", zdaj) time.strftime(
'Danes je 10. 02. 2024, ura pa je 17.36'
Podamo ji niz, ki vsebuje znake, kot so %d
,
%m
, %Y
in tako naprej, ter čas. Funkcija bo te
znake zamenjala z ustreznimi vrednostmi.
Celoten seznam možnih znakov najdete na https://docs.python.org/3/library/time.html#time.strftime.
"Danes je %A, %d. %B %Y", zdaj) time.strftime(
'Danes je Saturday, 10. February 2024'
Tole ni izpadlo najboljše. Očitno se ni odločil za slovenščino. K temu bi se ga sicer dalo pripraviti.
import locale
"sl_SI") locale.setlocale(locale.LC_ALL,
'sl_SI'
Zdaj pa bo.
"Danes je %A, %d. %B %Y", zdaj) time.strftime(
'Danes je sobota, 10. februar 2024'
Tule smo mimogrede uporabili še module locale
, ki
vsebuje vse živo povezano z različnimi navadami različnih jezikov - od
imen dni in mesecev, do tega, ali uporabljajo decimalno vejico ali piko
in načina zapisa valut
42.19) locale.currency(
'42,19 SIT'
(haha, tolarji!)
datetime
Bistvo modula datetime
(dokumentacija)
je manipulacija z datumi. Z njim lahko odštejete dva časa in izveste,
koliko let, mesecev, dni, ur, minut, sekund je med njima. Ali pa
pripravite objekt vrste timedelta
, ki bo, recimo, dve
meseca in tri dni, ter to prištejete k nekemu datumu.
Še pomembneje: modul zna pretvarjati čase iz nizov.
from datetime import datetime
"13. november 2023, 21:14", "%d. %B %Y, %H:%M") datetime.strptime(
datetime.datetime(2023, 11, 13, 21, 14)
Najprej čudni import: iz modula datetime
uvozimo
"funkcijo" datetime
. (V resnici ni funkcija, temveč tip,
vendar za tole zdaj ni časa. :)
Funkcija strptime
zahteva niz, v katerem je zapisan
datum, in niz, ki pove obliko niza - spet s črkami, kot smo jih videli v
strftime
. Do delov rezultata spet dostopamo z imeni
polj.
= datetime.strptime("13. november 2023, 21:14", "%d. %B %Y, %H:%M") cas
cas.day
13
cas.hour
21
Tole vam bo znalo razkopati datum v prilično poljubni obliki. Takole opravimo z Američani.
"11/13/2023", "%m/%d/%Y") datetime.strptime(
datetime.datetime(2023, 11, 13, 0, 0)
Takole pa z Američani, ki pišejo leto brez stoletij.
"11/13/23", "%m/%d/%y") datetime.strptime(
datetime.datetime(2023, 11, 13, 0, 0)
calendar
Zadnji od treh modulov, povezanih s časom, je preprosti
calendar
(dokumentacije).
Ta vsebuje stvari kot so imena dni, mesecev in podobno.