Wednesday, July 12, 2006

Python 2.5 beta

Megjelent a python2.5 masodik betaja. Csak most volt idom kiprobalni par uj featuret ezert nemirtam az elsorol. Errol viszont most egy kicsit bovebben fogok.

Nezzuk milyen ujdonsagokat rejteget szamunkra. Elszor is van amd64 portja ami tok jo (lesz majd). Mostmar van a c-s '?:'-hez hasonlo felteteles kifejezes bar teljsen mas syntaxal. "x = cond ? 1 : 0" helyett "x = (1 if cond else 0)". A zarojel nem kotelezo de azt ajanljak(nagyon helyesen) hogy hasznaljuk a jobb olvashatosag miatt. Nem tudom eldonteni hogy ez jo vagy rossz, eddig se volt nehez leirni azt 2 sort, a python pedig sose arrol volt hires hogy kevesebbet kell gepelni (mint pl perl) hanem hogy rendkivul jol olvashato a kod. Eloszor arra gondoltam hogy c-s verziot kellett volna akkor mar belerakni, mert azt mindenki ismeri es megszokta mar. Viszont az egyaltalan nem illik a python szintakszisahoz. Valoszinuleg azert viszolyogtam eloszor tole mer rogton a perles "expression if (condition)" -re asszocialtam, (Na akkor mar csak az unless hianyozna es kb dobnam kukaba az egesz nyelvet:)) node nem errol van szo ugyhogy lehet hogy hasznosnak fog bizonyulni.

Van egy masik nyelvi feature aminel egyaltalan nem volt kerdes hogy jo-e vagy nem. Megpedig hogy finally megengedett lett exceptionnel egyutt.

Azaz:

try:
print 1/0
except Exception, e:
print e
finally:
print 'finally'


Ez egyertelmuen ql, johetett volna hamarabb is.

Ha mar finally akkor ugylatszik nem alltak meg ennel a developerek hanem tovabbmentek es csinaltak egy meg egyszerubb modszert a clean-up es hasonlo muveletek lefuttatasara. Bejott egy uj kulcsszo a "with" (es "as") aminek segitsegevel az object tulajdonkeppen sajat maga vegezheti a clean-up-ot, eroforras felszabaditast illetve minden olyat amit altalban az ember a finally blockba tesz. Kovetkezokeppen kell elkepzelni:


with kifejezes as valtozo:
valtozo.fgv1
valtozo.fgv2


Az erdekes ebbe az hogy a with block vegen vagyha kivetel keletkezett, tehat mindekeppen lefut egy cleanup amit az osztalyban van elore definialva. Olyan objectet hasznalhatunk with blockba ami tamogatja ezt, un. Context Manager protocolt. Ami egyszeruen annyit jelent hogy egy elore meghatarozott interface metodusaival rendelkezik, de errol majd kesobb.

Hogy vilagosabb legyen ime egy filekezelos pelda:


with open('file.txt', 'r') as f:
for line in f: print line


A muvelet vegen a file szepen lezarodik, anelkul hogy ki kene irni az f.close()-t.

A PEP-ben erre a modszerre tobb peldat is mondanak, pl I/O muvelet mint filekezeles, thread lock hogy ne felejtsunk el releaselni, es ami nekem a legjobban tetszett az a tranzakcio kezeles. Erre fogok most kiterni.

Tehat van egy db tablank akarunk valamilyen muveleteket vegrehajtani rajta, ha pl valamelyik nem sikerul egy kivetel miatt akkor rollbackelje az egeszet egyebkent mehet a commit.

Ezt ezt ehhez hasonlo koddal megtehetjuk.


db = DatabaseConnection()
# begin transaction
with db as cursor:
cursor.insert('first row')
cursor.delete('another row')


De nezzuk mi van a hatterben azaz hogy tudunk olyan osztalyt csinalni ami tamogatja a with-et. Eloszor is ez a bizonyos Context Manager eloirja szamunkra hogy legyen az osztalynak egy __enter__ es egy __exit__ metodusa. Az enter a blockba valo belepeskor hivodik meg es visszaadja azt az objectet amin a muveletet szeretnenk elvegezni. Ez fog az 'as' kulcsszo utan megadott valtozoba eltarolodni. ( masszoval cursor = db.__enter__() ) Kell hogy legyen tovabba egy __exit__(self, type, value, tb) amibe altalaba cleanupot tesszuk. Itt a commitot, rollbackat vagy a db connectionpooling lezarast. Az exit parameterei ugyanaz mint a sys.exc_info(). Innentol kezdve mar haszanhatjuk is a with-et.

A lenti examplet a PEP-bol vettem es egeszittem ki, a DatabaseConnection az ami tudja ezt a bizonyos interfacet, van neki exit es entere. Az enter visszater a cursorral amivel insertelhetunk vagy torolhetunk az adatbzisbol. Az exit pedig ha nincs kivetel akkor commitol, egyebkent rollbackkel. Az exit visszateresi erteke is fontos, ez altalaban false, ami azt jelenti hogy a kivetelt ujradobja, a true (csak a pelda miatt true) pedig teljesen elnyeli.


from __future__ import with_statement # ez elvileg csak a betaban kell, kesobbiekben alapbol importalni fogja

class Cursor:
def insert(self, s):
print 'insert', s

def delete(self, s):
print 'delete', s
raise Exception('Database exception: delete error')


class DatabaseConnection:
def __enter__(self):
self.cursor = Cursor()
return self.cursor

def __exit__(self, type, value, tb):
if tb is None: # No exception
# do commit
print 'COMMIT'
else:
# do rollback
print 'ROLLBACK', value
# release the connection object...
return True #False



db = DatabaseConnection()
# begin transaction
with db as cursor:
cursor.insert('first row')
cursor.delete('another row')



A program kimenete pedig a kovetkezo:

insert first row
delete another row
ROLLBACK Database exception: delete error

Ugyanis a deleteben szandekosan dobtam egy kivetelt, ellenkezo esetben kommitol.

Errol lehet azt is gondolni hogy nem egy nagy dolog, raadasul eddig is siman meg lehett finallyval mostmeg irhatok neki kulon osztalyokat. A dolog lenyege inkabb az szerintem hogy ezekutan a standard runtime osztalyai es valoszinuleg a thirdparty libek nagyresze is tamoatni fogja ezt a modszer ahol ez szukseges, azaz nem nekem kell megirni a cleanupot minden muveletnel hanem az object gondoskodni fog arrol hogy a block vegen lezarja a filet, bezarja a socket kapcsolatot/adatbazist stb. Szerintem tokjo featurenek nez ki. Ja, es van egy contextlib modul amibe olyan decorator van definialva ami leegyszerusiti a context managerek fuggvenybol torteno gyartasat.

Van meg relativ import, es sok mas uj feature is, ezeket mindenki olvassa el a whatsnew-ban.

0 comments: