Oblikovanje nizov

Kot vsak normalen jezik ima tudi Python nek način oblikovanja nizov. Iz zgodovinskih razlogov pravzaprav tri.

Operator %

V C-ju in jezikih, ki se zgledujejo po njem, imamo vzorce oblike "Danes sem videl %i primerkov %s.". To je tudi najstarejša oblika oblikovanja nizov v Pythonu, le da Python nima funkcij, kot je C-jev printf, temveč ima niz operator % (ja, recikliran operator za ostanek po deljenju), ki mu sledi terka z vrednostmi, ki jih je potrebno vstaviti. Če vstavljamo le eno vrednost, je ni potrebno dajati v terko.

"Danes sem videl %i primerkov %s." % (7, "medvedov")
'Danes sem videl 7 primerkov medvedov.'
"Danes sem videl %s." % "medveda"
'Danes sem videl medveda.'

Seveda lahko vključimo tudi vse ostale C-jevske trike - število mest, decimalk, predznak...

"π je približno %4.2f." % 3.14159265
'π je približno 3.14.'

To starodavno obliko boste v novejši kodi videvali le še v povezavi z modulom logging, zato v zvezi z njo ne bomo našteli vsega, kar se da (še) početi z njo in tega (še) ne poznati iz drugih jezikov, kjer ste morda srečali nize v tej obliki. Kdor hoče vedeti, bo pogledal dokumentacijo. Tu pokažimo le še tole: namesto terke lahko podamo slovar.

"Danes sem videl %(n)i primerkov %(zival)s." % {"n": 7, "zival": "medvedov"}
'Danes sem videl 7 primerkov medvedov.'

To je očitno še posebej uporabno predvsem

Slovar lahko vsebuje tudi odvečne elemente; Python jih bo pač ignoriral.

Metoda format

Nizi imajo metodo format. Ta znotraj niza poišče vse pare zavitih oklepajev in jih zamenja z istoležnimi argumenti, ki jih podamo ob klicu format. Bolj očitno bo iz primera.

vzorec = "Danes sem videl {} primerkov {}."

vzorec.format(7, "medvedov")
'Danes sem videl 7 primerkov medvedov.'

Dele lahko, tako kot prej, tudi poimenujemo.

"Danes sem videl {n} primerkov {zival}.".format(n=7, zival="medvedov")
'Danes sem videl 7 primerkov medvedov.'

Če želimo dodati oblikovanje, dodamo : in za njim obliko v običajni obliki.

"{n:.2f} odstotkov medvedov še ne spi.".format(n=3.14159265)
'3.14 odstotkov medvedov še ne spi.'

Če hočemo brez imena, pač naredimo brez.

"{:.2f} odstotkov medvedov še ne spi.".format(3.14159265)
'3.14 odstotkov medvedov še ne spi.'

Ta način je praktičen zato, ker je vzorec shranjen v obliki niza. Kaj s tem mislim, bomo videli, ko izvemo za trenutno aktualen način oblikovanja, kjer ni tako. V praksi pa tudi tega način ne uporabljamo več pogosto, zato bodi tudi o njem dovolj. Berite dokumentacijo.

Interpolacija

Danes je v vseh sodobnih jezikih v modi veliko prikladnejši način oblikovanja nizov. Tipično ga najdemo pod imenom string interpolation. Python ga ima od različice 3.6.

Ko pišemo niz, pred narekovaj (enojni ali dvojni ali trojni) damo znak f in Python bo vse, kar je znotraj zavitih oklepajev izračunal in vstavil v niz.

n = 7
zival = "medvedov"

f"Danes sem srečal {n} primerkov {zival}."
'Danes sem srečal 7 primerkov medvedov.'

Znotraj oklepajev so lahko celi izrazi.

fahr = 42

f"{fahr} Fahrenheitov je {(fahr - 32) * 5 / 9} Celzijev"
'42 Fahrenheitov je 5.555555555555555 Celzijev'

Tako kot pri format, lahko izrazu sledi dvopičje in nato format.

f"{fahr:3.1f} Fahrenheitov je {(fahr - 32) * 5 / 9:3.1f} Celzijev"
'42.0 Fahrenheitov je 5.6 Celzijev'

Vse je enako kot v C-ju: v formatu 4.1f številke, 4.1, pomenijo, da bi radi izpis na štiri mesta, pri čemer naj bo eno rezervirano za decimalko. Za črko f si predstavljajmo, da pomeni float. Če pustimo za število premalo prostora, ga bo izpis pač zasedel več.

x = 1234.5678
f"Primer predolgega števila: {x:3.1f}"
'Primer predolgega števila: 1234.6'

Še nekaj oblikovanja:

podatki = [
    (74, "Anze", False),
    (82, "Benjamin", False),
    (48, "Cilka", True),
    (66, "Dani", False),
    (61, "Eva", True),
    (101, "Franc", False),
    ]

for teza, ime, spol in podatki:
    print(f"{ime:10}{teza:6}")
Anze          74
Benjamin      82
Cilka         48
Dani          66
Eva           61
Franc        101

Znak, ki pove, za kaj gre (število, niz...) lahko tudi izpustimo in Python bo naredil, kot bo prav.

