Axlor Elorza Eizagirre
Python programazio hizkuntza interpretatua 90. hamarkada hasieran sortu zen GUIDO VAN ROSSUM-en eskutik. Python-ek maila altuko datu estrukturak eta objetuei zuzenduriko programazioarekiko soluzio simple eta eraginkorrak ditu, honela script-ak eta aplikazioen garapen azkarrerako hizkuntza egokia delarik.
Python-ek aginduen lerroak (shell) baino laguntza eta azpiegitura gehiago eskaintzen ditu. Bestalde C-k baino errore egiaztapen gehiago du eta, maila altuko hizkuntza izatean, matrize malgu edota hiztegien moduko maila altuko datu motak barneratzen ditu. Erraza delarik funtzio berri eta C edo C++-n landuriko datu motak erabiliz Python interpretea hedatzea eragiketa kritikoak abiadura handienean burutzeko edo Python programak modu bitarrean dauden liburutegiekin lotzeko. Honela Python interpretea C-n idatziriko aplikazio bati lotu daiteke eta aplikazio honentzat makroen hizkuntza moduan erabili.
Python-en programak C edo C++-en baino motzagoak dira, honako arrazoiak direla medio:
Datu mota ezberdinekin frogak egiteko interpretea erabiltzea gomendatzen da. Interpretea abiaraztean gonbit nagusia ``>>>'' ageri arte itxaron (ez luke asko tardatu behar).
Sarrerak gonbit edo indikatzaileak (``>>>'' eta ``...'') ageri direnean emango dira, gonbitik ageri ez den lerroetan interpretearen irteera emango delarik. Adibide askotan iruzkinak azalduko dira, beti ere ``#'' karaktereaz hasiko dira, lerroearen amaieraraino luzatuko direlarik. Iruzkinak lerro haseran edo kodearen atzetik joango dira eta ez konstante literal baten barruan. Kate baten barruko traol (#) hutsa da, besterik gabe.
Interpreteak kalkulagailu xume bat bezala jokatuko du: adierazpena idatzi eta berak emaitza erakutsiko du: +, -, * eta / operadoreak beste hizkuntzetan bezala jokatzen dute. Parentesiak erabili daitezke operazioak taldekatzeko.
Zenbakiak adierazteko modu ezberdinak:
0x003f # sistema hamartarraz gain, besteen erabilera
0776 # aurretik 0 bat izanda ere berdin da
10L # long
2134865345657L # long
0.5 # erreala
5e10 # exponentziala
1.5+0.3j # zenbaki konplexuak
Kateak adierazteko modu ezberdinak:
'elurra ari du'
>>> 'L\'Hospitalet'
"L'Hospitalet"
>>> "L'Hospitalet"
"L'Hospitalet"
>>> '"Bai," esan zuen.'
'"Bai," esan zuen.'
>>> "\"Bai,\" esan zuen."
'"Bai," esan zuen.'
>>> '"L\'Hospitalet," esan zuen.'
'"L\'Hospitalet," esan zuen.'
testua da, C izango balitz bezala.\n\
Ohar zaitez lerro haserako zuriunea\
esanguratsua dela.\n"
print kaixo
testua da, C izango balitz bezala.
Ohar zaitez lerro haserako zuriunea esanguratsua dela.
-h Erabilera mezua erakutsi
-H ZerbitzariIzena Konektatu beharreko zerbitzariaren izena
"""
-h Erabilera mezua erakutsi
-H ZerbitzariIzena Konektatu beharreko zerbitzariaren izena
>>> hitza 'LaguntzaZ'
>>> '<' + hitza*4 + '>'
'<LaguntzaZLaguntzaZLaguntzaZLaguntzaZ>'
>>> import string
>>> string.strip('kat') + 'ea' # <- Honek balio du 'katea'
>>> string.strip('kat') 'ea' # <- Honek ez du balio
File "<stdin>", line 1
string.strip('kat') 'ea'
^
SyntaxError: invalid syntax
'n'
>>> hitza[:2] # Lehen bi karaktereak
'La'
>>> hitza[2:] # Lehen biak ezik beste guztiak
'guntzaZ'
'LaguntzaZ'
>>> hitza[2:4] # Lehen 4 karakteretatik lehen biak ez besteak
'gu'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn't support item assignment
'XaguntzaZ'
'z'
>>> hitza[-3:] # Azken hiru karaktereak
'zaZ'
>>> hitza[:-3] # Azken hiru karaktereak ez beste guztiak
'Lagunt'
>>> hitza[-100:]
'LaguntzaZ'
>>> hitza[-10]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
IndexError: string index out of range
9
Python-ek datu mota konposatu ezberdinak erabiltzen ditu, beste balio batzuk taldekatzeko. Joko gehiena eskaintzen dutenak zerrendak dira, kortxete artean komaz bananduz idatziko dira balio edo elementuak. Zerrendako elementu guztiek ez dute zertan mota berdinekoak izan behar.
>>> a
['arkatza', 100.90000000000001, 1234]
'arkatza'
>>> a[3]
1234
>>> a[-2]
100.90000000000001
>>> a[1:-1]
100.90000000000001
>>> a[:2] + ['elurra', 2*2]
['arkatza', 100.90000000000001, 'elurra', 4]
>>> 3*a[:3] + ['Eurre!']
['arkatza', 100.90000000000001, 1234, 'arkatza', 100.90000000000001,
1234, 'arkatza', 100.90000000000001, 1234, 'Eurre!']
['arkatza', 100.9, 1234]
>>> a[3] = a[3] + 23
>>> a
['arkatza', 100.90000000000001, 1257]
... a[0:2] = [1, 12]
>>> a
[1, 12, 1234]
>>> # Elementuak kendu:
... a[0:2] = []
>>> a
[1234]
>>> # Elementuak gehitu:
... a[1:1] = ['ZimZum', 'Duran']
>>> a
[1234, 'ZimZum', 'Duran']
>>> a[:0] = a # Kopia bat sartu bere haseran
>>> a
[1234, 'ZimZum', 'Duran', 1234, 'ZimZum', 'Duran']
6
>>> p = [1, q, 4]
>>> len(p)
3
>>> p[1]
[2, 3]
>>> p[1][0]
2
>>> p[1].append('xtra') # Consulte la sección 5.1
>>> p
[1, [2, 3, 'xtra'], 4]
>>> q
[2, 3, 'xtra']
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[5, 6, 7, 8, 9]
>>> range(0, 10, 3)
[0, 3, 6, 9]
>>> range(-10, -100, -30)
[-10, -40, -70]
>>> for i in range(len(a)):
... print i, a[i]
...
0 Cure
1 for
2 pain
>>> pila.append(6)
>>> pila.append(7)
>>> pila
[3, 4, 5, 6, 7]
>>> pila.pop() 7
>>> pila [3, 4, 5, 6]
>>> pila.pop()
6
>>> pila.pop()
5
>>> pila
[3, 4]
>>> cola.append("Buzz")
>>> cola.append("Dunn")
>>> cola.pop(0)
'Patton'
>>> cola.pop(0)
'Fantomas'
>>> cola
['Lonbardo', 'Buzz', 'Dunn']
Zerrendekin lan egiteko hiru funtzio baliagarri ditugu: filter(), map() eta reduce().
...
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]
...
>>> map(kubo, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
...
>>> reduce(batura, range(1, 11))
55
Hirugarren argumentu bat pasa geniezaiokegu haserako balioa zehazteko. Kasu honetan balio hau itzuliko luke zerrenda hutsik balego eta funtzioa lehen elementuari aplikatuko zaio, gero bigarrenari eta horrela hurrenez hurren. Adibidez:
... def batu(x,y): return x+y
... return reduce(batu, sekuentzia, 0)
...
>>> batu(range(1, 11))
55
>>> batu([])
0
LC-ek map(), filter() edota lambda funtzioak erabili gabe zerrendak sortzeko modu zehatza dira. LC-en egitura adierazpen bat, for sententzia bat eta for edo if (zero edo gehiago) adierazpenez eratuak daude. Emaitza izango den zerrenda adierazpenaren ondoren datozen for eta if sententzietan adierazpena ebaluatu ondoren lortuko da. Adierazpenak emaitz bezala tupla bat itzuli behar badu parentesi artean itxi beharko da.
>>> [arma.strip() for arma in fruitufreskoa]
[' platano', ' sagarra ', 'marrubia ']
>>> bec = [2, 4, 6]
>>> [3*x for x in bec]
[6, 12, 18]
>>> [3*x for x in bec if x > 3]
[12, 18]
>>> [3*x for x in bec if x < 2]
[]
>>> [{x: x**2} for x in bec]
[{2: 4}, {4: 16}, {6: 36}]
>>> [[x,x**2] for x in bec]
[[2, 4], [4, 16], [6, 36]]
>>> [x, x**2 for x in bec] # error - tupletan parentesia behar da
File "<stdin>", line 1
[x, x**2 for x in bec]
^
SyntaxError: invalid syntax
>>> [(x, x**2) for x in bec]
[(2, 4), (4, 16), (6, 36)]
>>> bec1 = [2, 4, 6]
>>> bec2 = [4, 3, -9]
>>> [x*y for x in bec1 for y in bec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]
>>> [x+y for x in bec1 for y in bec2]
[6, 5, -7, 8, 7, -5, 10, 9, -3]
Indizea edo mozketa pasata elementuak zerrendatik ezabatzeko balio du, baita aldagai osoa ezabatzeko ere. Adibidez:
>>> del a[0]
>>> a
[1, 66.6, 333, 333, 1234.5]
>>> del a[2:4]
>>> a
[1, 66.6, 1234.5]
>>> del a
Zerrenda eta kateak bezala tuplak ere datu mota sekuentzialak dira. Tuplek zenbait balio komaz bananduak izaten dituzte:
>>> t[0]
12345
>>> t
(12345, 54321, 'Rosemary')
>>> # Tuplak habitzea posible da:
... u = t, (1, 2, 3, 4, 5)
>>> u
((12345, 54321, 'Rosemary'), (1, 2, 3, 4, 5))
Elementu bakarreko edo elementurik gabeko tuplak adierazteko parentesi hutsak eta elementu bakarraren ondoren koma bat gehituz lortuko da.
>>> vendetta = 'charade', # <- Begiratu amaierako koma
>>> len(hutsa)
0
>>> len(vendetta)
1
>>> vendetta
('charade',)
Hiztegiak Python-eko barne-datu mota erabilgarriak dira. Sekuentziekin alderatuz, zenbakiez indexatu beharrean gakoak erabiliz indexatuko dira, edozein mota aldaezinekoak izango direlarik, zenbaki eta kateak bezala. Tupla gako bezala erabiltzeko baldintza tupla, kate edo zenbakiez bakarrik eratzea da. Tupla batek zuzenean edo zeharka objetu aldakor bat badu ezingo da gako bezala erabili. Listak ezingo dira gako bezala erabil append() edo extend() metodoak erabiliz aldatzeko gaitasuna baitute, mozketa asignazio eta asignazio aniztuez gain.
Egokiena hiztegiak ordenarik gabeko gakoa : balioa bikoteen talde bezala hartzea da, gakoak hiztegi barruan bakarrak izango diren baldintzarekin. {} giltz pareak hiztegi huts bat adierazten du eta gakoa : balioa pare bat sartuz gero gakoa : balioa pare haseratuak sartzen dira hiztegian.
Hiztegien eragiketa nagusiak bertan gako bat erabiliz balio bat gorde eta gako bat emanik balioak ateratzea dira. Hauez gain del erabiliz gakoa : balioa bikote bat ezabatu daiteke. Iada hiztegian dagoen gako bat sartuz gero lehendik dagoen balioa ezabatu egingo du. Existitzen ez den gako bat ateratzen saiatzeak errorea emango du.
Objetu baten keys() metodoak hiztegiaren gako guztiak itzuliko dizkigu ausazko ordena batean (ordenaturik nahi badira sort() metodoa aplikatu beharko zaio gako zerrendari).
Gako bat hiztegian ba al dagoen jakiteko hiztegiaren has_key() metodoa erabili behar da.
Hona hemen hiztegi bat erabiltzen duen adibide bat:
>>> tel['alex'] = 4127
>>> tel
{'alex': 4127, 'mikel': 4098, 'xabier': 4139}
>>> tel['mikel']
4098
>>> del tel['xabier']
>>> tel['axlor'] = 4127
>>> tel
{'alex': 4127, 'mikel': 4098, 'axlor': 4127}
>>> tel.keys()
['alex', 'mikel', 'axlor']
>>> tel.has_key('axlor')
true
Nahi adina elif eta else izan ditzake, aukerakoa delarik hauen erabilera. if ... elif ... elif... sekuentziak beste hizkuntza batzuetako switch edo case bezala jokatzen du.
elif baldintza2: sententzia2
...
else: sententziaN
>>> if x < 0:
... x = 0
... print 'Zenbaki negatiboa zerora bihurtu da.'
... elif x == 0:
... print 'Zero'
... elif x == 1:
... print 'Bat'
... else:
... print 'Gehiago'
...
sententzia
... # Aurreko bi zenbakiren baturak emango digu hurrengoaren balioa
... a, b= 0, 1
>>> while b < 10:
... print b,
... a, b = b, a+b
...
1 1 2 3 5 8
for sententziak C edo Pascal-ekiko ezberdintasun bat du. Progresio arimetiko bateko elementu denak banan bana pasa beharrean edo programatzaileari inizializazio, egiaztapen eta urrats-jauzia aukeratzeko askatasuna utzi beharrean, Python-en sekuentzia baten (zerrenda edo kate bat, adibidez) elementu guztiak banan bana pasako ditu, sekuentzian azaltzen diren ordenean.
... sententzia
... a = ['katu', 'lehioa', 'hitzluzeagoa']
>>> for x in a:
... print x, len(x)
...
katu 4 lehioa 6 hitzluzeagoa 12
zerrenda[:]
... if len(x) > 7: a.insert(0, x)
...
>>> a
['hitzluzeagoa', 'katu', 'lehioa', 'hitzluzeagoa']
break sententziak, C-n bezala, aribidean dagoen barrueneko for edo while bukletik irteera bultzatuko du.
continue sententziak buklearen hurrengo errepikapenean jarraitzera behartzen du.
Bukleko eraketek else klausula izan dezakete. Hau, buklean izanez gero, bukletik irtetean baldintza gezurrezkoa delako (while-en) edo zerrenda amaierara iritsi denean (for-en) exekutatuko da, baina ez break sententziarekin amaitu bada.
Lehenago deskribaturiko for eta while eraketetan erabilitako baldintzek konparazioez gain beste baldintza mota batzuk erabili ditzakete.
in eta not in konparazio operadoreek balio bat sekuentzi baten barrun ba al dagoen begiratzen dute. is eta is not bi objetu benetan bera al diren begiratzen dute. Hauek listak bezalako objetu aldakorretan bakarrik dute garrantzia. Konparazio operadore guztiek lehentasun bera dute, zenbakizko operadoreena baino baxuagoa.
Konparazioak elkartu daitezke: Adibidez, a < b == d, a b baino txikiagoa al den eta b eta d berdinak al diren egiaztatzen du.
and eta or operadore logikoak erabiliz ere egin daitezke konparazioak, not-ek emaitza ezeztatuko lukeelarik. Konparazio operadoreek baino lehentasun baxuagoa dute. Beraien artean lehentasuna not-ek izango du, baxuenak or-ek izango lukeelarik, ondorioz A and not B or C ,(A and (not B)) or C-ren berdina da. Emaitza ezkerretik eskubira ebaluatuko da eta emaitza zehaztu orduko ebaluazioa moztu egingo da. Adibidez, A egia da eta B gezurra, ondorioz A and B and D-k ez du ebaluatuko D adierazpena. Orokorrean, lasterbide deituriko operadore hauek itzuliko duten balioa, balio orokor bezala erabiltzean eta ez balio logiko bezala, ebaluaturiko azken argumentua izango da:
>>> non_null = str1 or str2 or str3
>>> non_null
'Norbegia'
Sekuentzia objetuak mota berdineko sekuentziez alderatu daitezke, ordenazio lexikografikoa erabiliko delarik.: Lehenendabizi lehen bi elementuak konparatuko ditu, ezberdinak badira emaitza hauek emango digute, eta berdinak badira hurrenez hurren sekuentzia bakoitzeko elementuak alderatzen joango da, sekuentzietako bat amaitu arte. Elementuetako bat sekuentzia bat bada, konparazio lexikografiko habitu bat emango da. Konparazio lexikografikoa egiteko ASCII kodearen ordena erabiliko da. Hona hemen mota berdineko sekuentzien arteko alderapen batzuk:
[1, 2, 3] < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4) < (1, 2, 4)
(1, 2) < (1, 2, -1)
(1, 2, 3) == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4)
Honako adibide honek telefono zenbakiak gordeko ditu hiztegi batetan:
# Zenbakiak.py fitxategiaren hasera
#
def menua():
print '1. Telefono zenbakiak erakutsi'
print '2. Zenbaki berri bat sartu'
print '3. Zenbaki bat ezabatu'
print '4. Zenbaki bat bilatu'
print '5. Irten'
zenbakiak = {}
aukera = 0
menua()
while aukera != 5:
aukera = input("Sartu aukera (1-5):")
if aukera == 1:
print "Zenbaki telefonikoak: "
for x in zenbakiak.keys():
print "Izena: ",x," \tZenbakia: ",zenbakiak[x]
elif aukera == 2:
print "Sartu izena eta zenbakia"
izena = raw_input("Izena: ")
telefonoa = raw_input("Zenbakia: ")
zenbakiak[izena] = telefonoa
elif aukera == 3:
print "Ezabatu izena eta zenbakia"
izena = raw_input("Izena: ")
if zenbakiak.has_key(izena):
del zenbakiak[izena]
else:
print "Ezin izan da ", nombre, " aurkitu"
elif aukera == 4:
print "Zenbakia bilatu"
izena = raw_input("Nombre:")
if zenbakiak.has_key(izena):
print "Zenbakia: ",zenbakiak[izena]
else:
print "No pude encontrar a ",izena
elif aukera != 5:
menua()
# Zenbakiak fitxategiaren amaiera
Adibidea:
... ``n-rainoko Fibonacci seriea idatzi``
... a, b = 0, 1
... while b < n:
... print b,
... a, b = b, a+b
...
>>> # Orain funtzio definitu berriari deituko diogu:
... fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
Funtzio baten exekuzioak Python-en aldagai lokalentzat sinbolo-taula berri bat sortzen du. Zehazki, funtzio baten aldagaien asignazio guztiek balioa sinbolo-taula lokalean gordetzen dute; honela, aldagaien erreferentziek lehenengo sinbolo-taula lokalean begiratuko dute, gero sinbolo-taula orokorrean eta, azkenik, barneko izen-taulan. Arrazoi honexegatik ezin izango diogu aldagai orokor bati baliorik ezarri funtzio baten barruan (global sententzi batean aipatzen ez bada behintzat), nahiz eta beraiei erreferentzia egin daitekeen.
Funtzio bati argumentuak balioz pasatuko zaizkio, balioa beti objeturi erreferentzia bat izango delarik eta ez objetuaren balioa.
Funtzioaren definizioak funtzioaren izena indarrean dagoen sinbolo-taulan gordeko du, izenaren balioa interpreteak onarturiko mota izango du erabiltzaileak definituriko funtzio bezala. Honela berizendapen-generiko bezala balio duelarik:
<function fib at 0x403f6bc4>
>>> f = fib
>>> f (50)
1 1 2 3 5 8 13 21 34
None
... ``n-rainoko Fibonacci seriea itzuli``
... a, b = 0, 1
... emaitza = []
... while b < n:
... emaitza.append(b) # Edo: emaitza = emaitza + [b]
... a, b = b, a+b
... return emaitza
...
>>> f10 = fib2(10) # funtzioari deitu
>>> f10 # emaitza idatzi
[1, 1, 2, 3, 5, 8]
Modurik errazena da argumentu bat edo gehiagori balio lehenetsiak zehazteko. Honela dituena baino argumentu gutxiagorekin deitu dezakegun funtzioa sortu dezakegu:
while 1:
erantzuna = raw_input(adierazlea)
if erantzuna in ('b', 'bai'): return 1
if erantzuna in ('e', 'ez'): return 0
ahaleginak = ahaleginak - 1
if ahaleginak < 0: raise IOError, 'Erabiltzailea ukatua'
print kexua
Balio lehenetsiak funtzioa defintzean ebaluatuko dira:
def f(arg = i): print arg
i = 6
f()
Kontuz! Argumentu lehenetsiak behin bakarrik ebaluatzen dira. Emaitza ezberdinak lortuko ditugu balio lehenetsiak zerrenda edo hiztegien moduko balio aldakorrak direnean. Adibidez:
l.append(a)
return l
print f(1)
print f(2)
print f(3)
[1, 2]
[1, 2, 3]
if l is None:
l = []
l.append(a)
return l
"gakoa = balioa" modua erabiliz ere deitu diezaiokegu funtzioari. Adibidez:
print "- Txori honek ezingo luke ", ekintza,
print tentsioa, " boltio jasanaraziz ere."
print "- Lumatza ederra ", mota,"rena."
print "- ", egoera, " dago!"
txoria(ekintza = "DANBA!", tentsioa = 1000)
txoria('bi mila', egoera = 'antzarrak perratzen')
txoria('milioika', 'hilda', 'salto egin')
txoria(tentsioa=5.0, 'hilda') # Gako argumentua argumentu ez-gakoaren
# ondoren
txoria(110, tentsioa=220) # Argumentuaren balioa bikoiztua
txoria(hegokopurua='bat') # Gako ezezaguna
... pass
...
>>> funtzioa(0, a=0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: funtzioa() got multiple values for keyword argument 'a'
print "- Ba al duzu", mota, "-ik?"
print "- Barkatu, ez dugu", mota, "-ik"
for arg in argumentuak: print arg
print '-'*30
for kw in gakoak.keys(): print kw, ':', gakoak[kw]
"Zuk hala nahi izanez gero", bezeroa='dooteo',
dendaria='axlor')
- Barkatu, ez dugu duff -ik
Samielak ditugu, jauna.
Zuk hala nahi izanez gero
---------------
bezeroa : dooteo
dendaria : axlor
Azkenik, gutxien erabiltzen den aukera funtzio bati zehaztugabeko argumentu kopuru batekin deitu diezaiokegunekoa da. Argumentu hauek tupla batean bilduko dira. Zehaztugabeko argumentu kopuruaren aurretik argumentu arruntak izan ditzake, bat ere ez edo nahi adina.
file.write(formatua % args)
Erabiltzaileen beharren arabera, Python-en Lisp programazio hizkuntza funtzionaletako ezaugarri batzuk gehitu dira. lambda hitza erabiliz funtzio ezezagun txikiak gehitu daitezke. Funtzio honek bere bi argumentuen batura itzuliko digu: lambda a, b: a+b. Lambda egiturak funtzio objetu bat behar direnean bakoitzean erabil daitezke. Sintaktikoki adierazpide simple batetara mugaturik daude. Funtzio habiaratuak (anidadas) bezala lambda egiturek ezin dute dituen esparruko aldagaiei erreferentziarik egin, nahiz eta hori, lehenetsiriko argumentuen balioak erabiliz konpondu daitekeen, adibidez:
return lambda x, gehi=n: x+gehi
Nahiz eta ez den derrigorrezkoa, komenigarria da funtzioen lehen hilaran funtzioaren zeregina azalduko digun esaldi labur bat sartzea Maiuskulaz hasiz eta '.' puntuz amaituz. Funtzio baten dokumentazio katea ikusteko:
Dokumentazio katea.
Python interpretetik irten eta berriz sartzean, lehenxeago eginiko definizioak (funtzio eta aldagaiak) galdu egin direla ohartuko zara. Horregatik, programa luzeago bat idatzi nahi bada, hobe izango da testu editore batetan prestatzea interpreterako sarrera eta fitxategi horrekin sarrera moduan exekutatzea. Honi gidoi bat sortzea deitzen zaio. Gehitzen doazen einean fitxategi gehiagotan banatzea komeniko da hauen mantenimendua errazteko.
Honetarako, Python-ek badu definizioak fitxategi batetan utzi eta gidoi batetan edo interpretearen ekinaldi interaktibo batetan erabiltzeko modu bat. Fitxero hori modulua deitzen da; modulu baten funtzioak beste modulu batzuetara edo modulu nagusira (goragoko mailatik eta kalkulagailu moduan exekutatutako gidoi batetik sarbidedun den aldagai bilduma) inportatu daitezke.
Modulu bat Python sententziak eta definizioak dituen fitxategi bat da. Fitxategiaren izena moduluarena izango da .py atzizkiarekin. Modulu baten barruan, moduluaren izena (kate bezala) __name__ aldagai orokorrak emango digu. Adibidez, erabili gustokoen duzun testu editorea fibo.py izeneko fitxategi bat sortzeko uneko direktorioan, hurrengo edukinarekin:
def fib(n): # n-rainoko Fibonacci seriea idatzi
a, b = 0, 1
while b < n:
print b,
a, b = b, a+b
def fib2(n): # n-rainoko Fibonacci seriea itzuli
emaitza = []
a, b = 0, 1
while b < n:
emaitza.append(b)
a, b = b, a+b
return emaitza
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Modulu batek funtzioen definizioez gain, modulua haseratzeko balio duten sententziak izan ditzake. Hauek inportatzen diren lehenengo aldian bakarrik exekutatuko dira.
Modulu bakoitzak bere sinbolo-taula du, moduluan definituriko funtzio guztiek sinbolo-taula orokor bezala erabiliko dutelarik. Ondorioz, modulu baten egileak moduluaren barnean aldagai orokorrak erabili ditzake moduluaren erabiltzaile baten aldagai orokorrekin izan ditzakeen arazoekin kezkatu gabe. Bestalde, modulu baten aldagai orokorrak aldatzeko modIzena.elemIzena erabil genezake.
Moduluek beste modulu batzuk inportatu ditzakete. Ez da derrigorrezko ohitura import sententzia guztiak modulu (edo gidoiaren) haseran jartzea. Inportaturiko moduluaren izenak inportatzen duen modulu orokorraren sinbolo-taula orokorrean kokatzen dira.
Bada import sententziaren bariazio bat, non modulu baten izenak inportatzen duen moduluaren sinbolo taulara zuzenean inportatzen diren:
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
Gainera badago modulu batek definituriko izen guztiak inportatzen dituen aldakuntza bat:
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
dir() barne-funtzioak modulo batek zein izen zehazten dituen jakiteko erabiltzen da. Kate zerrenda ordenatu bat itzultzen du:
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__name__', 'argv', 'builtin_module_names', 'copyright', 'exit',
'maxint', 'modules', 'path', 'ps1', 'ps2', 'setprofile',
'settrace', 'stderr', 'stdin', 'stdout', 'version']
>>> import fibo, sys
>>> fib = fibo.fib
>>> dir()
['__name__', 'a', 'fib', 'fibo', 'sys']
dir()-ek funtzio eta barne-aldagaien izenik ez du itzuliko. Izen hoiek lortzea nahi bada, __builtin__ modulu estandarrean daude zehaztuta:
>>> dir(__builtin__)
['AccessError', 'AttributeError', 'ConflictError', 'EOFError',
'IOError', 'ImportError', 'IndexError', 'KeyError',
'KeyboardInterrupt', 'MemoryError', 'NameError', 'None',
'OverflowError', 'RuntimeError','SyntaxError',
'SystemError', 'SystemExit', 'TypeError', 'ValueError',
'ZeroDivisionError', '__name__', 'abs', 'apply', 'chr',
'cmp', 'coerce', 'compile', 'dir', 'divmod', 'eval',
'execfile', 'filter', 'float', 'getattr', 'hasattr',
'hash', 'hex', 'id', 'input', 'int', 'len', 'long',
'map', 'max', 'min', 'oct', 'open', 'ord', 'pow', 'range',
'raw_input', 'reduce', 'reload', 'repr', 'round',
'setattr', 'str', 'type', 'xrange']
Paketeak Python-eko moduluen izendatze-formak egituratzeko bidea dira, "modulu izenak puntuaz" erabiliz. Adibidez A.B moduluaren izenak "A" izeneko modulu baten "B" izeneko azpimodulu bati egiten dio erreferentzia.
Adibide bezala, soinu fitxategi eta soinu datuak lantzeko modulu talde bat (paketea) diseinatzea nahi da. Soinu fitxategi mota ezberdinak daude (luzapenaz bereiztua, .wab, .aiff edo .au) eta ondorioz formatu ezberdinen artean bihurketa moduluen taldea sortu eta mantendu beharko genuke. Soinu datuen gain eragiketa ezberdinak daude (nahastu, ohiartzuna gehitu, ekualizatu edo efektuak sartu), eragiketa hauek burutzeko hainbat modulu idazten ari garelarik. Hona hemen paketearen egituraketa posible bat:
__init__.py Soinuen pakatea inizializatu
Formatuak/ Fitxategien formatuen eragiketen
azpipaketea
__init__.py
irakurwav.py
idatziwav.py
irakuraiff.py
idatziaiff.py
irakurau.py
idatziau.py
...
Efektuak/ Soinu efektuen azpipaketea
__init__.py
ohiartzuna.py
surround.py
alderantzizkatu.py
...
Filtroak/ Filtroen azpipaketea
__init__.py
ekualizadorea.py
vocoder.py
karaoke.py
...
Paketearen erabiltzaileek paketearen modulu bakanak inportatu ditzakete:
atzerapena=0.3, aten=5)
import elementua.azpielementua.azpiazpielementua sintaxia erabiltzean, elementu bakoitza, azkena ez ezik, paketea izango da. Azken elementua paketea edo modulua izan daiteke baina ez goiko mailan zehazturiko funtzio, klase edo aldagaia.
Eragiketa hau Windows-en ez da oso zuzen ibiltzen fitxategien sistemak ez baitu fitxategien miuskulataz ideia zehatzik. OHIARTZUNA.PY fitxategia ezin dugu jakin ohiartzuna, Ohiartzuna edo OHIARTZUNA bezala inportatuko duen. DOS-en berriz izen luzedun moduluentzat arazoa da 8 hizkitik ezin baita pasatu. Berez, from Soinua.Efektuak import * landuz paketean dauden azpimodulu denak aurkitu eta denak inportatu beharko lituzke.
Hau konpontzeko paketearen egileak paketeari ezaugarri esplizitu bat ezartzea da. Import sententziak honako ohitura du: pakete baten __init__.py-ren kodeak __all__ izeneko zerrenda bat zehazten badu, from paketea import * aurkitzean inportatu beharreko moduluen izen zerrenda izango da. Paketearen bertsio berri bat kaleratzean egilearen esku dago zerrrenda hori eguneratzea. Adibidez Soinua/Efektuak/__init__.py fitxategiak hurrengo kodea izan lezake:
import Soinua.Efektuak.surround
from Soinua.Efektuak import *
Programa baten irteerak erakusteko modu ezberdinak daude; gizakiek ulertzeko moduan datuak inprimatu edo geroago erabiltzeko fitxategi batean idatzi daitezke. Kapitulu honetan aukera batzuk ikusiko ditugu.
Orain arte bi modu ezberdin erabili ditugu balioak idazteko: expresio sententziak eta print sententzia. Hirugarren modu bat ere badago: fitxategi objetuen write() metodoa, sys.stdout-i esker da zilegi.
Irteerei formatua emateko bi modu daude: lehenengoan norberak eratu beharko ditu kateak, mozketa eta elkarketak erabilz. string modulu estandarrak baditu kateak zutabe zabalera jakin batzuetara egokitzeko eragiketak. Bigarrengo modua % operadorea ezker argumentu bezala kate batekin erabiltzea litzateke. % operadoreak ezker argumentua C-ko sprintf() formatu estiloko kate bat bezala azalduko du eta eskuin argumentuari aplikatu beharko zaio formatuaren emaitz katea itzultzeko.
Python-ek balioak kateetara itzultzeko repr() funtzioa du, edo komatxo simple alderantzizkatu artean idatziz balioa. Adibide batzuk:
>>> y = 200*200
>>> s = '"x"-en balioa: ' + `x` + ' eta "y"-rena ' + `y` + '...'
>>> print s
"x"-en balioa: 31.4 eta "y"-rena 40000...
>>> # Komatxo alderantzizkatuek zenbakiez gain beste mota batzuei
ere eragiten die:
... p = [x, y]
>>> ps = repr(p)
>>> ps
'[31.4, 40000]'
>>> # Katera itzultzeak kateei komatxo eta alderantzizko barrak
gehitzen dizkie:
... kaixo = 'kaixo mundua\n'
>>> katkaixo = `kaixo`
>>> print cadhola
'kaixo mundua\012'
>>> # Komatxo alderantzizkatuen argumentu tupla bat ere izan daiteke:
... `x, y, ('euria', 'elurra')`
"(31.4, 40000, ('euria', 'elurra'))"
>>> for x in range(1, 11):
... print string.rjust(`x`, 2), string.rjust(`x*x`, 3),
... # Ohar zaitez aurreko lerroko amaierako komaz
... print string.rjust(`x*x*x`, 4)
...
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
>>> for x in range(1,11):
... print '%2d %3d %4d' % (x, x*x, x*x*x)
...
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
>>> string.zfill('12', 5)
'00012'
>>> string.zfill('-3.14', 7)
'-003.14'
>>> string.zfill('3.14159265359', 5)
'3.14159265359'
>>> print 'PI-ren balioa gutxigorabehera: %5.3f.' % math.pi
PI-ren balioa gutxigorabehera: 3.142.
>>> for izena, telef in taula.items():
... print '%-10s ==> %10d' % (izena, telef)
...
Jack ==> 4098
Dcab ==> 7678
Sjoerd ==> 4127
Oso luzea den eta banatzea nahi ez den formatuko katea izatean, aldagaiei erreferentzia bere izenez egitea komeni da, hau lortzeko %(izena)formatua erabil daiteke:
>>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % tabla
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
open()-ek fitxategi objetu bat itzuliko digu. Bi argumenturekin
erabili ohi da:
open(fitxategiIzena,modua).
>>> print f
<open file 'C:/fitxategiizena', mode 'w' at 80a0960>
Windows eta Macintosh-en moduari 'b' gehituz fitxategia modu bitarrean irekiko du, ondorioz 'rb', 'wb' edo 'r+b' moduak existitzen dira. Windows-ek testu-fitxategi eta fitxategi-bitarren artean ezberdintasunak ditu: fitxategien lerro amaierako karaktereak arinki aldatuak izango dira automatikoki, irakurtzean edo datuak idaztean. Ezkutuko aldaketa hauek ASCII testudun fitxategien gain ez dute eraginik, modu bitarreko (JPEG edo .EXE) fitxategiek ez bezala.
Fitxategitik datu kopuru bat irakurri eta kate bezala itzuliko ditu. Kopurua argumentua aukeakoa da, honen faltan edo negatiboa bada, fitxategi osoa irakurriko du. Argumentua positiboa bada gehienez byte kopuru hori irakurri eta itzuliko du. Iada fitxategi amaierara iritsi bada kate hutsa ("") itzuliko du.
'Hau da fitxategi osoa.\012'
>>> f.read()
''
Fitxategiko lerro bakarra irakurtzen du. Katearen bukaeran lerro aldaketako karaktere bat (\n) uzten da, azken lerroan bakarrik kentzen delarik, beti ere fitxategia lerro-jauzi batean amaitzen ez bada. readline()-ek kate hutsa itzultzen badigu fitxategia amaierara iritsi dela esan nahi du eta fitxategiko lerro hutsa, lerro-jauzia bakarrik duena, '\n' bitartez adieraziko da.
'Fitxategiaren lehen lerroa.\012'
>>> f.readline()
'Fitxategiaren bigarren lerroa.\012'
>>> f.readline()
''
Fitxategiaren lerro guztiak dituen zerrenda bat itzuliko digu. Nahi izanez gero sizehint parametroa pasa geniezaiokegu, byte kopuru hori irakurriko du eta lerroa amaitu arte jarraitu, itzuliko dizkigun lerroak osorik egongo dira.
['Fitxategiaren lehen lerroa.\012', 'Fitxategiaren bigarren lerroa.\012']
Katearen edukia fitxategian idatzi eta None itzuliko du.
Fitxategian fitxategi objetuak duen posizioa itzultzen du, honen haseratik bytetan nehurtua.
Fitxategi objetuaren posizioa aldatzeko erabiltzen da, nondik argumentua hasera bezala hartuta desplazamendua aplikatuz lortzen den posiziora. nondik 0 erabiliz fitxategi haseratik hasiko da kontatzen, 1 erabiliz uneko posiziotik eta 2 erabiliz fitxategi amaiera hartuko da erreferentzi bezala.
>>> f.write('0123456789abcdef')
>>> f.seek(5) # Fitxategiaren 5. bytera joan
>>> f.read(1)
'5'
>>> f.seek(-3, 2) # Amaiera aurretik hirugarren bytera joan
>>> f.read(1)
'd'
Fitxategiaren erabilera amaitzean hau isteko eta sistemaren errekurtsoak askatzeko erabiltzen da. close() egin ostean fitxategi objetua erabiltzeko saiakera guztiek huts egingo dute.
>>> f.read()
Traceback (innermost last):
File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file
Fitxategietan kateak ez diren datu mota ezberdinak erabilera errazteko modulua da. Python-eko ia edozein objetu hartu eta kate modura pasatzen ditu. Prozesu honi zamatzea deitzen zaio, eta kontrako prozesuari arintzea. Zamatze eta arintzearen artean, objetua irudikatzen duen katea fitxategi batean, memorian gorde edo sare konexio baten bitartez hurruneko makina batetara bidali ahal izango da.
x objetu bat eta f lehendik idazteko moduan irekitako fitxategi bat baditugu objetua zamatzeko:
Hiztegien ataleko adibide berbera da, baina telefono zenbakiak fitxategi batetan gorde edo idazteko gaitasunarekin:
# Zenbakiakfitx.py fitxategiaren hasera
#
import string
egia = 1
gezurra = 0
def erakutsi(zenbakiak):
print "Telefono zenbakiak:"
for x in zenbakiak.keys():
print "Izena: ",x," \tZenbakia: ",zenbakiak[x]
def gehitu(zenbakiak,izena,zenbakia):
zenbakiak[izena] = zenbakia
def bilatu(zenbakiak,izena):
if zenbakiak.has_key(izena):
return "Zenbakia: "+zenbakiak[izena]
else:
return "Ezin izan dut aurkitu "+izena
def ezabatu(zenbakiak,izena):
if zenbakiak.has_key(izena):
del zenbakiak[izena]
else:
print "Ezin izan dut aurkitu ", izena
def kargatu(zenbakiak,fitxizena):
fitx_sarrera = open(fitxizena,"r")
while egia:
sarrera = fitx_sarrera.readline()
if sarrera == "":
break
sarrera = sarrera[:-1]
[izena,zenbakia] = string.split(sarrera,",")
zenbakiak[izena] = zenbakia
fitx_sarrera.close()
def gorde(zenbakiak,fitxizena):
fitx_irteera = open(fitxizena,"w")
for x in zenbakiak.keys():
fitx_irteera.write(x+","+zenbakiak[x]+"\n")
fitx_irteera.close()
def menua():
print '1. Zenbakiak ikusi'
print '2. Zenbaki bat gehitu'
print '3. Zenbaki bat ezabatu'
print '4. Zenbaki bat bilatu'
print '5. Zenbakiak kargatu'
print '6. Zenbakiak gorde'
print '7. Irten'
telzerrenda = {}
aukera= 0
while aukera!= 7:
menua()
aukera = input("Zer nahi duzu egitea? ")
if aukera == 1:
erakutsi(telzerrenda)
elif aukera == 2:
print "Sartu izena eta zenbakia"
izena = raw_input("Izena:")
zenbakia = raw_input("Zenbakia:")
gehitu(telzerrenda,izena,zenbakia)
elif aukera == 3:
print "Ezabatu izena eta zenbakia"
izena = raw_input("Izena:")
ezabatu(telzerrenda,izena)
elif aukera == 4:
print "Bilatu zenbakia"
izena = raw_input("Izena:")
print bilatu(telzerrenda,izena)
elif aukera == 5:
fitxizena = raw_input("Kargatzeko fitxategia:")
kargatu(telzerrenda,fitxizena)
elif aukera == 6:
fitxizena = raw_input("Gordetzeko fitxategia:")
gorde(telzerrenda,fitxizena)
elif aukera == 7:
pass
else:
menua()
print "Agur ta hurrenarte"
# Zenbakiakfitx.py fitxategiaren amaiera
Badira (gutxienez) bi errore mota ezberdin: sintaxi erroreak eta eszepzioak.
Interprete sintaktikoak akatsa izan duen lerroa errepikatuko du errorea eman deneko lehen puntua gezitxo batez seinalatuko du. Errorearen arrazoia gezitxoaren aurreko sinboloan egongo da:
File "<stdin>", line 1
while 1 print 'Iepa mundua!'
^
SyntaxError: invalid syntax
Nahiz eta sententzia edo espresio bat sintaktikoki zuzen egon, hau exekutatzean errore bat sortu liteke. Exekuzioan sortzen diren erroreak eszepzioak deitzen dira eta ez dira derrigorrez itzulezinak. Harrapatu ez diren eszepzioek ondorengoa bezalako errore mezuak sortzen dituzte:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
>>> 4 + fantomas*3
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'fantomas' is not defined
>>> '2' + 2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects
Hurrengo adibidean erabiltzaileak zenbaki bat sartu arte datuak eskatzen jarraituko du:
... try:
... x = int(raw_input("Sartu zenbaki bat: "))
... break
... except ValueError:
... print "Ez da zenbakia. Saiatu berriro..."
...
... pass
try:
f = open('fitxategia.txt')
s = f.readline()
i = int(string.strip(s))
except IOError, (errno, strerror):
print "S/I errorea(%s): %s" % (errno, strerror)
except ValueError:
print "Ezin izan dira datuk osora itzuli."
except:
print "Errore ezezaguna:", sys.exc_info()[0]
raise
try:
f = open(arg, 'r')
except IOError:
print 'Ezin da ireki', arg
else:
print arg, '-ek', len(f.readlines()), 'lerro ditu'
f.close()
... fantomas()
... except NameError, x:
... print x
...
name 'fantomas' is not defined
Eszepzio kudeatzaileek ez dituzte try klaulan jaurti direlako bakarrik kudeatuko, try klausulan deitzen (zuzenean edo zeharka) zaien funtzioetan saltatzen badute ere kudeatuko dituzte. Adibidez:
... x = 1/0
...
>>> try:
... fun()
... except ZeroDivisionError, xehetasuna:
... print 'Errore kudeaketa:', xehetasuna
...
Errore kudeaketa: integer division or modulo by zero
raise (saltarazi) sententzia erabiliz programatzaileak eszepzio bat azalduarazi dezake. Adibidez:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: Atsaldeon
Programek beraien eszepzioak izendatu ditzakete aldagai bat kate bat asignatuz edo eszepzio mota berri bat sortuz. Adibidez:
Lehen argumentuak zein eszepzio jaurti behar duen adierazten du eta bigarrenak (aukerazkoa) eszepzioaren argumentua.
... def __init__(self, balioa):
... self.valor = balioa
... def __str__(self):
... return `self.balioa`
...
>>> try:
... raise raise NireErrorea(2*2)
... except NireErrorea, e:
... print 'Nire eszepzioak saltatu du, balioa:', e.balioa
...
Nire eszepzioak saltatu du, balioa: 4
>>> raise mi_exc, 1
Traceback (innermost last):
File "<stdin>", line 1
mi_exc: 1
Edozein momentutan exekutatuko beharko diren garbiketa ekintzak zehazteko balio duen aukerazko beste klausula bat du try sententziak:
... raise KeyboardInterrupt
... finally:
... print 'Aio danoi!'
...
Aio danoi!
Traceback (most recent call last):
File "<stdin>", line 2, in ?
KeyboardInterrupt
try sententzia batek except klausula bat edo gehiago edo finally klausula eduki beharko du, baina ez biak.
Python-en, C++-eko terminologia erabiliz, klaseko atalak (datuak barne) publicoak dira eta atal funtzio guztiak virtualak. Ez dago eraikitzaile eta destruktore berezirik. Metodo funtzioa, objetua adierazten duen lehen argumentu esplizituarekin zehazten da eta funtzioari inplizituki deitzen laguntzen du. Klaseak objetuak dira, Python-en datu mota guztiak diren bezala. "Objetu" hitzak ez du derrigorrez klase baten instantzia denik esan nahi. Nahiz eta datu mota guztiak ez diren klaseak (fitxategi, zerrenda edo osoak), denek dute semantika zati bat berdina. Sintaxi berezia duten barne operadore gehienak klaseetan birzehaztu daitezke.
Objetuek banakotasuna dute. Izen bat baino gehiago izan ditzake objetu batek, "alias"ak sortzea deitzen zaio honi beste hizkuntza batzuetan. Kasu batzutan alias-as erakusle bezala jokatzen dute. Adibidez, objetu bat pasatzea erraza da, erakuslea bakarrik pasatzen baita. Funtzioak argumentu bezala pasatako objetua aldatzen badu, funtzioari deitzen dionak ikusiko ditu aldaketok.
Klaseen erabilera ulertzeko beharrezkoa da izen taldeek nola jokatzen duten jakitea.
Izen eremu bat izenak eta objetuen arteko egokitzapena da. Gehienak hiztegi bezala inplementatzen dira. Izen eremuen adibideak:
Atributuak soilik irakurtzeko edo irakurri/idaztezko izan daitezke. Atributuei balioak asignatu dakizkiokete. Moduluen atributuak irakurri/idazteko dira eta del sententzia erabiliz ezabatu daitezke.
Izen eremuak momentu ezberdinetan sortzen dira eta bizi-denbora ezberdina dute. Barne izenak dituen izen eremua Python interpretea abiaraztean sortzen da eta ez da ezabatzen. Modulu baten izen eremu orokorra moduluaren definizioa irakurtzean sortuko da eta interpretetik irten arte iraungo dute. Eta funtzio baten izen eremua funtzioari deitzean sortu eta irtetean ezabatuko da. Deitura errekurtsiboek bakoitzak bere izen eremua sortuko du.
Esparru bat (ambito) Python programa baten gune testual bat da, non izen eremuara zuzenean iritsi daiteken. Kontestu honetan kalifikatu gabeko (punturik gabe) izen bat izen eremuan bilatzen saiatuko da.
Nahiz eta esparruak estatikoki finkatzen diren, dinamikoki erabiltzen dira. Exekuzioaren edozein puntutan hiru esparru habitu daude, zuzenean heldu daitezken hiru izen eremu: barne esparrua (lehenengo hemen bilatzen da izena, izen lokalak ditu), erdiko esparrua (hemen jarraituko du bilaketa, moduluaren izen orokorrak izango ditu) eta kanpo esparrua (bilaketan azkena, barne izenak ditu).
Esparru lokalak lantzen ari den funtzioaren izenak edukiko ditu. Funtzioetatik kanpo, esparru lokalak esparru orokorraren izen eremu berari egiten dio erreferentzia: moduluaren izen eremua. Klaseen definizioek esparru lokalean beste izen eremu bat hartzen dute.
Modulu baten zehazturiko funtzio baten esparru orokorra modulu beraren izen eremua da. Bestalde, izenen benetako bilaketa dinamikoki egiten da, exekuzio garaian. Baina hizkuntzaren definizioak izenen ebazpen estatikora garamatza.
Asignazioak beti barnekoeneko esparruan doaz. Asignazioek ez dute daturik kopiatzen, soilik izenak objetuei estekatzen dizkie eta berdin ezabatzean (del x sententziak x-en esparru lokalak erreferentzia egiten dion izen eremuko esteka kenduko du.
Klase baten definizioaren itxurarik sinpleena:
<sententzia-1>
.
.
.
<sententzia-N>
Klaseko objetuek bieragiketa mota jasan ditzakete: atributuei erreferentzia eta instantziazioa.
Atributuei erreferentziek Python-eko sintaxi estandarra erabiltzen dute: obj.izena. Atributuentzat balio duten izenak klasea sortzean klasearen izen eremuan zeuden izen guztiak izango dira. Ondorioz klasearen definizioa:
"Adibiderako klasea"
i = 37
def f(x):
return 'iepa mundue!'
Klaseen instantziazioak funtzioen notazioa erabiltzen du:
self.hustu()
... def __init__(self, zatiErreala, zatiIrudikaria):
... self.r = zatiErreala
... self.i = zatiIrudikaria
...
>>> x = Konplexua(3.0,-4.5)
>>> x.r, x.i
(3.0, -4.5)
Instantzia objetuekin atributuei erreferentzia bakarriak egin geniezaiokegu. Bi atributu izen mota bakarrik daude: metodoak eta datuen atributuak.
Datuen atributuak deklaratu beharrik ez dago aldagai lokalak bezala.
Metodoak objetuei dagozkien funtzioak dira.
Objetu instantzia baten metodoen izenak klasearen araberakoak izango dira. Funtzio objetuak diren klase baten atributu guztiak instantziei dagozkien metodoak zehazten dituzte. Adibidez, klaseIzena.f funtzioa denez x.f metodo bati erreferentzia da, baina ez x.i, klaseIzena.i ez delako funtzioa. x.f ez da klaseIzena.f-ren berdina, objetu metodoa baita eta ez objetu funtzioa.
klaseIzena klasearen adibidean x.f()-ri deituz 'iepa mundue!' itzuliko liguke. Baina ez beharrezkoa bereala deitzea: x.f metodo objetua denez, gorde eta geroago berreskuratu bait genezake, adibidez:
while 1:
print xf()
f metodoaren definizioak argumentu bat behar zuela ohartuko zinen. Deitzen duen objetua pasako zaio lehen argumentu bezala. Orokorrean, metodo bati argumentu zerrenda batekin deitzea, metodo objetua haserako argumentu zerrendan sartuz lortuko genuken argumentu zerrendarekin deitzearen berdina da.
Funtzio objetua den klaseko atributua erakusten badu izenak, metodo objetu bat sortuko da objetu instantzia eta objetu abstraktu batean aurkituriko objetu funtzioa (metodo objetua) bateratuz.
# Ajedreza.py fitxategiaren hasera
#
class alfil:
"Alfilaren klasea"
def __init__(self, x, y):
self.posX=x
self.posY=y
def pX(self):
return self.posX
def pY(self):
return self.posY
def mugitu(self,x,y):
if ((x<=0)or(x>8)or(y<=0)or(y>8)):
return False
import math
if (abs(self.posX-x))!=(abs(self.posY-y)):
return False
if ((self.posX==x)and(self.posY==y)):
return False
self.posX=x
self.posY=y
return True
print '\nAlfilaren jokuan hastera goaz\n'
auk='b'
pieza=alfil(1,1)
while ((auk=='b')or(auk=='B')):
print 'Alfilaren posizioa:',pieza.pX(),',',pieza.pY()
x=int(raw_input("Zein X-en posiziora nahi duzu mugitu? "))
y=int(raw_input("Zein Y-en posiziora nahi duzu mugitu? "))
if (pieza.mugitu(x,y)):
print 'Mugitu dut.'
else:
print 'Ezin da mugimendu hori burutu'
auk=raw_input('Beste mugimendu saiakerarik nahi? (b/e) ')
# Ajedreza.py fitxategiaren amaiera
Eratorritako klase baten definizioaren sintaxiak honako itxura du:
<sententzia-1>
.
.
.
<sententzia-N>
klaseEratorriIzena() landuz klasearen instantzia berri bat sortuko da. Metodoei erreferentziak egiteko: dagokion klaseko atributua bilatuko du, behar izanez gero klase oinarrietatik jeitxiz, eta metodoaren erreferentzia ondo egongo da modu honetan funtzio objetu bat lortzen bada.
Klase eratorriek klase oinarrietan zehaztutako metodoak berriro definitu ditzakete. Metodoek objetu bereko beste metodoei deitzean ez dutenez lehentasun berezirik, klase oinarri batean zehazturiko metodo batek klase oinarri bereko metodo bati deitzean, berriro definituko duen klase eratorri batetako metodo bati deitzen amaitu lezake.
Eratorritako klase batetan metodo bat berriro definitzean, baliteke ordeztu beharrean gehiago sakontzea klase oinarriko izen bereko metodoa. Klase oinarriko metodoari zuzenean deitzeko: klaseOinarriIzena.metodoIzena(self, argumentuak) erabiliz.
Klase oinarri anitzdunetatik eratorritako klase baten definizioaren sintaxiak honako itxura du:
<sententzia-1>
.
.
.
<sententzia-N>
Herentzia anizkoitzaren arazo bat klase oinarrietako bat berdina duten bi klasetatik eratorritako klaseena da. Nahiz eta erraza izan, kasu honeta zer gertatuko den jakitea (instantziak "instantzia aldagaien" edo elkarbanatzen duten oinarriak erabilitako datuen atributuen kopia bakarra izango du), ez da garbi ikusten.
Modu mugatu batetan klaseko identifikadore pribatuak erabili daitezke. __fantomas formako edozein identifikadore _klaseIzena__fantomas-ekin testualki ordezkatuko da, non klaseIzena uneko klasea den haserako azpi-marrak kenduz. Berriro idazte hau indentifikadorearen posizio sintaktikoa kontutan hartu gabe egingo da, modu pribatuan klase eta instantziako aldagaiak, metodoak eta aldagai orokorrak zehazteko erabili daitekelarik. Beste klase batzuetako instantzietan klase honetako instantzia pribatuko aldagaiak gordetzeko ere balio du. Baliteke berriro idatzitako izenak 255 karaktere baino gehiago izatean izenak moztea. Klaseetatik kanpo edo klasearen izenak azpi marrak bakarrik dituenean, izenak ez dira berriro idatziko.
Izenen berridazpenak klaseei metodoak eta instantzia aldagai "pribatuak" zehazteko modu errazagoa ematen dute, klase eratorrietan zehazturiko instantzia aldagaietaz ahaztuz. Aldagai pribatuak aldatu edo irakurri liteke, nahiz eta zaila izan. Akats txiki bat dago: klase oinarriaren izen berdinarekin eratortzean klasea bat, klase oinarriaren aldagai pribatuak erabiltzea posible da.
Hona hemen __getattr__ eta __setattr__ bere metodoak inplementatzen dituen eta atributu denak aldagai pribatuetan gordeko dituen klase bat:
__vdic = None
__vdic_izena = locals().keys()[0]
def __init__(self):
self.__dict__[self.__vdic_izena] = {}
def __getattr__(self, izena):
return self.__vdic[izena]
def __setattr__(self, izena, balioa):
self.__vdic[izena] = balioa
Askotan Pascal-eko "record" edo C-ko "struct"-en antzeko datu egiturak erabiltzea oso baiogarria da. Hau lortzeko klase huts baten definizioa erabili genezake, adibidez:
pass
ion = Langilea() # Langile fitxa huts bat sortzen da
# Fitxaren eremuak beteko ditugu
ion.izena = 'Ion Elorza'
ion.departamentua = 'Kalkulu zentrua'
ion.soldata = 2000
erabiltzaileak zehaztutako eszepzioak iada ez daude testu-kate objetuetara mugatuta; klaseen bitartez ere identifikatu daitezke. Mekanismo hauek erabiliz eszepzioen jerarkia zabalkorra sortu liteke.
raise sententziaren bi modu berri:
raise instantzia
Except klausula batek kate objetuak bezalaxe klaseak zenbakitu ditzake. Except klausula baten klase batek jaurti den eszepzioaren klase berekoa edo bere klase oinarrikoa bada eszepzioa harrapatuko du (alderantziz ez; klase eratorri batek ez du harrapatuko bere klase oinarrienik). Ondorengo adibidea landuz gero, B, C, D erakutsiko du, ordena horretan:
pass
class C(B):
pass
class D(C):
pass
for c in [B,C,D]:
try:
raise c()
except D:
print "D"
except C:
print "C"
except B:
print "B"
Alfilaren jokuaren egokitzapena da, hemen alfilaz gain zaldiarekin ere jolastu genezake biak pieza klasearen eratorriak direlarik. Honez gain mugimenduen erabilera okerra eszepzioak erabiliz landuko da:
# Ajedreza01.py fitxategiaren hasera
#
class pieza:
"Piezen klasea"
def __init__(self, x, y):
self.posX=x
self.posY=y
def pX(self):
return self.posX
def pY(self):
return self.posY
class alfila(pieza):
"Piezatik eratorritako alfilaren klasea"
def mugitu(self,x,y):
if ((x<=0)or(x>8)or(y<=0)or(y>8)):
raise Taula
import math
if ((abs(self.posX-x)) != (abs(self.posY-y))):
raise Mugimendua
if ((self.posX==x)and(self.posY==y)):
raise Batez
self.posX=x
self.posY=y
class zaldia(pieza):
"piezatik eratorritako zaldiaren klasea"
def mugitu(self,x,y):
if ((x<=0)or(x>8)or(y<=0)or(y>8)):
raise Taula
import math
if ((self.posX==x)and(self.posY==y)):
raise Batez
if((abs(self.posX-x)!=2)and(abs(self.posY-y)!=1)or
(abs(self.posX-x)!=1)and(abs(self.posY-y)!=2)):
raise Mugimendua
self.posX=x
self.posY=y
class Ajedreza:
pass
class Taula(Ajedreza):
pass
class Mugimendua(Ajedreza):
pass
class Batez(Ajedreza):
pass
def piezalortu():
"Zein piezarekin jolastuko dugun zehaztuko da"
auk=int(raw_input( '''Sartu:\n\t1 alfilarekin jolasteko\n\t2
zaldiarekin jolasteko\n'''))
if auk==1:
pieza=alfila(1,1)
return pieza
elif auk==2:
pieza=zaldia(1,1)
return pieza
jokoan=piezalortu()
jarraitu='b'
while ((jarraitu=='b')or(jarraitu=='B')):
print 'Zure pieza',jokoan.pX(),',',jokoan.pY(),'posizioan aurkitzen da.'
try:
x=int(raw_input('Zein da mugitu nahi duzun X posizioa?\n'))
y=int(raw_input('Zein da mugitu nahi duzun Y posizioa?\n'))
jokoan.mugitu(x,y)
jarraitu=raw_input('Beste saiakerarik nahi? (b/e)\n')
except Taula:
print 'Pieza tulatik kanpo atera duzu!'
except Mugimendua:
print 'Horrela ezin duzu mugitu!'
except Batez:
print 'Toki berean utzi duzu!'
except ValueError:
print 'Zein herritan da hori zenbakia? Nirean ez behintzat!'
# Ajedreza01.py fitxategiaren amaiera
This document was generated using the LaTeX2HTML translator Version 2002-2-1 (1.70)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -no_subdir -split 0 -show_section_numbers /tmp/lyx_tmpdir5371KEsA6b/lyx_tmpbuf0/Tutoretza.tex
The translation was initiated by on 2004-03-09