PYTHON liburua/Ohiko datu-egiturak eta dagozkien metodoak

Wikibookstik

6. Ohiko datu-egiturak eta dagozkien metodoak[aldatu]

Programazio-lengoaia guztietan bezala Pythonen ere bertako funtzio-multzo bat dago, eta erabiltzaileak erabil ditzake nahiz eta berak ez dituen definitu. Built-in funtzio esaten zaie funtzio orokor horiei. Asko dira, eta ez daude objektuekin lotuta, nahiz eta datu-mota zehatzen gainean aplikatu behar diren. Zerrenda luzea da, osoa https://docs.python.org/3/library/functions.html gunean dago. Atal honetan erabilienak aipatuko ditugu. Beste batzuk hurrengo orrietan agertuko dira.

Lehenik eta behin, aipa ditzagun aurreko kapituluetan azaldu direnak: input, print, int, str, type, len eta range (gogoratu zertarako diren eta, beharrezkoa izanez gero, kontsultatu aurreko kapituluak). Geroago aipatuko diren dict, list eta open funtzioak ere asko erabiltzen dira. Aski erabiliak diren eta zenbakiekin zerikusia duten funtzio batzuk 6.1. taulan deskribatzen dira.

6.1. taula. Built-in funtzio garrantzitsu batzuk:
PROTOTIPOA EMAITZA
abs(n) Balio absolutua
bin(n) Baliokide bitarra
chr(n) Zenbakiari dagokion Unicode karakterea
%float(n) Zenbaki oso bati edo stringari dagokion zenbaki erreala
hex(n) Baliokide hamaseitarra
oct(n) Baliokide zortzitarra
ord(k) Unicode karaktereari dagokion zenbakia

Horrez gain, orain arte aipatutako datu-moten gainean metodo anitz daude aurredefinituta, datu-mota horiek berez klaseak direlako, eta dagozkien aldagaiak objektuak. Gainera, oinarrizko klase berri garrantzitsu bat eta dagozkion metodoak ere azalduko dira: hiztegiak. Eta garrantzi txikiagoko beste klase batzuk ere: tuplak, bektoreak, karaktere-bektoreak...

from google.colab import drive
drive.mount('/content/drive')

sst_home = 'drive/My Drive/Colab Notebooks/Python_UEU_20/kodea_izen_luzeak/kap6_datu_egiturak/'

6.1. OHIKO DATU-MOTEN GAINEKO METODOAK[aldatu]

Karaktere-kateak eta zerrendak, dagozkien metodoekin, aztertuko ditugu bereziki hemen. https://docs.python.org/3/library/stdtypes.html webgunean informazio zabalagoa lor daiteke.

6.1.1. Karaktere-kateen gaineko oinarrizko metodoak[aldatu]

Metodoak azaltzen sartu baino lehen jakin behar da karaktere-kateak indizeen bidez kudea daitezkeela. Horrela, zerrenden portaera imitatzen dute. Lehen karaktereari 0 indizea dagokio, bigarrenari 1... Indize negatiboak ere erabil daitezke bukaeratik abiatzeko: –1 azken karakterea da, –2 azken-aurrekoa... Adibidez, lehen erabilitako st katean

st = "PYTHON Lengoaia"

zuriunea identifikatzeko st[6] edo st[-9] erabil daitezke.

Indize-tarteak ere erabil daitezke string osoaren azpikateak adierazteko. Horrela, lehen hitza (PYTHON) adierazteko st[1:6] erabiliko genuke; eta bigarrenerako (Lengoaia) st[8:15] edo st[-8,-1].

Aipatutako len funtzioa eta lower eta upper metodoez gain, hainbat metodo erabil daitezke: count, startswith, endswith, find, replace, split eta join:

  • count metodoaren bidez kate batean karaktere bat edo azpikate bat zenbatetan azaltzen den konta daiteke. Kontatu nahi den karakterea edo katea izango da parametroa eta kopurua emaitza.
  • startswith eta endswith: lehen edo azken karaktereaz galdetzeko metodoak. • find metodoaren bidez kate batean ea karaktere bat edo azpikate bat dagoen bila daiteke. Bilatu nahi den karakterea edo katea izango da parametroa eta aurkitutakoaren indizea emaitza; aurkitzen ez bada bilatutakoa, emaitza –1 balioa izango da.
  • replace metodoa find-en antzekoa da, baina aurkitutako azpikatea ordezkatzen du.
  • split metodoaren bidez kate bateko osagaiak banatzen dira eta zerrenda bat osatuko du zati horiekin. Emaitza zerrenda bat da eta parametro gisa karaktere banatzaile bat zehatz daiteke, baina zehazten ez bada, ohiko banatzaileak (zuriunea, tabulazioa eta lerro-jauzia) erabiliko dira.
  • join aurreko metodoaren alderantzizkoa da, parametroa den zerrenda baten elementuak biltzen ditu emaitza den katean. Apur bat bitxia izan arren, oinarri gisa banatzailea erabiltzen da. Oso erabilia da emaitzak pantailaratzeko.

6.1. programaren bidez metodo horien erabilera eta emaitzak azaltzen dira. Egiaztatu ohar moduan agertzen diren emaitzak exekuzioan agertzen direnak direla.

