Doslej smo spoznali le prgišče funkcij - input
,
len
, sqrt
. V resnici pa skupaj s Pythonom dobimo
tisoče funkcij za vse mogoče reči, od pošiljanja pošte in kriptografije do
predvajanja zvoka in brskanja po datotekah .zip. Še večja gora funkcij
obstaja na spletu: karkoli si zamislite napisati, skoraj gotovo je nekdo
- če le gre za dovolj splošno reč - že potreboval kaj takšnega ter to tudi
napisal in vam dal na razpolago. Da se ne bi izgubili v gori funkcij (in
drugih reči), jih moramo nekako urediti.
Modul je zbirka funkcij (in omenjenih drugih reči). Veliko modulov dobimo
že kar ob namestitvi Pythona, druge poberemo z interneta. Da bi lahko
uporabljali funkcije iz modula, moramo modul najprej uvoziti, kar storimo
z ukazom import
, ki mu sledijo imena enega ali več modulov.
S Pythonom dobimo, recimo, modul z matematičnimi funkcijami, ki se imenuje
math
in ga uvozimo takole:
import math
To praviloma storimo na začetku programa. Ko je modul uvožen, kličemo njegove funkcije. Do funkcije, ki se nahaja v modulu, pridemo tako, da napišemo ime modula, piko, in ime funkcije.
>>> math.sqrt(2) 1.4142135623730951 >>> math.log(2.71828) 0.99999932734728203 >>> math.log10(100) 2.0
Primer druge reči, ki je v modulu, so konstante.
>>> math.pi 3.1415926535897931
Drug primer modula je, recimo, modul s funkcijami, ki vračajo naključna
števila (in počnejo tudi druge naključne reči), random
. Ta
ima, recimo, funkcijo randint(a, b)
, ki vrne naključno število
med podanima vrednostima a
in b
(vključno z
b
! Tu pravilo o tem, da b
ni vključen, ne bi
imelo veliko smisla). Še dve zanimivi funkciji sta choice
,
ki vrne naključno izbrani element seznama, in shuffle
, ki
naključno premeša elemente seznama.
>>> import random >>> random.randint(10, 20) 17 >>> random.randint(10, 20) 16 >>> random.randint(10, 20) 10 >>> l = ["Ana", "Berta", "Cilka", "Dani", "Ema", "Fanci"] >>> random.choice(l) 'Ana' >>> random.choice(l) 'Dani' >>> random.shuffle(l) >>> l ['Ana', 'Fanci', 'Dani', 'Cilka', 'Ema', 'Berta']
random.gauss(mu, sigma)
vrača naključna števila iz Gaussove
distribucije s podanim poprečjem mu
in varianco
sigma
. Tule je pet števil iz distribucije N(10, 3):
>>> for i in range(5): ... print(random.gauss(10, 3), end=" ") ... 8.96174816507 8.79299353551 8.75687382602 9.49106109252 8.21589651224
Poglejmo še en modul, os
. Ta vsebuje goro funkcij, povezanih
z datotekami in direktoriji (podatki o datotekah, preimenovanje, brisanje),
programi, ki tečejo na računalniku in drugo. Tako recimo funkcija
os.listdir
vrne seznam vseh datotek v direktoriju, katerega
ime podamo kot argument.
>>> os.listdir("/Users/janez/Dropbox/Pedagosko/P1/2014/03 seznami") ['blagajna.py', 'palindrom.py', 'stetje.py', 'domaca', 'razpakiranje.py', 'zapiski.html', 'fibo.py', 'seznami.py', 'zip.py']
Funkcija os.remove
pobriše datoteko s podanim imenom. Če bi
želeli v direktoriju c:\d\kontrabant
pobrisati vse datoteke s
končnico .pyc
, bi to storili takole:
for fname in os.listdir("/Users/janez/Dropbox/Pedagosko/P1/2014/03 seznami"): if fname[-4:] == ".py": os.remove("/Users/janez/Dropbox/Pedagosko/P1/2014/03 seznami" + fname)
Ob tej priliki povejmo, da ima v normalnih operacijskih sistemih vsak program
(bolj učeno: proces) nek "trenutni direktorij". Kadar imena direktorija
ne začnemo z / (ali \ ali c: ali čim podobnim na Windowsih), se ime nanaša
na datoteke oz. direktorije znotraj tega, trenutnega direktorija. Kakšen je
trenutni direktorij, nam pove funkcija getcwd()
(get current
working directory), spremenimo pa ga z os.chdir
. Kar smo
počeli zgoraj, bi se lahko napisalo tudi
Vse skupaj bi bilo morda lepše, če bi predtem zamenjali trenutni direktorij.
os.chdir("/Users/janez/Dropbox/Pedagosko/P1/2014/03 seznami") for fname in os.listdir("."): if fname[-4:] == ".py": os.remove(fname)
Ko smo ravno pri Windowsih, potarnajmo še, da ima znak \ v nizih v večini programskih jezikov poseben pomen. Danes povejmo le, da moramo, če hočemo dobiti \, napisati \\. Se pravi, ko bomo hoteli reči "c:\Users\janez", bomo morali napisati "c:\\Users\\janez". Na srečo lahko tudi na Windowsih že dolgo uporabljamo sicer običajnejši /.
Če bi datoteke raje preimenovali kot brisali - recimo tako, da bi k njihovem
imenu dodali .bak, to storimo z os.rename
, ki ji podamo staro
in novo ime datoteke.
for fname in os.listdir("."): if fname[-4:] == ".py": os.rename(fname, fname + ".bak")
Ob modulu os
se lahko naučimo še nečesa zanimivega: modul
lahko vsebuje celo druge module. Tako modul os
vsebuje modul
path
. Modula path
nam ni potrebno uvoziti,
dovolj je, da uvozimo os
. Lahko pa ga uvozimo tudi takole
import os.path
Razlike pravzaprav (skoraj) ni.
Modul os.path
vsebuje različne funkcije povezane z imeni
datotek in njihovimi lastnostmi. Zanimiva je, denimo,
os.path.splitext
, ki ji podamo ime datoteke in vrne terko z
dvema elementoma - osnovo imena in končnico. Pri tem ni potrebno, da
datoteka v resnici obstaja.
>>> os.path.splitext("/Users/janez/datoteka.txt") ('/Users/janez/datoteka', '.txt')
Ker vemo, da lahko terko razpakiramo v dve spremenljivki, bomo pogosto rekli kar
>>> osnova, koncnica = os.path.splitext("/Users/janez/datoteka.txt")
Gornji programček bi se torej še bolj lepo napisalo takole.
for fname in os.listdir("."): if os.path.splitext(fname)[1] == ".py": os.rename(fname, fname + ".bak")
Modul os.path
ima še kup zanimivih funkcij, recimo
funkcijo, ki pove, ali določena datoteka oz. direktorij obstaja
(os.path.exists
), funkcije, ki povedo ali določeno ime
predstavlja datoteko (os.isfile
), direktorij
(os.isdir
), povezavo (os.islink
) ali kaj
drugega, kar je znano na Unixu, v Windowsih pa ne.
Kaj je "imenski prostor" vam še ne nameravam, kaj "globalni", pa še ne morem povedati. Vseeno se lahko naučimo, kako uvažamo vanj.
Stvar je namreč jako preprosta. Morda se mi ne da stalno pisati
math.sin
, math.cos
, math.pi
. Če bi
raje pisal le sin
, cos
in pi
, bom
namesto z
import math
modul uvozil z
from math import sin, cos, pi
S tem povem dve reči. Prva: zanimajo me le tri reči, sin
,
cos
in pi
. Ostalih, recimo sqrt
,
ne potrebujem in naj jih ne uvaža. (Dejanski mehanizem je malo drugačen,
tudi sqrt
je v resnici uvožen, vendar ga ne vidim, a to ni
pomembno.) Druga: nočem, da se funkcije "skrivajo" v modulu
math
, hočem jih "tu", torej, hočem jih klicati, ne da bi moral
prej pisati math.
.
Pogosto smo leni ali, še pogosteje, ne vemo točno, katere vse funkcije bomo potrebovali, zato rečemo kar
from math import *
Zvezdica pomeni "vse funkcije" in hočemo jih tu, ne v math
.
Za to obliko uvoza sem vam, da nam je bilo enostavneje, pokazal, ko smo
začeli streljati s topom.
Temu načinu uvažanja se načelno izogibamo. Pogosto ga uporabljamo pri modulu
math
, iz drugih modulov pa uvažamo le posamične funkcije
(from random import randint
) ali pa pustimo modul kot modul
(import random
).
Napišimo program, ki bo vseboval konstanto odgovor
,
ki bo imela vrednost 42, in funkcijo, ki računa Fibonaccijeva števila.
odgovor = 42 def fibonacci(n): a = b = 0 for i in range(n): a, b = b, a+b return aProgram shranimo pod imenom fibo.py.
To je to. V drugem programu lahko rečemo
import fibo print("Odgovor je", fibo.odgovor) print("Deseto Fibonaccijevo število pa je", fibo.fibonacci(10))
Tudi vse ostale finte, na primer, from fibo import odgovor
,
delujejo.
Modul ni nič drugega kot program, ki ga uvozimo.
Tudi vsi drugi programi, ki ste jih napisali doslej, so hkrati moduli:
lahko jih uvozite. Pazite le na tole: ko modul uvozimo,
se ta v resnici izvede, čisto tako, kot bi se izvajal program.
Vse, kar se v tem programu-modulu definira, ostane definirano in se
nahaja v modulovem imenskem prostoru. Vendar se zgodi tudi vse ostalo,
kar piše v modulu: če pri izvajanju naleti na print("Foo")
se bo ob uvozu modula izpisalo Foo. Če program-modul vsebuje klic funkcije
(in ne le definicij), se bo ta funkcija poklicala tudi ob uvozu.
Kje Python išče module? Navadno v trenutnem direktoriju,
poleg tega pa še v drugih. Na Windowsih v, recimo,
c:\Python34\lib\site-packages
.
Več o tem si lahko preberete v dokumentaciji.
Tudi sicer ne bomo rinili prav globoko v module, samo še eno stvar omenimo, da vas ne bo presenetila. Ko boste prvič uvozili modul, se bo poleg datoteke s končnico .py pojavila še ena, za enakim imenom, a končnico .pyc. Python si vanjo "prevede" (pravzaprav bi smeli pisati brez narekovajev, temu se v resnici reče prevajanje) v obliko, v kateri ga bo lahko naslednjič hitreje uvozil. Pri manjših modulih se to ne pozna, pri velikem številu velikih modulov pa. Če vas moti, jo lahko pobrišete; drugič se bo pač spet pojavila ponovno.