Funkcijam, ki smo jih srečevali doslej, smo, da so kaj naredile,
morali dati podatke, na katerih so delale. Funkcija len
kot
argument zahteva seznam ali niz, katerega dolžino bi radi izvedeli.
Funkcija input
kot argument želi niz z vprašanjem, ki bi ga
radi zastavili uporabniku. Razen argumentov, ki jih podamo, te funkcije
nimajo drugih podatkov (vsaj ne, da bi mi vedeli zanje).
Ko smo se učili o seznamih, pa smo mimogrede naleteli na neko
nenavadnost: za dodajanje novega elementa v seznam nismo poklicali
funkcije, ki bi ji podali seznam in element (na primer
append(imena, "Ana")
), temveč smo morali napisati ime
seznama, ki mu je sledila pika in append
, kot argument pa
smo navedli le element, ki smo ga želeli dodati, torej
imena.append("Ana")
.
= []
imena "Ana")
imena.append("Berta")
imena.append( imena
['Ana', 'Berta']
append
je očitno nenavaden, ne kličemo ga tako kot druge
funkcije. Funkcija append
"pripada" seznamu; zato mu
pravimo imena.append
. Naredimo še en seznam.
= []
teze 55)
teze.append("Cilka") imena.append(
imena
['Ana', 'Berta', 'Cilka']
teze
[55]
Vsak seznam ima svoj append
: imena
imajo
imena.append
in teze
imajo
teze.append
.
Takšnim funkcijam pravimo metode. Klic
imena.append
si predstavljamo, kot da seznamu
imena
rečemo "dodaj si element" "Cene"
in
klic teze.append(55)
pomeni, da seznamu
teze
rečemo "dodaj si element" 55
.
Pika, .
izraža nekakšno pripadnost, vsebovanost. Ko smo
spoznali module, smo videli, da z math.sqrt
pridemo do
math
-ove funkcije z imenom sqrt
. Z
imena.append
zahtevamo "imenovo" metodo
append
. In s teze.append
"tezovo" metodo
append
.
Takšnih metod je še veliko: takole prosimo niz ime
, naj
nam pove, koliko črk "n" vsebuje.
= "Benjamin"
ime "n") ime.count(
2
Takole pa niz fname
vprašamo, ali se konča s
"torrent".
= "en film.torrent"
fname ".torrent") fname.endswith(
True
Kako bi Benjamina spremenili v Benjamaxa? Težko: kot vemo, so nizi nespremenljivi (tako kot terke; od vsega, o čemer smo govorili prejšnji teden, lahko spreminjamo samo sezname). Pač pa lahko vprašamo niz, kako bi bil videti, če "min" zamenjano z "max".
"min", "max") ime.replace(
'Benjamax'
Metode niso povezane s tem, ali je niz shranjen v spremenljivki ali ne. Metodo moremo poklicati tudi na nizu "kar tako".
"Maja".lower()
'maja'
Skoraj vsaka reč v Pythonu ima metode (ali vsaj nekaj podobnega). Celo običajna števila imajo metode, čeprav zgolj tehnično in z zelo čudnimi imeni, kot lahko vedoželjen študent hitro preveri.
= 3.14
x x.is_integer()
False
Med tipi, ki smo jih spoznali doslej, pa imajo uporabe vredne metode nizi in seznami. V okviru predavanj ne bomo podrobneje spoznavali vse mogočih podatkovnih tipov. Temeljiteje pa bomo pogledali metode nizov, seznamov in podobnih reči, ki jih pri programiranju v Pythonu vsakodnevno uporabljamo. Obenem bomo tako dobili vtis, kako te reči izgledajo.
Namen tega predavanja ni, da si zapomnite vse te metode in jih znate na pamet za izpit. :) Namen je le, da dobite predstavo, kako to deluje in kakšne vse stvari obstajajo. Za konkretna imena pa vam bo vedno na voljo dokumentacija.
Nekaj smo jih že spoznali: count
, replace
in lower
. Zadnja ima sestro, upper
, ki vrne
niz, pri katerem so vse črke pretvorjene v velike črke. Podobna sta še
capitalize
in title
.
"Maja".lower()
'maja'
"Maja".upper()
'MAJA'
"maja".capitalize()
'Maja'
"stavek, KI GA bomo povelikočrkovali po anGLEško".title()
'Stavek, Ki Ga Bomo Povelikočrkovali Po Angleško'
Da ne bi kdo pozabil, za vsak slučaj še enkrat spomnimo: te metode ne spreminjajo niza, temveč vračajo nove nize. Nizi ostanejo takšni, kot so bili. Po tem primeru bi moralo biti jasno, kaj ne deluje in kako je potrebno pisati, da bo delovalo.
= "Benjamin"
s s.upper()
'BENJAMIN'
s
'Benjamin'
= s.upper()
s s
'BENJAMIN'
Metodo count
smo že spoznali. Povejmo le še, da lahko
išče tudi daljše
"Maja".count("a")
2
"Maja".count("aj")
1
Poleg count
imamo tudi nekaj funkcij, ki povedo, kje v
nizu se nahaja določen podniz. Prvi sta find
in
index
.
"Benjamin".find("jam")
3
"Benjamin".index("jam")
3
Edina razlika med njima je v tem, kaj storita, če iskanega niza ni.
find
vrne -1, index
pa javi napako.
"Benjamin".find("max")
-1
"Benjamin".index("max")
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-22-c435d9d16506> in <module>
----> 1 "Benjamin".index("max")
ValueError: substring not found
Če se dani podniz pojavi večkrat, bosta funkciji vrnili indeks prve
pojavitve - razen, če jima z dodatnimi argumenti povemo, od kod naprej
naj iščeta. Poleg find
in index
obstajata še
funkciji rfind
in rindex
, ki iščeta s konca in
tako vrneta zadnjo pojavitev podniza v nizu.
Mimogrede smo že omenili tudi preprosto, a zelo uporabno funkcijo
endswith
, ki pove, ali se niz konča s podanim podnizom.
Poleg njega obstaja še startswith
, ki pove ali se niz
začne z danim podnizom.
Metode ljust
, rjust
in center
dopolnijo niz s presledki z leve, z desne ali z obeh strani, tako da je
dolg toliko, kot želimo. Takole napihnemo Benjamina na 15 znakov:
"Benjamin".ljust(15)
'Benjamin '
"Benjamin".rjust(15)
' Benjamin'
"Benjamin".center(15)
' Benjamin '
Še enkrat: te metode ne spreminjajo niza, temveč vrnejo nov niz! Nobena metoda ne more spremeniti niza.
Metoda strip
naredi ravno nasprotno: odbije presledke
(in tabulatorje in znake za prehod v novo vrstico) na levi in desni
strani niza. lstrip
in rstrip
pospravita samo
levo in samo desno stran.
" Benjamin ".strip()
'Benjamin'
" Benjamin ".lstrip()
'Benjamin '
" Benjamin ".rstrip()
' Benjamin'
Če se zdi ta metoda komu neuporabna, se moti. Zelo. Svojo zmoto bo spoznal, ko pridemo do branja datotek.
Nizi imajo še veliko metod. Pogledali bomo le še dve najzanimivejši.
Metoda split
razbije niz na seznam podnizov, kakor jih
ločujejo presledki, tabulatorji in znaki za nove vrstice. (V prvem
približku: razbije jih na besede.)
= "Metoda split razbije niz na seznam podnizov, kakor jih ločujejo presledki."
s s.split()
['Metoda',
'split',
'razbije',
'niz',
'na',
'seznam',
'podnizov,',
'kakor',
'jih',
'ločujejo',
'presledki.']
Presledkom, tabulatorjem in znakom za novo vrstico rečemo tudi
beli prostor (white space). Namesto glede na beli
prostor lahko split
razbije niz tudi glede na kak drug
znak, ki ga moramo v tem primeru podati kot argument.
"123-4123-21".split("-")
['123', '4123', '21']
"123-4123-21".split("1")
['', '23-4', '23-2', '']
Zadnja metoda, join
, dela ravno obratno kot
split
: združuje nize. Način, na katerega je obrnjena, je
nenavaden, a če malo razmislimo, vidimo, da drugače ne bi moglo
biti.
= ["Ana", "Berta", "Cilka", "Dani", "Ema"]
imena "".join(imena)
'AnaBertaCilkaDaniEma'
Praznemu nizu, ""
, smo "naročili", naj združi nize iz
podanega seznama. To sicer ni videti preveč lepo, lepše bo, če jih
združimo s kakim ločilom.
" - ".join(imena)
'Ana - Berta - Cilka - Dani - Ema'
", ".join(imena)
'Ana, Berta, Cilka, Dani, Ema'
" in ".join(imena)
'Ana in Berta in Cilka in Dani in Ema'
Najlepše pa bo, če vsa imena do zadnjega združimo z vejicami, nato pa z "in" pripnemo še zadnje ime. Ker ravno poznamo rezine.
", ".join(imena[:-1]) + " in " + imena[-1]
'Ana, Berta, Cilka, Dani in Ema'
To, mimogrede, deluje celo z dvema imenoma - prvo bo pač pustil pri
miru, saj v seznamu, kot je ["Ana"]
ni česa združevati:
= ["Ana", "Benjamin"]
imena ", ".join(imena[:-1]) + " in " + imena[-1]
'Ana in Benjamin'
Pri enem samem pa malo zataji.
= ["Ana"]
imena ", ".join(imena[:-1]) + " in " + imena[-1]
' in Ana'
Tako kot nizi imajo tudi seznami metodi count
in
index
, o katerih ne bomo izgubljali besed.
Medtem ko vam pri nizih metoda index
ne bo prišla
velikokrat na misel, jo boste, sodeč po izkušnjah iz preteklih
generacij, pridno zlorabljali na seznamih. Že kaka dva, tri tedne pred
temi predavanji jo nekateri študenti odkrijejo in si z njeno pomočjo
otežijo reševanje domačih nalog.
Metoda index
je v resnici uporab(lje)na zelo
redko. Metode index
prav gotovo ne gre uporabljati
znotraj zanke for
, ki gre prek seznama in ob tem poskuša
dobiti indeks trenutnega elementa.
Ena tipičnih zlorab je ta:
= ["Ana", "Berta", "Cilka", "Dani", "Ema"]
imena = [72, 78, 70, 65, 68]
teze for ime in imena:
= imena.index(ime)
i print(ime, "tehta", teze[i], "kilogramov.")
Ana tehta 72 kilogramov.
Berta tehta 78 kilogramov.
Cilka tehta 70 kilogramov.
Dani tehta 65 kilogramov.
Ema tehta 68 kilogramov.
Tole tule slučajno deluje. Neha pa delovati takoj, ko imamo v seznamu
dve enaki imeni: index
bo vrnil prvo.
= ["Ana", "Ana", "Ana"]
imena = [72, 78, 70]
teze for ime in imena:
= imena.index(ime)
i print(ime, "tehta", teze[i], "kilogramov.")
Ana tehta 72 kilogramov.
Ana tehta 72 kilogramov.
Ana tehta 72 kilogramov.
Tu se študenti tipično pritožijo: ko se ime
nanaša na
drugo Ano v seznamu, bi morala metoda index
po njihovem
vrniti indeks drugega elementa, 1
in ne 0
.
Če bi index
res delal tako: kaj bi dobili, če bi
poklicali imena.index("Ana")
? V tem primeru se niz
"Ana"
ne nanaša na nek specifičen element v seznamu.
V resnici je ime
v gornjem primeru vedno samo
"Ana"
. Ne neka konkretna Ana s tega seznama. Samo Ana. In
index
vrne prvo Ano.
Vem, vem, zakaj študenti pišejo programe, kot je gornji. Zaradi moje
reklame proti range(len(...))
. Radi bi napisali tole, a si
ne upajo.
= ["Ana", "Berta", "Cilka", "Dani", "Ema"]
imena = [72, 78, 70, 65, 68]
teze
for i in range(len(imena)):
print(imena[i], "tehta", teze[i], "kilogramov.")
Ana tehta 72 kilogramov.
Berta tehta 78 kilogramov.
Cilka tehta 70 kilogramov.
Dani tehta 65 kilogramov.
Ema tehta 68 kilogramov.
In prav je, da si ne upajo. To se naredi tako:
for ime, teza in zip(imena, teze):
print(ime, "tehta", teza, "kilogramov.")
Ana tehta 72 kilogramov.
Berta tehta 78 kilogramov.
Cilka tehta 70 kilogramov.
Dani tehta 65 kilogramov.
Ema tehta 68 kilogramov.
Kadar potrebujemo element in indeks, pa uporabimo
enumerate
.
for i, ime in enumerate(imena):
print(i, ":", ime)
0 : Ana
1 : Berta
2 : Cilka
3 : Dani
4 : Ema
Malo smo skrenili s poti, ampak je pomembno. Zato bom povedal še
enkrat preden uporabite index
, razmislite, ali ga
res potrebujete. Metoda index
je
Če je tako slab, zakaj obstaja? Ker ga včasih čisto legalno
potrebujemo. Zakaj pa o njem govorim programerjem - začetnikom? Zato,
ker ga sicer odkrijejo sami. index
je ena od stvari, za
katere je boljše, da otroci o njih slišijo od staršev, ne vrstnikov.
Zdaj pa nazaj k metodam.
Že nekaj časa vemo za append
, ki v seznam doda nov
element. Pazite, tole je zelo drugače kot pri nizih! Metoda
append
ne vrača novega seznama, temveč v resnici spreminja
seznam.
Kako pa bi k nizu pripeli seznam? Tule nam append
ne bo
pomagal: kar naredi, je povsem narobe.
imena
['Ana', 'Berta', 'Cilka', 'Dani', 'Ema']
"Fanči", "Ema", "Greta"]) imena.append([
Kaj smo pa pričakovali? Metoda append
prejme en
argument. In to kar prejme, doda k seznamu. Torej: kar ji podamo kot
argument, bo zadnji element seznama. Če torej append
-u
podamo seznam, bo seznam zadnji element seznama.
Metoda, ki bo naredila, kar hočemo, je extend
.
= ['Ana', 'Berta', 'Cilka', 'Dani', 'Ema']
imena "Fanči", "Greta"])
imena.extend([ imena
['Ana', 'Berta', 'Cilka', 'Dani', 'Ema', 'Fanči', 'Greta']
V resnici extend
-a praktično ne potrebujemo. Ker je
sezname možno seštevati, raje uporabimo kar +=
.
+= ["Helga", "Iva"]
imena imena
['Ana', 'Berta', 'Cilka', 'Dani', 'Ema', 'Fanči', 'Greta', 'Helga', 'Iva']
Metodi insert
podamo dva argumenta, indeks in element,
pa bo vstavila element pred element s podanim indeksom.
= ['Ana', 'Berta', 'Dani', 'Ema', 'Greta']
imena 2, "Cilka")
imena.insert(-1, "Fanči")
imena.insert( imena
['Ana', 'Berta', 'Cilka', 'Dani', 'Ema', 'Fanči', 'Greta']
Očitno deluje tudi indeksiranje s konca.
Elemente seznama lahko odstranjujemo na tri načine.
Prvi je del
. del
ni metoda in prihaja iz
povsem drugega vica, a vseeno ga pač omenimo, ker se ravno učimo o
spreminjanju seznamov. Uporabimo ga tako:
del imena[-2]
imena
['Ana', 'Berta', 'Cilka', 'Dani', 'Ema', 'Greta']
Metoda pop
vrne element s podanim indeksom in ga pobriše
s seznama.
2) imena.pop(
'Cilka'
imena
['Ana', 'Berta', 'Dani', 'Ema', 'Greta']
Metodo pop
redko uporabljamo za pobiranje elementov
sredi seznamov. Navadno na ta način poberemo prvi ali zadnji element.
Pravzaprav najpogosteje zadnjega, zato lahko pop
pokličemo
tudi brez argumentov, pa bomo dobili zadnji element.
imena.pop()
'Greta'
imena
['Ana', 'Berta', 'Dani', 'Ema']
Če bi hoteli, recimo, prestaviti prvi element na konec, bi napisali
0))
imena.append(imena.pop( imena
['Berta', 'Dani', 'Ema', 'Ana']
V obeh primeri, pri del
in pop
smo morali
podati indeks elementa, ki ga želimo odstarniti. Včasih nimamo indeksa,
pač pa poznamo vrednost elementa, ki ga želimo odstraniti. V tem primeru
uporabimo remove
.
"Dani")
imena.remove( imena
['Berta', 'Ema', 'Ana']
Pri tem ne odstrani vseh takšnih elementov, temveč le prvega, na katerega naleti, kakor lahko vidimo v spodnjem primeru.
= [7, 1, 2, 3, 4, 1, 1, 2]
s 1)
s.remove( s
[7, 2, 3, 4, 1, 1, 2]
Za metodo remove
velja vse, kar smo napisali za
index
. V resnici za remove
sicer obstaja več
situacij, ko ga "legalno uporabimo", vseeno pa je nevaren, ker odstrani
prvi takšen element; počasen, ker mora element najprej poiskati; pogosto
nepotreben (ker lahko poznamo indeks). Poleg tega pa je še zelo nevaren:
študenti ga radi uporabijo znotraj zanke, v kateri gredo čez prav ta
isti seznam. Brisati elemente seznama, čez katerega greš ravnokar z
zanko, je vedno zelo slaba ideja. Če uporabljaš for
ali če
nisi pošteno previden.
Metoda s.copy()
naredi kopijo seznama s
,
tako kot da bi napisali s = s[:]
. Navadno uporabimo
s.copy()
, ker bolj eksplicitno pove, kaj počnemo.
Metoda s.clear()
ga izprazni, kar je isto kot
s[:] = []
ali del s[:]
in ni isto kot
s = []
. Razlika je tako prefinjena, da bo vredna posebnega
predavanja. Navadno uporabimo s.clear()
.
Le še dve metodi sta nam ostali. reverse
obrne vrstni
red elementov v seznamu.
= [7, 2, 5, 1, 1]
s
s.reverse() s
[1, 1, 5, 2, 7]
Zadnja je sort
, ki uredi elemente po vrsti.
s.sort() s
[1, 1, 2, 5, 7]
Metoda deluje nad vsakršnimi elementi, ki jih je mogoče primerjati - z njo lahko uredimo seznam števil, nizov... Podamo ji lahko tudi kup argumentov, ki pa jih v tem trenutku še nismo zmožni razumeti.
Ne spreglejte razlike med metodami nizov in seznamov. Metode nizov
vračajo nove nize; s.replace("min", "max")
ni spremenil
niza s
, temveč vrnil nov niz. Metode seznamov spreminjajo
seznam; s.insert(2, "Ana")
ne vrne novega seznama, temveč
spremeni s
. Enako velja za sort
in
reverse
.
Tule omenimo še dve Pythonovi funkciji, ki nista metodi, sta pa podobni gornjima in študente pogosto bega razlika.
= [7, 2, 5, 1, 1]
s for e in reversed(s):
print(e)
1
1
5
2
7
s
[7, 2, 5, 1, 1]
sorted(s)
[1, 1, 2, 5, 7]
s
[7, 2, 5, 1, 1]
sort
in reverse
sta metodi seznamov. Imeni
sta v velelniku - uredi!, obrni! - torej uredita oz. obrneta seznam.
Torej: spremenita ga.
sorted
in reversed
sta funkciji. Imeni sta
urejen in obrnjen, vrneta torej nov seznam (reversed
v
resnici ne vrača seznama, vrne pa nekaj, kar se vede malo podobno kot
seznam). Seznam, ki ga podamo kot argument, ostane nespremenjen. Obe
funkciji skoraj vedno uporabimo za zanko for
.
Eden od razlogov, zakaj sorted
in reversed
nista metodi, je tudi, da lahko na ta način sprejemata različne
argumente. Zadovoljni sta tudi z nizom ali terko (in vsem drugim, čez
kar je možno iti z zanko for
).
sorted("berta")
['a', 'b', 'e', 'r', 't']
for e in reversed("berta"):
print(e)
a
t
r
e
b
Terke imajo enake metode kot seznami, manjkajo jim le metode, ki spreminjajo seznam.
In, presenečenje: vse metode seznamov spreminjajo seznam. Terke imajo
le metodi: count
in index
.