6.1. programa. Oinarrizko metodoak karaktere-kateetarako:

st = "PYTHON Lengoaia"
#     012345678901234
st2 = "2,555,000"
print(st.lower())	# "python lengoaia"
print(len(st))		# 15
print(st.count('a'))	# 2
print(st.find('a'))	# 12 (lehen a-ren indizea, 0tik hasita)
print(st2.replace(',','.'))	# 2.555.000
print(st.split())		# ["PYTHON", "Lengoaia"] (zerrenda)
print(st2.split(','))	        # ['2', '555', '000']
print(','.join(st.split()))	# "PYTHON,Lengoaia" (karaktere-katea)

##Emaitza:
##python lengoaia
##15
##2
##12
##2.555.000
##['PYTHON', 'Lengoaia']
##['2', '555', '000']
##PYTHON,Lengoaia


Horrez gain, letra larria/xehea kudeatzeko metodo gehiago daude: capitalize (lehen karakterea larriz), title (hitz bakoitzeko lehen karakterea larriz) eta edukiaren nolakotasuna egiaztatzekoak (isalnum, isalpha, isdecimal, isdigit, islower, isnumeric, isprintable, isspace, istitle, isupper).

Esan bezala karaktere-kateen zati bat identifika daiteke indizeekin (0tik hasita): zatiaren hasierako posizioa eta bukaerakoa zehatz daitezke makoen artean eta ':' karaktereaz banatuta. Hasiera ez bada zehazten, 0 posizioa hartzen da, eta, bukaera posizioren faltan, katearen bukaeraraino hartuko da. Horrela, st[2:4] espresioak 3. eta 4. karaktereek osatutako azpikatea adierazten du, st[:2] espresioak lehen bi karaktereak, eta st[8:] espresioak 9.etik bukaera arteko katea. Indize bakar bat erabiltzen bada, ':' karakterea zehazten ez bada, jakina, posizio horri dagokion karakterea adierazten egongo gara (azken hori 4.9. programan erabili zen).

Adibidez, 6.1. programan ondoko kodea gehituta:

pos=st.find('a')
print(st[:pos])

##''PYTHON Lengo''


"PYTHON Lengo" agertuko da idatzita.

6.1.2. Zerrenden gaineko metodoak[aldatu]

