A lambdafüggvény nem más, mint egy névtelen, egysoros, „egyszer használatos” függvény. Használata minden esetben elkerülhető bővebb kifejtéssel.Szintaxisa: lambda <argumentumok>: kifejezés
A gyorsabb fejlesztés érdekében készített “onfly” eljárások, amelyeknél 1-2 sorban kifejthető a kód (eljárás törzs és név írása nélkül).
g = lambda x: x**2
g(8)
A printf függvény
formázott adatkivitelt valósít meg. H
ívásának formája:
printf(formátum
string
, paraméterlista)
A formátum
string
, amely rendszerint stringkonstans, kétféle karaktert tartalmazhat:
•
Az első csoport karakterei normál karaktersorozatot alkotnak a formátumstringen belül, ezek
minden átalakítás nélkül kerülnek kiírásra.
•
A másik csoport karakterei speciális konverziót írnak elő, amelyek meghatározzák a
paraméterlistában szereplő paraméterek értelmezési módját és a megjelenés formátumát. Ezek
a konverziós előírások százalékjellel kezdődnek és valamilyen konverziós karakterrel zárulnak
Változó definiálás, alaptípusok
Az objektumok az OOP szabályai alapján zárt egységek, amik különféle interface-eken (metódus/tulajdonság) keresztül kommunikálnak egymással, és a más programrészekkel. Megőrzik belső állapotukat.
A gyorsabb fejlesztés érdekében készített “onfly” eljárások, amelyeknél 1-2 sorban kifejthető a kód (eljárás törzs és név írása nélkül).
g = lambda x: x**2
g(8)
A printf függvény
formázott adatkivitelt valósít meg. H
ívásának formája:
printf(formátum
string
, paraméterlista)
A formátum
string
, amely rendszerint stringkonstans, kétféle karaktert tartalmazhat:
•
Az első csoport karakterei normál karaktersorozatot alkotnak a formátumstringen belül, ezek
minden átalakítás nélkül kerülnek kiírásra.
•
A másik csoport karakterei speciális konverziót írnak elő, amelyek meghatározzák a
paraméterlistában szereplő paraméterek értelmezési módját és a megjelenés formátumát. Ezek
a konverziós előírások százalékjellel kezdődnek és valamilyen konverziós karakterrel zárulnak
Változó definiálás, alaptípusok
anint1=int(128)
anint2=132
# két egész szám
print anint2/anint1
# becsapós - egész osztás!
print float(aint2)/anint1
# típusváltás - lebegőpontos osztás
text='Egy szöveges változó'
text2=text
# két szövegváltozó
text[1]='a'
# hiba, a stringek nem módosíthatóak!
text=text.replace('k','a')
# működik, lecseréli
text=""
for i in range(10):
text=text+chr(65+i)
# ez nem jó - bár működik
l=[] # ld. később
for i in range(10):
l.append(chr(65+i))
text="".join(l)
# gyors string összefűzés, mivel a folyamatos hozzáadás lassú
# ld. Java StringBuffer
fmts='%d. elem, név: "%s"'
text=fmts%(1,'János')
# string formázás (összefűzés helyett is használatos)
text="alma mater"
# egyszerű string
ubtext=u"alma mater"
# unicode string
utext=unicode(text,'iso-8859-2')
# unicode string konvertálással
print type(text)==type(ubtext)
# 0 vagy False - egyik string, másik unicode string
print type(utext)==type(ubtext)
# 1 vagy True - mindkettő unikódos
# mágikus unikóddá alakító eljárás (ha magyar gépen fájlokkal dolgoznánk)
_deflang='iso-8859-2'
def UnicodeIt(text):
if not (type(text) in [type(''),type(u'')]):
text=str(text)
if type(text)<>type(u''):
text=unicode(text,_deflang)
return text
# eljárás az azonos típusra hozáshoz
s1='a';s2=u'á'
print s1+s2
# exception!
s3=UnicodeIt(s1)+UnicodeIt(s2)
print s3
# a stringekben használhatunk vezérlő karaktereket
s="\n\t"
# újsor + tab
print "%s\n%s"%(1,2)
# ekvivalens ezzel
print 1
print 2
print chr(65)+chr(32)+chr(66)
# karakterkódok értékből
# a stringek másolása, részelemek (ld. később a listáknál is):
s="abcdef"
print s[1:2] # "bc"
s2=s[:] # ez olyan, mint az s2=s
s3=s[-1] # az utolsó karakter ("f")
ma=[]
# lista definiálás, ez most egy üres lista
ma.append(1)
# a listához adtunk egy értéket
ma.append('sss')
# a listához adtunk egy értéket
ma.append(text)
# a listához adtunk egy értéket - változóból
print len(ma)
# lista hossz
print ma
# a lista
print ma[1:2]
# lista részlete (másolata!)
ma1=ma
# ma REFERENCIA(!) átadása
ma1.append(1)
# ekkor ma-ba is kerül egy 1-es
ma2=ma[:]
# ma teljes átmásolása, egy új lista, de azonos elemekkel
ma2.append(2)
print "%s\n%s"%(ma,ma2)
# ekkor ma és ma2 már más értékeket ad vissza
ma.remove(1)
# 1 (mint egész érték) első előfordulásának eltávolítása
di={}
# új szótár - üres
di2={1:'a',2:'b','s':'sss'}
# új szótár, előre definiált értékekkel
di[1]='c'
# elem értékadás (vagy új elem hozzáadása a szótárhoz). A kulcs 1, az érték "c".
print di[1]
# elem elérése, érték kinyerése
print di
# a szótár a maga teljességében
di.update(di2)
# felülírás a másikkal
print di
# a szótár
print di[1]
# elem olvasása
print di['s']
# elem olvasása
print di.keys()
# kulcsok
# fontos: a sorrendjük a hashelés miatt változhat!
print di.has_key(1)
print di.has_key(555)
# van ilyen kulcs ?
d1={'a':1,'c':1}
d2={'a':2,'b':3}
d1.update(d2)
# felülírás, és új elemek áthozatala
# {'a':2,'b':3,'c':1}
d3=d1.copy()
# teljes másolás
tu=()
# egy üres tuple (vektor, "konstans")
# ezzel nem tudunk mit kezdeni
tu=(1,2,3)
print tu[0]
# elem olvasás
print tu[1:]
# több elem 1. indextől felfelé
tu.remove(1)
# ez hibát dob, mert nincs neki ilyen metódusa
#
# Speciális (imádnivaló!!!) nyelvi jellemzők:
#
z=y=x=1
# értékadás egy lépésben
x,y,z=(1,2,3)
# értékadás egy lépésben, tuple-ből
alist=[1,2,3]
x,y,z=alist
# értékadás egy lépésben, list-ből
a=1;b=2
a,b=(b,a)
# felcserélés egy lépésben
a=[0]*10
# 10 elemű tömb, csupa nullával
b=[[],[]]
# 2 elemű tömb, tömb elemekkel
b=[[]]*2
print b
b[1].append(2)
print b
# 2 elemű tömb, azonos elem referenciával
Összehasonlítás, elágazás
x=1
if x==1:
print "x=1'
x=2
if x<>1 or x!=1:
# az <> jel ekvivalens a!= jellel
# tehát fenti kifejezésből az egyik redundáns
print "x<>1"
if x<2:
print "<2"
s1="a">1 or b==2 or c==3:
pass
# Nem kell zárójelezni az alelemeket (gyorsabban gépelhető)
if a&&1 and (a%1)<>0:
print "Páratlan"
# Az bitszintű "and" és a logikai "and"
Eljárás definiálás, hívás
def Proc1():
return "valami"
# eljárás bemenő érték nélkül
print Proc1
# hiba - ez magát az eljárást adja!
print Proc1()
# ez adja az eljárás eredményét
def Proc2(x,y):
return x*y
print Proc2(1,2)
# több paraméter
def Proc3(x,y):
return (x*x,y*y,x*y)
print Proc3(1,2)
# több paraméter visszaadása
def Proc4(list):
list.append('aresult')
alist=['a','b']
print Proc4(alist)
# ez nem ad vissza semmit
print alist
# de a listában megtaláljuk, mert a lista objektum (referencia)
# így több elemet is vissza tud adni
proclist=[Proc3,Proc2]
for proc in proclist:
print proc(1,2)
# összegyűjtés, végrehajtás, procedure típus
def Proc5(list,value=None,item=None):
if list.has_key(item): return None
if value<>None: list.append(value)
return item
alist=[]
Proc5(alist,None,1)
Proc5(alist,item=128)
Proc5(alist,value=1,item=119)
# több paraméter, default értékek, nevesített paraméterátadás
Egyéb elemek, elágazás, ciklus
# listák generálása
print range(3)
# 0,1,2
print range(1,3)
# 1,2
print range(1,6,2)
# 1,3,5
# ciklus
# range-dzsel generált tartományból
for i in range(3):
print i
# 0,1,2 => i
for i in range(1,6,2):
print i
# 1,3,5 => i
# saját listából
alist=[1,2,6]
for i in alist:
print i
# 1,2,6 => i
# stringből
alist='abc'
for i in alist:
print i
# a,b,c => i
# nagy memóriafoglalással
for i in range(1000000):
print i
# nagy memóriafoglalás elkerülésével (xrange)
for i in xrange(1000000):
print i
# ciklus vezérlése
for i in range(10):
if i==2: continue
if i==8: break
print i
# 0,1,3,4,5,6,7
Az objektumok az OOP szabályai alapján zárt egységek, amik különféle interface-eken (metódus/tulajdonság) keresztül kommunikálnak egymással, és a más programrészekkel. Megőrzik belső állapotukat.
Pythonban az objektumok a PHP-től eltérően kétféle tagot tudnak megkülönböztetni: privátot, és publikusat. Bizonyos trükkökkel a privát tagok is elérhetővé válhatnak, erre ügyelni kell, de alapvetően, "hackelés" nélkül nem lehet belenyúlni egy objektum privát adataiba.
Nézzünk egy mintát:
class A:
def __init__(self,param1,param2):
self.Params={1:param1,2:param2}
def getParams(self):
return self.Params
a=A(1,2)
# osztály létrehozása
print a.Params
print a.getParams()
Ez egy alapvető osztálydefiníció. Az __*__ tagok mindig privát tagfüggvények. Nem használhatóak másra, mint felülírásra (új funkciók). Jelen esetben az __init__ pl. maga a constructor, itt két paramétert várunk, amit eltárolunk. Mivel alapobjektumot hívtunk, nincs szükség rá, hogy meghívjuk az őst (másutt inherited, vagy super).
Fontos: a Python jelenleg átalakulás közben van, ahol bizonyos osztály jellemzők, és tulajdonságok megváltoznak. Lehetséges, hogy később nem fog működni egy-egy példa, illetve nem lesz helytálló, ami itt szerepel.
Mint láthatjuk, a Python alapértelmezetten kiajánlja a Params osztályváltozót (member), ami elég furcsa dolog a Java és a Delphi OOP viselkedéséhez képest. Ez azért van, mert a Python az objektumok belső szótárához (amely a membereket is tárolja) alapértelmezetten hozzáférést enged. Hasznos, ha az ember rekordként (struct, record) tárolni akar valamit egy objektumban, de annak forráskódjával nem rendelkezik. Ld. pl. Delphiben a Tag változó, amit direkt ezért hagytak életben. Ugyanakkor ez OOP szempontból kellemetlen, hiszen írhatóvá válnak belső tartalmak.
A Pythonban a __slots__ szótárban felsorolhatjuk az elemeket, amiket láttatni kívánunk. Ekkor minden más elérhetetlen lesz kívülről.
A másik megoldás a property-k használata. (Ezek setter/getter rutinok) Így privátként lehet definiálni az adott membert.
class A:
def __init__(self,param1,param2):
# a _ előtag priváttá teszi az elemet
self._Params={1:param1,2:param2}
def getParams(self):
return self._Params
Params=property(getParams);
a=A(1,2)
# osztály létrehozása
print a.getParams()
print a.Params
Ez már megfelel egy rendes, tisztességes objektum alapvető követelményeinek.
Az öröklés, de főleg a többszörös öröklés (multiple inheritance) kényes téma a Python-ban, annál is inkább, mivel forradalmi változások zajlanak az objektumok táján, és ezek a kódokra óriási hatással lesznek. Mindenesetre annyit el lehet mondani, hogy a Python a többszörös öröklődés útját követi (nem pedig a Delphi-ben és Java-ban használatos interface-re épülő megoldásokat).
A következő példa egy egyszeres öröklést mutat be:
class A:
def __init__(self,param1,param2):
self._Params={1:param1,2:param2}
def getParams(self):
return self._Params
Params=property(getParams);
class B(A):
def __init__(self,param1,param2,param3):
A.__init__(self,param1,param2) # az ős meghívása - nagyon fontos dolog (ld. super/inherited)
self.Params[3]=param3
b=B(1,2,3)
# osztály létrehozása
print b.getParams()
print b.Params
# megjegyzés:
# pontosan a változások miatt érdemesebb minden objektumot az alapobjektumból
# származtatni. Máskülönben érdekes hibákat kaphatunk, mivel a property-kezelés
# alacsonyabb rendű, mint az osztályváltozók elérése.
# Vagyis egy property írás helyett (Set* method) könnyen egy osztályváltozóba
# írhatunk!
class C:
def __init__(self,param1,param2):
self._Params={1:param1,2:param2}
def getParams(self):
return self._Params
def setParams(self,value):
self._Params=value
Params=property(getParams,setParams);
c=C(1,2)
d={'a':1,'b':2}
c.Params=d # hiba, mi egy Params változóba írtunk
# A megoldás:
class C(object):
...
A Pythonban az osztályok temérdek beépített metódust tartalmaznak, amelyekkel szabályozni lehet a viselkedésüket. Ezekkel meg lehet mondani, hogy mely műveletet hogyan értelmezzünk egy osztályon. Pl. a DateTime osztályban felülírásra került a komparáció, és kivonás/összeadás, így ha ezekben a műveletekben szerepel az objektum, akkor nem kell külön eljárásokat írni/hívni.
dt=DateTime('2001.01.12')
dt=dt+1 # 1 nappal előre
print dt
Íme néhány felülírható metódus:
__repr__ Az objektum általános leírása (állapota, stb.).
__cmp__ Összevetés egy értékkel (kisebb/nagyobb/egyenlő).
__len__ Hossz (pl. elemszám).
__add__ Érték hozzáadás
__getitem__ Al-elem értéke (index).
Természetesen sok más metódus is létezik (fenti lista csak ízelítő), de az alábbi példa megértéséhez szükséges.
class A:
def __init__(self,param1,param2):
self._Params={1:param1,2:param2}
def __repr__(self):
return "A object: "+str(self._Params)
def __add__(self,op1):
p=self._Params
if type(op1)==type(''):
return (op1+str(p[1])+str(p[2]))
else:
return (op1+p[1]+p[2])
def __getitem__(self,idx):
return self._Params[idx]
a=A(1,2)
# osztály létrehozása
print a
print a+1
print a[1]
A Python objektumok rendelkeznek még egy érdekes lehetőséggel, egyfajta áldestruktor definiálásával. Ezek a metódusok tartalmazhatnak olyan elemeket, amelyek segítik a szemétgyűjtő munkáját.
Megjegyzés: Mint tudjuk, a szemétgyűjtés a változók és objektumok automatikus memóriakezelését célozza meg. Ezzel gond lehet, hogyha a változók/objektumok keresztreferenciákat tárolnak, mert így a szemetet nem lehet eltüntetni, ami memóriahiányt okoz. A megoldás, hogyha egyrészt minden olyan helyen, ahol nem tárolunk elsődleges elemeket, gyenge referenciákat tartunk (weakref.ref()), másrészt a objektum "halálakor" segíthetjük a garbage collectort bizonyos erőforrások felszabadításával.
class A:
def __init__(self,param1,param2):
# Egy nagy adattömb foglalása
self._Data=[0]*1000000
self._ID=param1
self._Refs=None
def CloseResources(self):
# mindent megszüntetünk
# memória felszabadítás, ez a kevésbé fontos, mert ez a gc megteszi, ha meghal az objektum
self._Data=None
# külső referenciák törlése - ez a lényeges pont
# más esetben keresztbehivatkozás miatt a gc nem tudja kidobni az objektumot
# és memóriaszivárgást okoz!
self._Refs=None
def SetReferences(self,Refs):
# Külső refrenciákat tárolunk
self._Refs=Refs
def __del__(self):
print "Now release data of "+str(self._ID)
self.CloseResources()
for idx in range(10):
a=A(idx,idx+1)
import gc
gc.collect()
Erre építeni programot azonban nem szabad, mivel nem garantált a lefutása sem (lehet, hogy a program befejeződik még a memória teljes felszabadítása előtt)! Az efféle "destruktorok" végrehajtása kétséges, amellett az lefutási idejüket sem tudjuk kiszámítani. Lásd Java GC működése + finalize metódus.
Ezzel áttekintettük a Python objektumorientált programozás legeslegalapjait.
Példaprogramok
1.) Összevetés kód strukturáltság, és tömörség tekintetében:
Python
Delphi
def MyFunction(value):
return value*2+1
ma=myarray=[0]*10
for idx in range(len(ma)):
ma[idx]=idx
na=newarray
for value in ma:
na.append(MyFunction(value))
print myarray
print newarray
function MyFunction(value:double):double;
begin
Result:=value*2+1;
end;
var
ma, myarray,na,newarray:array of double;
idx:integer;
begin
SetLength(myarray,10);
ma=myarray;
SetLength(newarray,10);
na=newarray;
for idx:=0 to High(ma) do begin
ma[idx]:=idx;
end;
for idx:=0 to High(ma) do begin
na[idx]:=MyFunction(ma[idx]);
end;
for idx:=0 to High(ma) do write(',',ma[idx])
writeln();
for idx:=0 to High(na) do write(',',na[idx])
writeln();
end;
2.) Helyfoglalás számítás egy szerver egy mappájában:
import os,sys
print "NetDirLen"
l=len(sys.argv)
if (l<2):
print 'Usage:\n Netdirlen.py [starting dir]\n\n Starting dir can "."'
sys.exit()
s=str(sys.argv[1])
if (s=='..'):
print 'Error: starting dir cannot be ".."'
sys.exit()
if (s=='.'):
s=os.getcwd()
sdir=s
print "Working dir:",sdir
print "Dir","Size"
fstat=open("netdirlen.stat.txt","w")
fstat.write("Dir"+chr(9)+"Size\n")
def processdir(basedir,Root):
Sum=0
os.chdir(basedir)
files=os.listdir(basedir)
files.sort()
for s in files:
sfile=basedir+"/"+s
try:
stt=os.stat(sfile)
size=stt[6]
except:
size=-1
isdir=os.path.isdir(sfile)
if Root==0:
if isdir:
print "- subdir:",s
Sum=processdir(sfile,1)
stat=s+chr(9)+str(Sum)
print " size :",Sum
fstat.write(stat+"\n")
elif Root==1:
if isdir:
Sum=Sum+processdir(sfile,1)
else:
if size<>-1: Sum=Sum+size
return Sum
processdir(sdir,0)
fstat.close()
3.) Grafikus felület wxPython-nal:
import wx
class MyApp(wx.App):
def OnInit(self):
frame = wx.Frame(None, -1, "Test Splitter")
splitter = wx.SplitterWindow(frame, -1)
p1 = wx.Panel(splitter, -1)
p1.SetBackgroundColour('red')
p2 = wx.Panel(splitter, -1)
p2.SetBackgroundColour('green')
splitter.SplitHorizontally(p1, p2)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(splitter, 1, wx.EXPAND)
frame.SetSizer(sizer)
frame.Show()
return True
MyApp(0).MainLoop()
4.) Külső FTP-vel letöltésre példa:
#!/usr/bin/env python
import sys,os,time,ftplib
from MyLogger import AddLog
import traceback
import commands, string
def IncSlash(adir):
if adir<>'':
if adir[-1]<>'/': adir=adir+'/'
return adir
def GetTraceBack():
typ,val,tra=sys.exc_info()
excmsg="\n".join(traceback.format_exception(typ,val,tra))
return excmsg
def GetActTime():
return time.strftime("%Y.%m.%d. %H:%M:%S:",time.localtime())
def StartIt(prog,params):
AddLog(GetActTime()) # az AddLog fgv. a MyLogger modulban van kifejtve
AddLog('Start program:')
AddLog(prog+' '+params+'\n')
return (commands.getstatusoutput(prog+' '+params))
def GetThisFromFTP(subdir,subfile='*.*'):
fdir=FTPAddr+'/'+FTPBaseDir+'/'+subdir+'/'+subfile
r=StartIt('wget','-x --passive-ftp -P '+BaseDir+' '+fdir)
return r
BaseDir='/home/suse'
FTPAddr='ftp.suse.com'
FTPBaseDir='pub/suse'
try:
if GetThisFromFTP('9.0','test1.rpm')==0:
print "Succeeds."
else:
print "An error occured."
except:
print GetTraceBack()
5.) Darabolás + Exception Handling (erőforrás lezárás):
#!/usr/bin/env python
import sys
fn=sys.argv[1]
fs=open(fn,'rb')
try:
cnt=0
while 1:
data=fs.read(1000000)
if len(data)>0:
fd=open(fn+'.split'+str(cnt),'wb')
try:
fd.write(data)
finally:
fd.close()
cnt+=1
finally:
fs.close()
Nincsenek megjegyzések:
Megjegyzés küldése