Objektumorientált programozás II.

Öröklődés

Írunk egy Person osztályt. Minden embernek lesz neve és titulusa, majd a __repr__ megszólítjuk az illetőt. 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ának összes tagváltozóját és metódusát.

In [3]:
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')
        
launcelot = Knight('Launcelot')
print launcelot
Sir Launcelot

A leszármazott osztályban definiálhatunk új tagváltozókat is. Például legyen minden lovagnak egy epitheton ornansa!

In [4]:
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')
print launcelot
Sir Launcelot

Minden lovag megérdemli, hogy a neve mellé az állandó jezőjét is hozzáfűzzük. Ehhez átdefiniá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.

In [5]:
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):
        return self.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
Sir Launcelot, the brave
Sir Robin, the Not-quite-so-brave-as-Sir-Launcelot

Statikus változók

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. Az osztályszinten definiált title azonban egybeesik a Person title változójával így a lovagok esetében a self.title erre a változóra mutat. Ahhoz, hogy az osztályszintű változót elérjük, a Knight.title-re kell hivatkozni. A searching_for azonban már úgy viselkedik, ahogyan szeretnénk.

In [6]:
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
         
launcelot = Knight('Launcelot', 'the brave')
robin = Knight('Robin', 'the Not-quite-so-brave-as-Sir-Launcelot')
print launcelot
print robin
print launcelot.searching_for
print robin.searching_for
Sir Launcelot, the brave
Sir Robin, the Not-quite-so-brave-as-Sir-Launcelot
The Holy Grail
The Holy Grail

Megjegyezzük, hogy az öröklési lánc tetszőlegesen hosszú lehet, illetve lehet egyszerre több osztálytól örökölni.

Iterálható objektumok

Láttuk, hogy a for i in L nem csak akkor működik, ha L lista. Tetszőleges, általunk definiált objektumra is megoldható. 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.

In [7]:
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
        self.index = -1
    def __iter__(self):
        return self
    def next(self):
        if self.index == len(self.persons) - 1:
            self.index = -1
            raise StopIteration
        self.index = self.index + 1
        return self.persons[self.index]
        
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
for knight in kotrt:
    print knight    
Sir Launcelot, the brave
Sir Galahad, the pure
Sir Bedevere, the wise
Sir Robin, the Not-quite-so-brave-as-Sir-Launcelot
Sir Launcelot, the brave
Sir Galahad, the pure
Sir Bedevere, the wise
Sir Robin, the Not-quite-so-brave-as-Sir-Launcelot

Vigyázzunk, hogy az indexet vissza kell állítani, különben csak egyszer tudunk iterálni! Persze mindezt megoldhattuk volna egyszerűbben.

In [8]:
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
        self.index = -1
    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
Sir Launcelot, the brave
Sir Galahad, the pure
Sir Bedevere, the wise
Sir Robin, the Not-quite-so-brave-as-Sir-Launcelot

Overload

Lehetőségünk van függvényeket, illetve metódusokat többféle módon meghívni. Ismerjük, hogy hogyan lehet default paraméterértéket megadni. Írjunk függvényt, ami felveszi a rendelést! Ha nem említjük, hogy mennyit kérünk, akkor úgy érti, hogy egyet.

In [9]:
def order(name, quantity=1):
    print name, quantity
order('eggs', 2)
order('spam')
eggs 2
spam 1

Most megoldjuk, hogy bármennyi különböző terméket rendelhessünk.

In [10]:
def order(name, *args):
    print name
    for a in args:
        print a
order('sausage', 'bacon', 'egg', 'spam')        
sausage
bacon
egg
spam

Ha különböző mennyiségeket akarunk rendelni, akkor másik módszerhez kell folyamodni.

In [11]:
def order(*args, **kwargs):
    for k in kwargs:
        print k, kwargs[k]
order('egg', 'sausage', spam=4)        
spam 4

Röviden a kivételekről

Vannak olyan esetek, amikor a kód hibába ütközik. Ilyenkor egy Exception típusú objektumot dob a python. Ha senki nem kapja el, akkor a kód megáll futni. Egy 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, de egyben le is kezeljük.

In [12]:
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
<type 'exceptions.Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

Most pedig lekezelünk egy nem mesterségesen létrehozott kivételt.

In [ ]:
try:
   str(5) + 5
except TypeError as inst:
   print type(inst)
   print inst.args     
   print inst           
<type 'exceptions.TypeError'>
("cannot concatenate 'str' and 'int' objects",)
cannot concatenate 'str' and 'int' objects

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.

In [ ]:
while True:
    try:
        x = int(raw_input("Please enter a number: "))
        break
    except ValueError:
        print "Oops!  That was no valid number.  Try again..."