Írunk egy Person osztályt. Minden embernek lesz neve és titulusa, a __repr__ függvénnyel pedig megszólítjuk. A Knight osztály a Person leszármazottja. Minden lovag egyben ember is, de a megszólításuk egyedi. Leszármaztatni akkor tudunk, ha az ősosztályunk is az object leszármazottja. A leszármazott örökli az ősosztály összes tagváltozóját és metódusát.
class Person(object):
def __init__(self, name, title):
self.name = name
self.title = title
def __repr__(self):
return self.title + " " + self.name
class Knight(Person):
def __init__(self, name):
super(Knight, self).__init__(name, 'Sir')
varga = Person('Varga', 'Mr')
launcelot = Knight('Launcelot')
print varga
print launcelot
A leszármazott osztályban definiálhatunk új tagváltozókat is. Például legyen minden lovagnak egy opcionális epitheton ornansa!
class Person(object):
def __init__(self, name, title):
self.name = name
self.title = title
def __repr__(self):
return self.title + " " + self.name
class Knight(Person):
def __init__(self, name, eo=""):
super(Knight, self).__init__(name, 'Sir')
self.eo = eo
launcelot = Knight('Launcelot', 'the brave')
launcelot
Minden lovag megérdemli, hogy a neve mellé az állandó jezőjét is hozzáfűzzük. Ehhez felüldefiniáljuk a __repr__ metódust. Azonos nevű metódusok esetén mindig a leszármazottban definiált élvez elsőbbséget és hívódik meg.
class Person(object):
def __init__(self, name, title):
self.name = name
self.title = title
def __repr__(self):
return self.title + " " + self.name
class Knight(Person):
def __init__(self, name, eo=""):
super(Knight, self).__init__(name, 'Sir')
self.eo = eo
def __repr__(self):
if len(self.eo) > 0:
return self.title + " " + self.name + ", " + self.eo
else:
return super(Knight, self).__repr__()
launcelot = Knight('Launcelot', 'the brave')
black = Knight('Black')
robin = Knight('Robin', 'the Not-quite-so-brave-as-Sir-Launcelot')
print launcelot
print black
print robin
Van mód arra is, hogy bizonyos változókat osztályszinten definiáljunk. Ilyen például a lovagok "Sir" megszólítása.
Hogy ne essen egybe a Person title változójával, nevezzük special_title-nek.
Ahhoz, hogy az osztályszintű változót elérjük, a Knight.special_title-ra kell hivatkozni, de bármelyik példány .special_title változója is erre mutat.
class Person(object):
def __init__(self, name, title):
self.name = name
self.title = title
def __repr__(self):
return self.title + " " + self.name
class Knight(Person):
special_title = 'Sir'
def __init__(self, name, eo=""):
super(Knight, self).__init__(name, "")
self.eo = eo
def __repr__(self):
return Knight.special_title + " " + self.name + ", " + self.eo
launcelot = Knight('Launcelot', 'the brave')
robin = Knight('Robin', 'the Not-quite-so-brave-as-Sir-Launcelot')
print launcelot
print robin
print robin.special_title, launcelot.special_title, Knight.special_title
Megjegyezzük, hogy az öröklési lánc tetszőlegesen hosszú lehet, illetve lehet egyszerre több osztályból örökölni.
Vannak olyan esetek, amikor a kód hibába ütközik. Ilyenkor egy Exception típusú objektumot dob (emel) a python.
Ekkor
Kivéve, ha
try:
...
except ... :
...
blokkalEgy Exceptiont bármikor el lehet kapni, akármennyi fügvényhívást túlél. Nézzünk egy példát! Most mi magunk hívjuk elő a hibát (raise), de egyben le is kezeljük.
try:
raise Exception('spam', 'eggs')
except Exception as inst:
print type(inst)
print inst.args
print inst
x, y = inst.args
print 'x =', x
print 'y =', y
Most pedig lekezelünk egy nem mesterségesen létrehozott kivételt.
try:
str(5) + 5
except TypeError as inst:
print type(inst)
print inst.args
print inst
Természetes környezetben. Ha a felhasználó nem egész számot ad, nem tudja azzá konvertálni, így hibát jelez, mi viszont ezt lekezeljük.
while True:
try:
x = int(raw_input("Please enter a number: "))
break
except ValueError:
print "Oops! That was no valid number. Try again..."
print 2*x
Nézzük meg hogy hol történt a kivétel dobása (raise) és és hol az elkapása.
def f(x):
return x + 5 # nem jó ha x egy string
def g(x):
return x + x # ez jó int-re és str-re is
x = "5"
y = g(x)
z = f(y)
Írhatunk saját kivétel osztályt is, ezt arra tudjuk használni, hogy egyedi hibákat jelezzünk vele.
Csupán az Exception beépített osztályból kell öröklődni (opcionálisan mást is lehet bele rakni).
class KnightException(Exception):
pass
lancelot = Person("Lancelot", "Mr")
x = lancelot.__repr__()
if x[:3] != "Sir":
raise KnightException("a", "b")
Láttuk, hogy a for i in L nem csak akkor működik, ha L lista.
Pontosan mely objektumok állhatnak a for ... in után?
A for meghívja az iter() függvényt, mely egy iterálható objektumot ad vissza, melyre definiálva van egy next() függvény, amely minden meghívására visszaadja az objektum egy elemét. Ha a next() nem talál több elemet, egy StopIteration kivételt dob.
Iterálható az az objektum, aminek van next metódusa.
for ... in után az állhat, aminek van __iter__ metódusa, ami iterálható objektumot ad vissza.
Ezek speciális metódusok!
r = range(3)
it = iter(r)
next(it)
print next(it)
print next(it)
next(it)
Tetszőleges, általunk definiált osztályhoz is adható iterátor tulajdonság. Először is szükség van egy __iter__ függvényre, ami egy olyan objektummal tér vissza, ami iterálható. Az iterálható objekcumok (list, set, tuple) definiálnak egy next() metódust, ami sorban visszaadja az elemeket.
Ha kifogyott, akkor StopIteration kivételt emel.
class Person(object):
def __init__(self, name, title=""):
self.name = name
self.title = title
def __repr__(self):
return self.title + " " + self.name
class Knight(Person):
title = 'Sir'
searching_for = 'The Holy Grail'
def __init__(self, name, eo):
super(Knight, self).__init__(name)
self.eo = eo
def __repr__(self):
return Knight.title + " " + self.name + ", " + self.eo
class Group(object):
def __init__(self, name, persons):
self.persons = persons
self.name = name
def __iter__(self):
self.index = 0
return self
def next(self):
if self.index >= len(self.persons):
raise StopIteration # dobunk egy kivetelt
self.index += 1
return self.persons[self.index - 1]
kotrt = Group('Knights of The Round Table',
[Knight('Launcelot', 'the brave'),
Knight('Galahad', 'the pure'),
Knight('Bedevere', 'the wise'),
Knight('Robin', 'the Not-quite-so-brave-as-Sir-Launcelot')])
for knight in kotrt:
print knight
Vigyázzunk, hogy az indexet vissza kell állítani, különben csak egyszer tudunk iterálni! Persze mindezt megoldhattuk volna egyszerűbben.
class Person(object):
def __init__(self, name, title=""):
self.name = name
self.title = title
def __repr__(self):
return self.title + " " + self.name
class Knight(Person):
title = 'Sir'
searching_for = 'The Holy Grail'
def __init__(self, name, eo):
super(Knight, self).__init__(name)
self.eo = eo
def __repr__(self):
return Knight.title + " " + self.name + ", " + self.eo
class Group:
def __init__(self, name, persons):
self.persons = persons
self.name = name
def __iter__(self):
return iter(self.persons)
kotrt = Group('Knights of The Round Table',
[Knight('Launcelot', 'the brave'),
Knight('Galahad', 'the pure'),
Knight('Bedevere', 'the wise'),
Knight('Robin', 'the Not-quite-so-brave-as-Sir-Launcelot')])
for knight in kotrt:
print knight