Opazimo, da so nizi privzeto poravnani na levo, številka na desno. To lahko spremenimo, če za dvopičje dodamo "puščico" <, > ali ^ (centriranje).

for teza, ime, spol in podatki:
    print(f"{ime:>10} {teza:<6}")
      Anze 74    
  Benjamin 82    
     Cilka 48    
      Dani 66    
       Eva 61    
     Franc 101   

Pred znak, ki določa poravnavo, lahko dodamo simbol, ki naj se uporabi za zapolnjevanje - če seveda nismo zadovoljni s presledkom. Poravnajmo imena levo, števile desno, namesto presledkov pa zapolnimo prazen prostor s pikami.

for teza, ime, spol in podatki:
    print(f"{ime:.<10}{teza:.>6}")
Anze..........74
Benjamin......82
Cilka.........48
Dani..........66
Eva...........61
Franc........101

Namesto pik lahko uporabimo poljuben drug znak. Kadar takole zapolnjujemo prostor s čimerkoli drugim kot s presledki, moramo dodati znake za poravnavanje (<, > ali ^), tudi kadar z njimi izberemo takšno poravnavanje, kot bi bilo tudi privzeto (desno za števila, levo za vse drugo) všeč.

Tega je seveda še ogromno. Določimo lahko, naj se vedno izpiše predznak, torej +, kadar je število pozitivno, zahtevamo izpis v dvojiškem ali šestnajstiškem sistemu.... Za števila lahko določimo, naj se izpišejo dvojiško ali šestnajstiško... Kdor potrebuje več kot to: dokumentacija.

Kdaj uporabiti kaj?

Vsaka oblika ima še vedno svoje prednosti.

V praksi: predlagam, naj vsa nova koda uporablja interpolacijo. Navadite se jih tudi zato, ker boste tudi v drugih sodobnih jezikih uporabljali interpolacijo, le sintaksa bo v vsakem jeziku malo drugačna.

Kontrolni znaki v nizih

Kontrolne znake zapisujemo tako, kot ste vajeni od drugod:

Če imamo v nizu veliko vzvratnih poševnic in se nam jih ne podvaja, uporabimo r-nize (r kot raw). Pred narekovaj damo znak r in vzvratna poševnica bo le še vzvratna poševnica. Kot naj bi (čeprav najbrž ni) rekel Freud: cigara je včasih vseeno samo cigara.

Vzvratno poševnico često pišemo v imenih direktorijev. Pišite navadno; tudi Windowsi jo že dolgo razumejo. Pač pa se boste z njimi pretepali v regularnih izrazih. Da, tam pa potrebujemo r-nize.

Komentar si zaslužijo še kode za Unicode: tudi teh ne potrebujemo pogosto. Programi v Pythonu so navadno shranjeni kot Unicode, praviloma UTF-8, in lahko brez težav vsebujejo znak π, kot smo prepričljivo videli tudi v enem gornjih nizov. Zato jih bomo z \N{GREEK SMALL LETTER PI} najbrž opisali približno tolikokrat, kot bomo veliki A opisali z \x41.

Delo z datotekami

Datoteke odpremo s funkcijo open(ime_datoteke). Če ne podamo drugih argumentov, jo bo Python odprl kot besedilno datoteko, za branje in s kodiranjem, ki je privzeto za sistem in je v spodobnih sistemih UTF-8, na Windowsih pa bogvekaj, recimo cp1250. open(ime_datoteke) je torej v normalnih razmerah isto kot open(ime_datoteke, "rt", encoding="utf-8"). Argument encoding podamo poimensko, ker je vmes še en nezanimiv argument in ker je poimensko podajanje (vsaj tu) tako ali tako lepše.

Branje besedilnih datotek

Datoteka, ki jo odpremo za branje, se vede kot generator, ki vrača vrstice. Običajno bomo datoteko torej brali z

for vrstica in open(ime):

Druge metode, ki vas lahko zanimajo, so:

Pisanje besedilnih datotek

Če želimo pisati v besedilno datoteko, jo odpremo z open(ime_datoteke, "w"), ki pobriše morebitno obstoječo datoteko s tem imenom, ali open(ime_datoteke, "a") (a kot append), ki dodaja na konec obstoječe datoteke. Namesto w in a lahko pišemo tudi wt ali at, vendar ni potrebno, ker je t (besedilna datoteka) tako ali tako privzeti način.

Edina res uporabna metoda za pisanje v datoteke je

Obstaja tudi

Zapiranje datotek

Datoteke imajo metodo close. V praksi jo redko kličemo,

Binarne datoteke

Binarne datoteke odpremo tako, da v niz, s katerim podamo način odpiranja, dodamo b. Torej open(ime, "rb") oziroma open(ime, "wb"). Ko beremo binarno datoteko - kar očitno počnemo z read in ne readline ali readlines, saj binarne datoteke nimajo vrstic - ne dobimo niza (str) temveč bajte (bytes). Torej čisto drug podatkovni tip. Prav tako z write v binarne datoteke zapisujemo bajte, ne nizov.

To pa je tema za ločeno poglavje, saj podatkovni tip bytes ni povezan le z datotekami.