Zerrenda datu-mota oso erabilia da eta dituen metodoei esker oso mota ahaltsua da. Zerrendak esleipen batez hasiera daitezke (adib. aukerak= ["bai","ez"]) edo list funtzioaren bidez (aukerak= list("bai","ez"). Zerrenda hutsa ere defini daiteke (adib. aukerak= []).

Zerrendako elementu zehatzak eta azpizerrendak ere erabil daitezke makoak eta ':' karakterea erabiliz. Horrela, zerrenda[0] lehen osagaia da eta zerrenda[:2] espresioaren bidez lehen bi osagaiak adierazten dira.

Bestalde, zerrendako elementu txikiena eta handiena hautatzeko min() eta max() funtzioak erabil daitezke; len() osagai kopurua lortzeko; eta '+' eragilea bi zerrenda kateatzeko.

Baldintzazko egituretan erabiliak izateko diseinatuta daude in eta not in eragiketak. Adibidez:

if hitza in hitzerrenda:


Zerrenden gaineko metodoei dagokienez, aipatutako append metodoa da interesgarrienetako bat, zerrendari osagaiak, banan banan, gehitzea ahalbidetzen baitu. Horrez gain, hainbat metodo erabil daitezke:

  • extend metodoaren bidez zerrendak bil daitezke. append funtzioaren modukoa da, baina osagai bat gehitu beharrez beste zerrendako osagai guztiak gehitzen ditu. (z.extend(z2) eta z=z+z2 espresioak baliokideak dira.
  • insert metodoaren bidez kate batean elementu bat txerta daiteke zehaztutako posizio batean. Beraz, elementua eta posizioa dira argumentuak. * count metodoaren bidez zerrenda batean balio bat zenbatetan azaltzen den konta daiteke.
  • sort metodoa zerrendako osagaiak ordenatzeko erabiltzen da. Ez du parametrorik. Ordenazio konplexuetarako aurredefinitutako sorted funtzioa erabil daiteke.
  • reverse metodoak zerrendaren osagaiak alderantzizko ordenan jartzen ditu. Ez du parametrorik.
  • index metodoak osagaien bilaketa egiten du, aurkituz gero indizea itzultzen du (0tik hasita).
  • pop metodoa erabil daiteke elementu bat zerrendatik kentzeko.

6.2. programan metodo horien erabileraren adibideak agertzen dira. Zerrenda osoa zuzenean ezin denez idatzi, edo egitura errepikakor baten bidez inprimatuko da, edo, adibidean egiten den bezala tarteak erabiliz ([:] espresioak tarte osoa adierazten du).

6.2. programa. Oinarrizko metodoak zerrendetarako:

z1 = ["bai","ez"]
z2 = [ 1, 2, 3, 5, 7, 11, 13 ]
z3 = [ -1, -3 ]
print(min(z3), max(z2))	# -3 13  Balio minimoa z3 eta maximoa z2
z1.append("zuri")	# osagaia erantsi z1-i
print(z1)		# ['bai', 'ez', 'zuri']
print(len(z1))		# 3    Osagai kopurua
print(z2)		# [1, 2, 3, 5, 7, 11, 13]
z2.extend(z3)		# z3 erantsi z2-ri. Baliokidea: z2 = z2 + z3
print(z2)		# [1, 2, 3, 5, 7, 11, 13, -1, -3]
print(len(z2))		# 9    Osagai kopurua
print(z2.count(-1))	# 1    -1 osagaia behin azaltzen da z2 listan
z2.insert(0,0)		# txertatu 0 hasieran
print(z2)		# [0, 1, 2, 3, 5, 7, 11, 13, -1, -3]
z2.sort()		# Ordenatu
print(z2[:])		# [-3, -1, 0, 1, 2, 3, 5, 7, 11, 13]
z2.reverse()		# Alderantzizko ordena
print(z2[:])		# [13, 11, 7, 5, 3, 2, 1, 0, -1, -3]
print(*z2)		# 13 11 7 5 3 2 1 0 -1 -3 (inprimatzeko beste modu bat)
print(z2.index(7))	# 2     7 osagaiaren indizea z2 listan

Emaitza hau izango da:

-3 13
['bai', 'ez', 'zuri']
3
[1, 2, 3, 5, 7, 11, 13]
[1, 2, 3, 5, 7, 11, 13, -1, -3]
9
1
[0, 1, 2, 3, 5, 7, 11, 13, -1, -3]
[-3, -1, 0, 1, 2, 3, 5, 7, 11, 13]
[13, 11, 7, 5, 3, 2, 1, 0, -1, -3]
13 11 7 5 3 2 1 0 -1 -3
2

6.1.3. Zerrenden eta karaktere-kateen arteko bihurketa[aldatu]

Kasu batzuetan komenigarria da bi mota hauen artean bihurketak egitea. Adibidez, zerrendaren elementuak inprimatzeko karaktere-kate bihur ditzakegu; bestalde zerrenden gaineko metodo edo ezaugarri batzuk aplikatzeko kateak zerrenda bihur daitezke.

Lehen helbururako join() metodoa erabiliko da objektu gisa banatzailea ze haztuz (zuriunea, koma edo karaktere hutsa adib.). Bigarrenerako, berriz, stringaren elementuak zuriuneen bidez berezituta badaude, split() metodoa erabiltzea besterik ez da egin behar zerrenda bat osatzeko. Banatzailea beste bat bada, orduan banatzailea zehaztu beharko da parametro gisa metodo horri deitzean. Adibidez datu-baseetatik inportatutako fitxategietan tabulazioa erabili ohi da banatzaile gisa, beraz, ondoko kodea erabiliko genuke eremuak zerrenda gisa eskuratzeko:

zeremuak = lerro.split('\t')


Banatzailerik ez baldin badago; alegia, karaktere bakoitza osagai bat izatea nahi badugu, orduan list() funtzio eraikitzailea erabil daiteke, katea parametro gisa pasaz.

Horrela, 4.9. programa (karaktere-kate bat irakurri teklatutik eta idatzi alderantziz) sinplifika daiteke 6.3. programan dagoen kodea erabiliz.

6.3. programa. string bat atzekoz aurrera, sinplifikatua:

katea1 = input('Sakatu karaktere-katea: ')
z = list(katea1) # katearen karaktereekin zerrenda bat osatu
z.reverse() # atzekoz aurrera jarri zerrendako osagaiak
katea2 = ''.join(z) # listako osagaiak kateatu banatzailerik gabe
print('Sarrera:', katea1)
print('Irteera:', katea2) # beste aukera bat: katea1[::-1]

Exekuzioaren adibidea:

>>>Sakatu karaktere-katea: abcdefg
Sarrera: abcdefg
Irteera: gfedcba

6.1.4. List comprehension[aldatu]

Zerrenda baten hasieraketa (edo esleipena) oso modu trinkoan egin daiteke comprehension izeneko aukeraz. Ondoko adibidean ikus daiteke nola hasieratu zerrenda balio kontsekutiboekin:

z = [ i for i in range(6) ]
print (z)

Emaitza honako hau litzateke: [0, 1, 2, 3, 4, 5] . Ikusten denez, for egitura erabiltzen da esleipenaren eskuin aldera eta ':' karakterea ez da erabiltzen. if ere aplika daiteke modu berean, horrela aurreko zerrendan balio bikoitiak bakarrik gordetzeko hau egin daiteke:

z2 = [ i for i in range(6) if(i%2==0)]
print (z2)

##[0, 2, 4]

Emaitza honako hau litzateke: [0, 2, 4].

Oso ahaltsua da ezaugarri hau eta ohituz gero kodea trinkotzeko lagungarria izango zaizu.

6.1.5. Espresio erregularrak[aldatu]

Stringekin eta zerrendekin lotuta dagoen eta oso interesgarria den klase bat aipa daiteke hemen: espresio erregularrena. Testuetan bilaketak egiteko oso tresna ahaltsuak dira espresio erregularrak. Horien erabilera bideratzeko Pythonek eskaintzen duen baliabidea re modulua da (re: regular expression-en laburpena da). Ohikoa denez, eta Unixeko grep programaren antzera, eragile anitz eskaintzen ditu: '.' (edozein karaktere), '^' hasiera, '$' bukaera, (kleene star, 0 edo gehiago), '+' (bat edo gehiago), etab. Espresio erregularrak erabiltzeko orduan match(patroia, st) prototipoa duen metodoa da oinarria. Patroia adierazteko r baten ondoan datorren string bat zehaztu behar da (Ez da derrigorrez beti *r aurrizkia jartzea, baina gomendatzen da bestelako ihes-karaktereekin gatazkarik egon ez dadin, \ sinboloarekin hasitakoekin esaterako (\n, \t...). r aurrizkiaren ordez R ere erabil daiteke.). Horrela, ondoko kodearekin:

import re
bokal_segida = r"[aeiou]+"
m1 = re.findall(bokal_segida, "egitea eta saiatzea")
m2 = re.findall(r"\(\w+\)", "(1) Udako Euskal Unib. (UEU), EH")
print(m1)
print(m2)

##['e', 'i', 'ea', 'e', 'a', 'aia', 'ea']
##['(1)', '(UEU)']


Lehen bilaketan bokal-segidak (bat edo gehiago jarraian) esleitzen zaizkio m1 zerrendari. findall metodoari bigarrenez deitzean, berriz, parentesien artean dauden hitzak bilatzen dira (\w espresioak identifikadoreetako ohiko karaktereak adierazten ditu. Horren baliokidea: [a-zA-Z0-9_]) eta m2 zerrendari esleitu. Dagokion emaitza ['(1)', '(UEU)'] izango da. Agerpen bakarra bilatu nahi bada, search metodoa erabiliko da findall ordez.

Hurrengo kapituluetan azalduko ditugu beste ezaugarri batzuk, erabili ahala. Informazio gehiagorako: https://docs.python.org/3/library/re.html.

6.1.6. Bektoreak eta matrizeak[aldatu]

Zerrenden bidez kudeatzen dira Pythonen beste lengoaietan taula, bektore, edo array izenekin definitzen diren datu-egiturak. Baina zer gertatzen da matrizeekin edo dimentsio anitzeko bektoreekin?

Matrizeak zerrenden zerrendak dira, hau da, zerrenda bat non osagaiak zerrendak diren. Osagaiak adierazteko bi indize erabiltzen dira (makoen artean).

6.4. programan matrizeen batuketa kalkulatzeko funtzioa eta deia dugu:

def mat_batu(A, B, C): # C=A*B
  for i in range(len(A)): # Aren errenkada kopurua
    for j in range(len(A[0])): # Aren zutabe kopurua
      C[i][j]=A[i][j]+B[i][j] # batuketa
X = [[1,2],[3,4],[5,6],[7,8]] # dim: 4*2
Y = [[11,12],[13,14],[15,16],[17,18]] # dim: 4*2
Z = [[0,0],[0,0],[0,0],[0,0]] # dim: 4*2
# Z = [[0]*2]*4 # hasieraketa modu trinkoan ere egin dateke
mat_batu(X,Y,Z)
print(Z)

Emaitza honako hau litzateke:

>>>
[[12, 14], [16, 18], [20, 22], [24, 26]]

Adibidean ikus daitekeenez, len funtzioa erabiltzen da errenkada zein zutabe kopuruak kalkulatzeko. Zeroz hasieratzea, berriz, nekagarria izan ez dadin * eragilea erabil daiteke. Adibidean bertan ikus daitekeenez, Z = [[0]2]4 espresioan 0 balioa, [0], 2 aldiz errepikatzen da zerrenda batean (2 elementu errenkadan), eta zerrenda hori 4 aldiz (4 errenkada) errepikatzen da matrizea osatuz.

Comprehension ezaugarria erabiliz hasieraketa ahaltsuak egin daitezke. Honako kode honen bitartez:

m = [[x, y] for x in [1,2,3,8,9] for y in [9,3,1,4] if x == y]
print (m)

bi tauletan dauden zenbakien bikoteak lortzen dira matrize batean, kasu honetarako: [[1, 1], [3, 3], [9, 9]]

Dena den, kalkulu matematiko konplexuak programatzeko asmoa izanez gero numpy hedapena erabiltzea gomendatzen da, dimentsio anitzeko bektoreen erabilera asko errazten du-eta.

6.1.7. Tuplak eta heina (range)[aldatu]

Zerrendekin batera tuplak (tuple) eta heinak (range) dira Pythoneko sekuentziak. Zerrenda motari dagozkion ezaugarri asko dituzte (funtzioak, + eta in eragileak, indizeen bitartez erabiltzeko aukera...). Pythonen nomenklaturan iterable-ak direla esaten da (stringak eta zerrendak bezala), for .. in egituran parte har dezaketelako.

Tuplak zerrenden moduan definitzen dira, baina makoen artean definitu beharrean parentesi artean definitzen dira (osagaiak komen bidez banatuta bietan). Tupletan zerrendetan ez bezala:

  • osagaiak aldaezinak dira (konstanteak)
  • ez dute metodorik onartzen (zerrenden ohiko funtzioak eta eragileak bai) • atzipen azkarragoa bideratzen dute
  • datu heterogeneoak barneratzeko pentsatuta daude.

Ondoko adibideko tuplaren balioak urteko hilen egun kopuruak dira. Balio konstanteak direnez, interesgarria izan daiteke tupla bat definitzea.

tup = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

Baina kontuz, otsailari dagokion balioa 29ra aldatu nahi badugu derrigorrezkoa da zerrenda erabiltzea, bestela tup[1]=29 esleipena egikaritzean errore bat sortuko da.

Bestalde range-ren oinarrizko erabilera 4. kapituluan azaldu da (ikus 4.5. programa): egitura errepikakorretan erabiltzea for .. in egituran. range() funtzioaren bidez range motako sekuentzia bat sortzen da, aldaezina. Parametro gisa hiru aukera daude:

  • parametro bat: balio kopurua (n bada 0 eta n-1 izango dira sekuentziaren hasierako eta bukaerako balioak)
  • bi parametro: hasierako eta bukaerako balioak
  • hiru parametro: hasiera, bukaera eta gehikuntza

Adibidez, range(2, 100, 2) 2 eta 98 arteko balio bikoitien multzoa adierazten du, biak barne.

6.1.8. Bestelakoak[aldatu]

Mota hauekin lotutako beste mota bat aipatu behar da: byte-taulak. Javaz ohikoak diren egitura hauek zerrendak balira bezala kudeatzen dira, baina osagaiak definitzean bi digitu hamaseitar (edo balio hamartar bat 0 eta 255 artean) erabili ohi dira. Adibidez, ondoko definizioa egin eta gero:

btaula = bytearray([0x01, 0x02, 0x04, 0x08])

btaula[i] bitartez osagaiak aipa daitezke eta btaula bitartez identifikadoreaz sekuentzia. bytes mota antzekoa da.

Horrez gain, memoryview klasea dugu memoriaren edukiak kudeatzeko, baina klase horren erabilera sistema eragilearekin lotua da, liburuaren esparrutik urrun samar geratzen da hori.

6.2. HIZTEGIAK[aldatu]

Hainbat lengoaiatan eta testuingurutan hash taula edo elkartze-taula izena erabiltzen den arren, Pythoneko terminologian egitura horiei hiztegi esaten zaie. Funtsean taulak edo zerrendak dira, baina osagaiak erreferentziatzeko gako bat erabiltzen da, ez zenbaki bat. Beraz, indize bat erabiliko da, makoen artean, baina indizea bilaketa gako bat izango da.

Adibide batekin hasiko gara: benetako hiztegitxo elebidun bat egiteko, euskara ingelesa hiztegi bat esaterako, Pythoneko hiztegi-egitura bat sortu nahi dugu, horrela euskarazko hitz bat emanda haren ingelesezko ordaina lortu ahal izateko. Adibidez 'bai' hitzaren ordain gisa 'yes' lortu nahi da. Hiztegiei esker Python lengoaian hori erraz lortzen da: hiztegia egitura ondo osatuta baldin badago, ondoko bi espresioetako edozeinek lortuko dute helburua:

hiztegia['bai'] # konstante bat erabilita
hiztegia[hitza_eu] # hitza_eu aldagaiaren balioa 'bai' bada

Orain falta zaiguna zera da: nola definitzen da datu-egitura hori modu egokian? Erraza da, dict() built-in funtzioa erabilita hiztegi bat sortzen da, 6.5. programan ikus daitezkeenez.

6.5. programa. Oinarrizko hiztegi baten erabilera:

hiztegia = dict() # hiztegia = {} (baliokidea)
hiztegia['bai'] = 'yes'
hiztegia['ez'] = 'no'
hitza_eu = input("Hitza euskaraz: ")
print ("Hitza ingelesez: ", hiztegia[hitza_eu])

Hiztegiak zuzenean hasiera daitezke beste bi modutan ere:

  • giltzen artean gako/balioa bikoteak zehazten dira, tartean ":" karakterea jarriz eta bikotetik bikotera pasatzeko "," banatzailea erabiliz.
  • dict() funtzio eraikitzailea deitzean (kontuz, gakoak kateak direla suposatzen da, eta kasu honetan ez da komatxorik erabili behar berauek mugatzeko).

Horrela, aurreko hiztegia hasieratzeko, ondoko bi espresioetako bat erabil daiteke (lehen hiru sententziak ordeztuz):

hiztegia = {'bai':'yes', 'ez':'no'}
print(hiztegia)
hiztegia = dict(bai='yes', ez='no')
print (hiztegia)

##>>>
##{'bai': 'yes', 'ez': 'no'}
##{'bai': 'yes', 'ez': 'no'}

Hiztegien gainean hainbat funtzio eta eragile erabil daitezke, osagai (bikote) kopurua itzultzen duen len() funtzioa adibidez. Ohikoa da for .. in egitura aplikatzea ere (iterable-ak dira), osagai guztiak inprimatzeko adibidez (6.6. programa):

6.6. programa. Hiztegia inprimatzen:

hiztegia = {'bai':'yes', 'ez':'no'}
#hiztegia = dict(bai='yes', ez='no')	#beste aukera bat

print(len(hiztegia))
for h_eu in hiztegia:
	print(h_eu, hiztegia[h_eu])

##>>>
##2
##bai yes
##ez no

6.2.1. Hiztegien gaineko metodoak[aldatu]

Aurrekoa oso ahaltsua izan arren, hainbat metodo ere erabil daitezke hiztegietan. 6.3. taulan daude erabilgarrienak.

6.3. taula. Hiztegien gaineko funtzioak eta eragileak:
PROTOTIPOA EMAITZA
clear(n) Hiztegia deuseztatzea
copy(n) Hiztegia bikoiztea
keys(n) Gakoen zerrenda
values(n) Balioen zerrenda
items(n) Bikoteen zerrenda (for zerrendetan erabiltzeko)
uodate(hizt2) Bi hiztegien bildura

Adibidez, 6.6. programaren azken zatia items metodoa erabiliz ere idatz daiteke:

for h_eu, b_eu in hiztegia.items():
    print(h_eu, b_eu)

##>>
##bai yes
##ez no

Bestalde, enumerate() built-in funtzioaren bitartez zerrenda batetik hiztegi bat lor daiteke. Gakoak zenbakizkoak izango dira. Horrela, hurrengo espresioaren bidez:

dict(enumerate(['bai','ez','zuri'],1))

Ondoko hiztegia lortzen da:

{1: 'bai', 2: 'ez', 3: 'zuri'}


Bigarren parametroa zehazten ez bada, 0tik hasiko dira gakoak.

Gainera, gakoak eta balioak zerrenda banatan badaude, zip funtzioaz biltzen dira bikotetan. Aurreko hiztegiaren hasieraketa honela ere egin daiteke:

eu=['bai','ez']
en=['yes','no']
hiztegi=dict(zip(eu,en))
print (hiztegi)

Hiztegi klasea oso erabilgarria da, baina oro har datuak fitxategietatik edo saretik kargatu beharko direnez, benetako etekina ateratzeko aukera hurrengo kapituluan izango dugu datuak kargatzeko aukerak aurkeztu ondoren.

Badaude hiztegiekin oso antz handia duten beste bi klase: set (multzoak) eta frozenset (multzo aldaezinak) klaseak. Klase bi horietan gako bidezko bilaketak ere egin daitezke, baina gakoek ez dute balio bat esleituta.

6.3. ERROREAK ETA SALBUESPENEN KUDEAKETA[aldatu]

Pythonen erroreen tratamendua salbuespenen bidez egin ohi da. Horretarako programazioan try eta except sententziak erabiliko dira, try adarrean egin beharrekoa zehazten da, eta except adarrean erroreen tratamenduari dagokion kodea da.

Adibide batekin hasiko gara berriro ere. Zenbakien arteko eragiketetan "zati zero" eragiketa salbuespena da, tratatzea komeni da. Salbuespen hori sistemak sortzen du, ZeroDivisionError izena duena. 6.7. programan tratamenduaren adibide bat ikus daiteke.

6.7a. programa. Salbuespenen tratamendua:

a = int(input("Sakatu zatikizuna: "))
b = int(input("Sakatu zatitzailea: "))
try:
	print(a/b)
except ZeroDivisionError:
	print("Errorea: zati 0")

Aurredefinitutako salbuespenak asko dira, 6.2. taulan erabilienetako batzuk agertzen dira.

6.2. taula. Ohiko salbuespenak:
KODEA ESANAHIA
Exception Orokorra, edozein salbuespen barneratzen duena
ArithmeticError Edozein salbuespen aritmetiko (zati 0, gainezkatzea...)
OSError Sistema eragilearen deiekin lotutako salbuespena, fitxategia aurkitzen ez denean adibidez
SystemError Sistemaren kernelak sortzen duen barne-errorea
TypeError Mota bateragarritasunarekin arazoak daudenean
IOError Sarrera edo irteerarako errorea. Hurrengo kapituluan sakonduko da
MemoryError Memoriaren gaineko errorea
KeyboardInterrupt Etena teklatutik (Ctrl teklen bidez sortzen dira

Taulan agertzen diren salbuespenak nahiko orokorrak direnez, eta batzuetan zehatzagoa izatea komeni denez, kode zehatzagoak ere eskaintzen ditu Pythonek:

  • Aritmetikoetarako: OverflowError (gainezkatzea), ZeroDivisionError (zati zero), FloatingPointError (koma higikorreko errorea).
  • Sistemetakoak: BrokenPipeError (arazoak pipe batean), ConnectionError (arazoak Internet edo sareko konexioan), FileNotFoundError (fitxategia ez da aurkitzen), PermissionError (arazoak baimenekin), NotADirectoryError (katalogo bat bilatu eta ez aurkitu)...

Salbuespen posibleak asko dira eta <https://docs.python.org/3/library/ exceptions.html#IndexError> gunean zehaztasunak aurki daitezke.

Salbuespenarekin batera askotan zenbait informazio gehigarri ere jasotzen da, eta horrelakoetan except adarrean as sententzia bat gehitu behar da aldagai batekin, informazio gehigarria jasoko duena. Horrela, sistemaren errore bat jaso eta inprimatzeko ondoko kodea erabil daiteke:

except OSError as akatsa:
print("Sistemaren errorea:", akatsa)

Edozein kasutan, goian aipatutakoak sistemak definitutako salbuespenak dira, baina posible da salbuespen berriak sortzea (eta komenigarria software-proiektu handietan zein gertaeretara zuzendutakoetan), erroreak mekanismo estandarraren bitartez tratatu ahal izateko. Horretarako raise sententzia erabiliko da. Adibidez, osoko negatiboen faktoriala ez dago definituta, eta 5.2. programan egiten zena baino dotoreagoa da ondoko hau

6.7b. programa. Faltorial funtzioa salbuespenekin definituta:.

# n faktoriala (3)
from funtz import faktorial
m=int(input('Sakatu zenbaki bat, faktoriala kalkulatzeko: '))
if m <= 0:
   raise NameError('FaktoNeg')
try:
   print(faktorial(m))
except NameError:
   print("Errorea")
   raise

NameError erabilita salbuespena sortzen da eta interpretatzaileak abisua emango du. Exekuzioaren adibidea:

Sakatu zenbaki bat, faktoriala kalkulatzeko: -3
Traceback (most recent call last):
 File "/home/PYTHON_UEU/code/kap6/p6-7b_Faltorial_salbuespenekin.py", line 6, in  <module>
 raise NameError('FaktoNeg')
NameError: FaktoNeg
>>>

Tratamendu berezi bat egin nahi bada, aplikazio konplexuetan ohikoa dena, kontua konplexuagoa da (kontsultatu https://docs.python.org/3/tutorial/errors.html#user-defined-exceptions).

6.4. ADIBIDEAK[aldatu]

6.4.1. 1. enuntziatua: Palindromoak detektatu[aldatu]

6.3. programan oinarrituta, egin programa bat hitz-zerrendako hitz palindromoak lortzeko. Palindromoak diren hitzetan atzekoz aurrerako irakurketa hitz berarena da.

6.8. programa. Palindromoak detektatzen:

def alderantziz(h):
	z = list(h)
	z.reverse()
	hald = ''.join(z)	# osagaiak kateatu banatzaile gabe
	return hald

hitzak = ["bai","ez","inoiz","eta","ama","aita","amama","ate"]

for hitz in hitzak:
	ztih = alderantziz(hitz)
	if ztih == hitz:
		print(hitz, ztih)

Exekuzioaren adibidea:

>>>
ama ama
amama amama

6.3. programaren kodea erabiliz funtzio bat definitu da hitz bat emanda haren karaktereak atzekoz aurrera jarrita beste hitz bat lortzeko, eta funtzio hori erabiliz kodea oso sinplea da: zerrendako hitz gutiak banan-banan tratatu, bakoitzari buelta eman eta hitz berarekin konparatu egiten da; biak berdinak badira palindromoa da.

6.4.2. 2. enuntziatua: Bokal gehieneko hitzak[aldatu]

Espresio erregularren atala kontsultatuta, egin programa bat hitz-zerrenda baten barruan bokal gehien dauka(te)n hitza(k) inprimatzeko.

6.9. programa. Bokal gehien duten hitzak:

import re

hitzak = ["bai","ez","berehalakoa","leihoetako","lehoietako","saiatzea"]
bokal = r"[aeiou]"
nmax = 0	# Kopuru maximoa metatzeko
zluze = []	# Bilatutako hitzen zerrenda

for hitz in hitzak:
	zatiak=re.findall(bokal, hitz)
	n=len(zatiak)
	if n>nmax:
		nmax = n		# Aurrekoek baino gehiago
		zluze = []		# Aurrekoek ez dute balio
		zluze.append(hitz)
	elif n==nmax:
		zluze.append(hitz)
print("Max:", nmax, zluze)

##>>>
##Max: 6 ['berehalakoa', 'leihoetako', 'lehoietako']
##>>>

Exekuioaren emaitza:

>>>
Max: 6 ['berehalakoa', 'leihoetako', 'lehoietako']

re.findall metodoarekin bokalak banan-banan lortzen dira zatiak izeneko zerrenda batean, eta len funtzioaren bidez kontatzen dira zerrendako elementuak Ariketa gisa zera proposatzen da: bokal kopurua kontatu beharrean, bokal segida luzeena kontuan hartzea.

6.4.3. 3. enuntziatua: Matrize-biderketa[aldatu]

Matrizeen batuketa egiten zuen programan oinarrituta (6.4. programa), egin matrizeen arteko biderketa kalkulatzeko programa.

6.10. programa. Matrizeen arteko biderketa:

def mat_bider(A, B):				  # Bukaeran C=A*B
   C = [[0,0,0],[0,0,0],[0,0,0],[0,0,0]] # dim: 4*3
   for i in range(len(A)): 		   # Aren errenkadak (len(A)=4)
      for j in range(len(B[0])):		# Bren zutabeak   (len(B[0])=3)
          C[i][j] = 0
          for k in range(len(B)):   	 # Bren errenkadak (len(B)=2)
              C[i][j] = C[i][j] + A[i][k]*B[k][j]	  # Kontuz, metaketa (+= eragilea)
          # print(i, j, C)
   return C
X = [[1,2],[3,4],[5,6],[7,8]]		# dim: 4*2
Y = [[0,1,2],[3,4,5]]			      # dim: 2*3
Z = mat_bider(X,Y)
print(Z)

##>>>
##[[6, 9, 12], [12, 19, 26], [18, 29, 40], [24, 39, 54]]

Emaitza: [[6, 9, 12], [12, 19, 26], [18, 29, 40], [24, 39, 54]]

Beste bertsio honek emaitza okerra ematen du baina (?):

def mat_bider(A, B):				  # Bukaeran C=A*B
   #  C = [[0,0,0],[0,0,0],[0,0,0],[0,0,0]] # dim: 4*3
   C =  [[0]*len(B[0])]*len(A)  #Honela hasieratuz gero ez dabil
   for i in range(len(A)): 		   # Aren errenkadak (len(A)=4)
      for j in range(len(B[0])):		# Bren zutabeak   (len(B[0])=3)
          C[i][j] = 0
          for k in range(len(B)):   	 # Bren errenkadak (len(B)=2)
              C[i][j] = C[i][j] + A[i][k]*B[k][j]	  # Kontuz, metaketa (+= eragilea)
          # print(i, j, C)
   return C
X = [[1,2],[3,4],[5,6],[7,8]]		# dim: 4*2
Y = [[0,1,2],[3,4,5]]			      # dim: 2*3
Z = mat_bider(X,Y)
print(Z)


##>>>
##[[24, 39, 54], [24, 39, 54], [24, 39, 54], [24, 39, 54]]
##

6.4.4. 4. enuntziatua: Hitza atzekoz aurrera jarrita ere badago listan[aldatu]

Hiztegi bat erabiliz aldatu 6.8. programa, mota honetako hitzak ere lortzeko: hitza dago listan eta atzekoz aurrera jarrita lortzen den hitza ere bai. Adibidez, ate hitzari buelta emanda eta lortzen da, eta biak daude zerrendan.

6.11. programan hiztegi bat erabiltzen da jakiteko hitz bat erabiltzen den (bat balioa esleitzen da kasu horretan) edo ez. Ideia hau zabal daiteke hitzen maiztasuna kalkulatzeko, ikusi geroago proposatuko diren ariketak.

6.11. programa. Hitza eta bere alderantzizkoa zerrendan. Hiztegi bidez:

def atzekoz_aurrera(h):
	z = list(h)
	z.reverse()
	hald = ''.join(z)	# osagaiak kateatu banatzaile gabe
	return hald

hitzak = ["bai","ez","noiz","eta","ama","zion","amama","ate"]

hiztegi = dict()

for hitz in hitzak:
	hiztegi[hitz]=1		# hitza dagoela adierazteko

for hitz in hitzak:
	ztih = atzekoz_aurrera(hitz)
	try:
		if hiztegi[ztih]==1:
			print(hitz, ztih)
	except:
		None

Errorea tratatu da, hiztegian ez dagoen hitz bat kontsultatzean errorea gertatzen baita. Hori saihestu daiteke 6.11b. programan erabili den defaultdict funtzioa erabiliz hiztegia definitzeko.

def atzekoz_aurrera(h):
	z = list(h)
	z.reverse()
	hald = ''.join(z)	# osagaiak kateatu banatzaile gabe
	return hald

hitzak = ["bai","ez","noiz","eta","ama","zion","amama","ate"]

from collections import defaultdict
hiztegi = defaultdict(lambda : None)

#hiztegi = dict()

for hitz in hitzak:
	hiztegi[hitz]=1		# hitza dagoela adierazteko

for hitz in hitzak:
	ztih = atzekoz_aurrera(hitz)
	if hiztegi[ztih]==1:
		print(hitz, ztih)

Egia esan, hiztegirik erabili gabe eta listaren gainean in eragilea erabilita, kodea askoz sinpleagoa izan zitekeen (6.11c. programa):

Add blockquote

def atzekoz_aurrera(h):
	z = list(h)
	z.reverse()
	hald = ''.join(z)	# osagaiak kateatu banatzaile gabe
	return hald

hitzak = ["bai","ez","noiz","eta","ama","zion","amama","ate"]

for hitz in hitzak:
	ztih = atzekoz_aurrera(hitz)
	if ztih in hitzak:
		print(hitz, ztih)

6.5. PROPOSATUTAKO ARIKETAK[aldatu]

  • 10 zenbaki dituen zerrenda bat osatu teklatutik irakurriz, gero ordenatu eta alderantzizko ordenan inprimatu.
  • Espresio erregularrak erabiliz, egin programa bat testu bateko bokal-segidarik luzeena bilatzeko.
  • Osatu hiztegi bat hilen euskarazko izenekin eta haien egun kopuruarekin. Gero, egin funtzio bat hau lortzeko: hil baten izena eta eguna emanda, urteko zein eguna den (1-366 arteko balioa) itzuli beharko du. Hainbat proba egin ondo dabilela ziurtatzeko.
  • Hiztegi bat erabiliz, kalkulatu zerrenda batean dauden hitzen maiztasuna. Adibidez, zerrenda honako hau bada: ["da","du","dute","da","dute","dira","da","d a","dute"] orduan irteerak honako hau izan beharko du: "da":4; "dute":3; "du":1; "dira":1.
  • Hiztegi bat erabiliz, egin programa bat kontatzeko zenbat aldiz agertzen den karaktere bakoitza string batean. Adibidez, "lengoaia" katean emaitzak hau izan behar du: a:2, e:1, g:1, i:1, l:1, n:1, o:1.