260 likes | 392 Views
Python - OOP. Osnove - zgled. Zgled – člani športnega kluba.
E N D
Python - OOP Osnove - zgled
Zgled – člani športnega kluba • Denimo, da bi radi napisali program, ki vodi evidenco o članih športnega kluba. Podatki o članu obsegajo ime, priimek, letnico vpisa v klub in vpisno številke (seveda je to poenostavljen primer). Torej objekt, ki predstavlja člana kluba, vsebuje štiri podatke: class Član def __init__(self, i ='Ne vem', p = 'Ne vem', l = '2009', v = 'Ni določena') : self.ime = i self.priimek = p self.letoVpisa = l self.vpisnaStevilka = v
Klub - uporaba import MojaKnjiznica a = MojaKnjiznica.Član() a.ime = "Janez" a.priimek = "Starina" a.letoVpisa = 2000 a.vpisnaStevilka = "2304" b = MojaKnjiznica.Član("Mojca", "Mavko", 2001, "4377") c = b c.ime = "Andreja" print("Ćlan a:\n" + a.ime + " " + a.priimek + " " + str(a.letoVpisa) + " (" + a.vpisnaStevilka + ")\n") print("Ćlan b:\n" + b.ime + " " + b.priimek + " " + str(b.letoVpisa) + " (" + b.vpisnaStevilka + ")\n") print("Član c:\n" + c.ime + " " + c.priimek + " " + str(c.letoVpisa) + " (" + c.vpisnaStevilka + ")\n")
Zakaj a importMojaKnjiznica a = MojaKnjiznica.Član() a.ime = "Janez" a.priimek = "Starina" a.letoVpisa = 2000 a.vpisnaStevilka = "2304" b = MojaKnjiznica.Član("Mojca", "Mavko", 2001, "4377") c = b c.ime = "Andreja" print("Ćlan a:\n" + a.ime + " " + a.priimek + " " + str(a.letoVpisa) + " (" + a.vpisnaStevilka + ")\n") print("Ćlanb:\n" + b.ime + " " + b.priimek + " " + str(b.letoVpisa) + " (" + b.vpisnaStevilka + ")\n") print("Članc:\n" + c.ime + " " + c.priimek + " " + str(c.letoVpisa) + " (" + c.vpisnaStevilka + ")\n") ime: Janez priimek: Starina b ime: Mojca priimek: Mavko ANDREJA c
Objektne metode • V definicijo razreda običajno spadajo tudi metode • Klic objektnih metod: • imeObjekta.imeMetode(parametri) • sez.append("To naj se doda") • platno.create_line(5, 10, 100, 23) • Metoda v razredu Član def inicialke(self) : return self.ime[0] + '.' + self.priimek[0] + '.'
Uporaba metode Klic metode importknjiznicaRaz # knjižnica z razredom Član a = knjiznicaRaz.Član("Janez", "Starina", 2000, "2304") inicialkeČlanaA = a.inicialke() print("Član a:\n" + a.ime + " " + a.priimek + " " + str(a.letoVpisa) + " (" + a.vpisnaStevilka + ")", end = '') print(" ima inicialke: " + inicialkeČlanaA)
Sprememba metode Spremembe v TestClan niso potrebne! class Član : def __init__(self, i ='Ne vem', p = 'Ne vem', l = '2009', v = 'Ni določena') : self.ime = i self.priimek = p self.letoVpisa = l self.vpisnaStevilka = v def inicialke(self) : return self.ime[0] + ' ' + self.priimek[0]
Metoda, ki vrača objekt iz Razreda • Vemo, da z • a = b • kjer je b spremenljivka tipa Član, v a ne shranimo kopije objekta b, ampak sedaj a in b označujeta isti objekt. • Metoda, ki naredi kopijo objekta. • a = b.Kopija() • V a je nov objekt, ki pa ima iste podatke kot b.
Kopija def Kopija(self) : nov = Član() nov.ime = self.ime nov.priimek = self.priimek nov.letoVpisa = self.letoVpisa nov.vpisnaStevilka = self.vpisnaStevilka return nov
Še metoda za izpis def Izpis(self) : print("Član:\n" + self.ime + " " + self.priimek + " " + str(self.letoVpisa) + " (" + self.vpisnaStevilka + ")\n") ali pa še defOpis(self) : opisiSe= self.ime + " " + self.priimek + " " + str(self.letoVpisa) opisSe= opisiSe + " (" + self.vpisnaStevilka + ")" returnopisiSe
Zgled >>> import knjiznicaRaz >>> nekČlan = knjiznicaRaz.Član_2('janez', 'Slovenski') >>> print(nekČlan) <knjiznicaRaz.Član_2 object at 0x02039850> >>> nekČlan <knjiznicaRaz.Član_2 object at 0x02039850> >>> nekČlan.Izpis() Član: janezSlovenski 2009(Ni določena) >>> print(nekČlan.Izpis()) Član: janezSlovenski 2009(Ni določena) None >>> print(nekČlan.Opis()) janezSlovenski 2009 >>> Od kje? Zakaj?
__str__ • Metodo Opis običajno poimenujemo __str__ (dva podčrtaja na vsaki strani!) def __str__(self) : returnself.Opis() • Seveda bi lahko namesto zgornjega stavka lahko čisto spustili metodo Opis (zbrisali) in pustili le __str__ kjer bi napisali opisiSe = self.ime + " " + self.priimek + " " + str(self.letoVpisa) opisSe = opisiSe + " (" + self.vpisnaStevilka + ")" returnopisiSe
__str__ • Potem • print(nekČlan) • str(nekČlan) >>> importknjiznicaRaz >>> nekČlan = knjiznicaRaz.Član_3('janez', 'Slovenski') >>> print(nekČlan) janez Slovenski 2009 >>> str(nekČlan) 'janez Slovenski 2009'
__repr__ >>> str(nekČlan) 'janez Slovenski 2009' >>> nekČlan <knjiznicaRaz.Član_3 object at 0x020D76D0> >>> • Izvede se metoda repr, ki vrne interno predstavitev objekta • Tudi to lahko "popravimo" • def __repr__(self) :
Uporaba >>> Član a Član: JanezStarina 2000(2304) Član b: AndrejaMavko 2001 Član c: AndrejaMavko 2001 Član d Član: TadejaMavko 2001(4377) >>> import knjiznicaRaz # knjižnica z razredom Član_3 a = knjiznicaRaz.Član_3("Janez", "Starina", 2000, "2304") b = knjiznicaRaz.Član_3("Mojca", "Mavko", 2001, "4377") c = b c.ime = "Andreja" d = b.Kopija() d.ime = "Tadeja" print("Član a") a.Izpis() print("Član b:\n" + b.Opis()) print("Član c:") print(c) print("Član d") d.Izpis()
Razred Datum • Denimo, da v naših programih pogosto delamo z datumi. • Zato bomo sestavili ustrezni razred • Načrt razreda: • Podatki • dan (število) • mesec (izbira: število ali pa niz) • Leto (število) • Metode • Konstruktorji • Izpiši • Povečaj za 1 dan • Je datum smiselen • Je leto prestopno • Nov datum za toliko in toliko dni pred/za danim datumom • Dan v tednu • ...
Datum – podatki in konstruktor class Datum : def __init__(self, dan = 1, mesec = "januar", leto = 2000) # privzeti datum je torej 1.1.2000 self.leto = leto self.mesec = m self.dan = d
Prestopno • Zanima nas, ali je leto prestopno defjePrestopno(self) : le = self.leto if le % 4 != 0 : returnFalse if le % 400 == 0 : returnTrue if le % 100 == 0 : returnFalse returnTrue Drugačen način pisanja
Uporaba razreda • Ugotovi, če je letošnje leto prestopno! importMojiRazredi danes = MojiRazredi.Datum(4, 12, 2009) ifdanes.jePrestopno() : print("Je prestopno leto") else : print("Ni prestopno leto")
Dodaj en dan defpovecajZaEnDan(self) : self.dan = self.dan + 1 if (self.dan < 29) : return if (self.dan == 29 andself.mesec != "februar") : return if (self.dan == 29 andself.mesec == "februar" and self.JePrestopno()) : return # lahko nehamo, mesec in leto sta ok meseciPo30 = ["april","junij","september", "november"] if (self.dan == 31) : if mesec in meseciPo30 : mesec = mesec + 1 if (mesec == 13) : mesec = 1 leto = leto + 1 return # če je 32 dni, je zagotovo ... Smiselno je, da je tudi mesec int! Ponovno za "risalno desko" – razred spremnimo tako, da je mesec int. Dokončaj za vajo! Narobe, mesec je string
Sprememba razreda • Spremenimo razred Član, tako, da vodimo datum vpisa class Član : def __init__(self, i ='Ne vem', p = 'Ne vem', l = Datum(), v = 'Ne vem') : self.ime = i self.priimek = p self.datumVpisa = l self.vpisnaStevilka = v y = Član() y Ime: "Ne vem" Priimek: "Ne vem" datumVpisa vpisnaStevilka: "Ne vem" dan: 1 mesec: 1 leto: 2000
Sprememba razreda class Član: def __init__(self, i ='Ne vem', p = 'Ne vem', l = '2009', v = 'Ni določena') : self.ime = i self.priimek = p self.letoVpisa = l self.vpisnaStevilka = v def inicialke(self) : return self.ime[0] + ' ' + self.priimek[0] defKopija() : nov = Član(self.ime,self.priimek, self.datumVpisa.Kopija(), self.vpisnaStevilka) return nov defIzpis() : print("Clan:\n" + self.inicialke + ": " + self.ime + " " + self.priimek+ " " + self.datumVpisa.OpisDat() + " (" + self.vpisnaStevilka+ ")"); Metoda Kopija iz razreda Datum! Nima zveze z metodo Kopija iz razreda Član Metoda OpisDat iz razreda Datum! Metoda inicialke iz razreda Član!
Način programiranja • Seveda zaradi spremembe uporaba v drugih programih, kjer je na primer pisalo if (enClan.letoVpisa > drugClan.letoVpisa) : … • ne deluje več! • Kako popraviti? • if enClan.datumVpisa.leto > drugClan.datumVpisa.leto: … • Torej smo s spremembo razreda “pokvarili” stare programe • Ampak rekli smo, da se z uporabo OOP skušamo temu izogniti • Problem je v tem, ker nismo upoštevali “pravil lepega obnašanja” in na objekte vrste Član nismo gledali kot na “črne škatle”
A če že v prvotnem razredu class Član : def __init__(self, i ='Ne vem', p = 'Ne vem', l = '2009', v = 'Ni določena') : self.ime = i self.priimek = p self.letoVpisa = l self.vpisnaStevilka = v defVrniLetoVpisa() : return self.letoVpisa Metoda, ki pove leto vpisa In potem uporabniki lahko razred uporabljajo kot “črno škatlo”. In že v prvotnem programu bi napisali if enClan.VrniLetoVpisa() > drugClan.VrniLetoVpisa() :
Ob spremembi razreda Član • Le metodo def VrniLetoVpisa() : return self.letoVpisa • zamenjamo z def VrniLetoVpisa() : return self.datumVpisa.leto Enak klic, enak tip rezultata – spremembe v uporabniških programih niso potrebne