Ügyességi játékok programozása
Pythonnal és Pygame-mel

Chapter 12: Bevezetés az osztályok használatába

Zsákoljuk be a hasonló változókat, és keltsük életre őket!

12.1 Miért tanuljunk az osztályokról?

Videó: Mire jók az osztályok?

Minden kalandjátékban a karakternek szüksége van adatra: név, hely, erő, felemelik a kezüket, merre vették az irányt, stb. Plussz, a karakterek még dolgokat is csinálnak. Futnak, ugranak, ütnek, és beszélnek.

A mi Python kódunk, ami ezt az adatot tárolja, így kéne kinézzen:

name = "Link"
sex = "Male"
max_hit_points = 50
current_hit_points = 50

Annak rendje szerint, hogy tegyünk bármit is a karakterrel ,szükséges átadni ezt az adatot egy függvénynek:

def display_character(name, sex, max_hit_points, current_hit_points):
    print (name, sex, max_hit_points, current_hit_points)

Most már el tudod képzelni, hogyan kell nekivágni egy olyan programnak, ami változókat tárol mindenféle karakterekről, szörnyekről, tárgyakról a játékhoz. Azután létre kell hozni olyan függvényeket, amik ezeket a tárgyakat kezelik. Tonnányi adaton kell átgázolni. Hirtelen ez már nem is tűnik szórakoztatónak!

Na, várj csak, lesz ez még rosszabb! Ahogy a játék egyre nagyobb lesz, újabb mezőket kell megadnunk, hogy leírjuk a karakterünket. Ez esetben a max_speed tulajdonságot adtuk hozzá:

name = "Link"
sex = "Male"
max_hit_points = 50
current_hit_points = 50
max_speed = 10

def display_character(name, sex, max_hit_points, current_hit_points, max_speed):
    print (name, sex, max_hit_points, current_hit_points)

A fenti példában mindössze egy függvény van. De egy nagy videójátékban, többszáz függvényt kell kezelnünk, amik a főkarakterrel bánnak. Egy új mező beillesztése azt kívánja meg tőlünk, hogy átrágjuk magunkat az összes függvényen, és hozzáadjuk a paraméter listájához. Na ez jó sok munka. És talán a max_speed-t más típusú karakterekhez is hozzá kell adnunk, mint amilyen egy szörny. Ehhez jobb módszert kell találni. Valahogyan, a programunknak szüksége volna egyben kezelnie az adatmezőket, és akkor könnyebb lenne az egésszel bánni.

12.2 Egyszerű osztályok létrehozása

Videó: Egyszerű osztályok létrehozása

Sokkal jobb módja a sok adat kezelésének, ha definiálunk egy szerkezetet, ami az összes adatot kezelni fogja. Azután már adhatunk ennek a csoportba szedett információnak nevet, olyanokat, mint Character vagy Address. Ezt könnyen megtehetjük a Pythonnal és más modern nyelvvel, ha osztályt használunk.

Például, egy osztály egy karaktert reprezentál a játékban:

class Character():
    name = "Link"
    sex = "Male"
    max_hit_points = 50
    current_hit_points = 50
    max_speed = 10
    armor_amount = 8

Itt egy másik gyakori példa arra, hogy hogyan tartsa egy cím osztály, összes mezőjét egy helyen:

class Address():
    name = ""
    line1 = ""
    line2 = ""
    city = ""
    state = ""
    zip = ""

A fenti kódban, az Address az osztály neve. A változók az osztályban, mint amilyen a name, city azok, amiket attribútumoknak vagy mezőknek hívunk. (Jegyezd meg, hogy a hasonlóságokat és különbségeket az osztály és a függvény definiálásakor.)

Más függvényhez és változóhoz képest az osztály neve nagybetűvel kezdődik. Lehetőség van arra, hogy kisbetűvel kezdjük a nevét, de az egy rossz gyakorlat.

Ahhoz, hogy jobban elképzelhessük az osztályokat és azt, ahogyan egymáshoz kapcsolódnak, a programozók gyakran készítenek diagramokat. Az ábra, ami az Address osztályhoz van, itt látható: 12.1. Figyeld meg, hogy az osztály neve van legfelül, azután pedig az attribútumok vannak felsorolva. Jobbra, minden attribútumtól van az adattípus arról, hogy szöveg vagy egész.

fig.address_example_3
Figure 12.1: Osztály diagram

Az osztály kód definiálja az osztályt, de nem hoz létre egyből példányt. A kód megmondja a számítógépnek, hogy milyen mezői vannak, és azoknak mi a kezdő értéke. Ennek ellenére még nincs semmi sem megcímezve. Készíthetünk úgy osztályt, anélkül, hogy bármivel is hivatkoznánk rá, ahogyan függvényt is csinálhatunk, anélkül, hogy hívnánk. Ahhoz, hogy lásd, hogyan hozunk létre egy osztályt és mezőket, nézd meg a példát alább:

# létrehozunk egy címet
homeAddress = Address()

# töltsük ki a mezőket
homeAddress.name = "John Smith"
homeAddress.line1 = "701 N. C Street"
homeAddress.line2 = "Carver Science Building"
homeAddress.city = "Indianola"
homeAddress.state = "IA"
homeAddress.zip = "50125"

A cím osztálynak egy példányát hoztuk létre, a második sorban. Figyeld meg, hogyan használtuk az Address osztály nevét: zárójeleket tettünk utána. A változó neve bármi lehet, ami a szokásos névadási normáknak megfelel.

Ahhoz, hogy a mezőket az osztályba tegyük, a program egy pont operátort használ. Ez választja el a homeAddress-t és a mezőnevet. Nézd meg, ahogyan az 5-10-s sorok használják ezt az operátort.

Egy gyakori hiba, az osztályokkal való munka során, hogy elfelejtik specifikálni melyik példányával akarnak dolgozni az osztályból. Ha csak egy cím lett létrehozva, akkor természetes, hogy a számítógép tudni fogja melyik az. Ez egy másik eset. Nézd a következő példát:

class Address():
    name = ""
    line1 = ""
    line2 = ""
    city = ""
    state = ""
    zip = ""

# cím létrehozása
my_address = Address()

# Figyelem! Ez nem egy cím neve! 
name = "Dr. Craven"

# Ez sem a cím neve! 
Address.name = "Dr. Craven"

# Ez a helyes:
my_address.name = "Dr. Craven"

Másik címet készítünk és az összes mezőt használjuk. Nézd meg az alábbi példát:

class Address():
    name = ""
    line1 = ""
    line2 = ""
    city = ""
    state = ""
    zip = ""

# Cím létrehozása
homeAddress = Address()

# A cím mezőinek feltöltése
homeAddress.name = "John Smith"
homeAddress.line1 = "701 N. C Street"
homeAddress.line2 = "Carver Science Building"
homeAddress.city = "Indianola"
homeAddress.state = "IA"
homeAddress.zip = "50125"

# készítünk egy másik címet
vacationHomeAddress = Address()

# ennek a mezőit is feltöltjük
vacationHomeAddress.name = "John Smith"
vacationHomeAddress.line1 = "1122 Main Street"
vacationHomeAddress.line2 = ""
vacationHomeAddress.city = "Panama City Beach"
vacationHomeAddress.state = "FL"
vacationHomeAddress.zip = "32407"

print("The client's main home is in " + homeAddress.city)
print("His vacation home is in " + vacationHomeAddress.city)

A tizedik sor hozza létre az első példányát az Address osztálynak; a huszonegyedik sor pedig a második példányt. A homeAddress változó az első példányra mutat, a vacationHomeAddress változó pedig a másodikra.

A 24-29 sor tölti fel adattal a mezőket az új osztály példánynál. A 31-s sor kinyomtatja a várost a lakóhelyből, mivel a homeAddress hivatkozik rá a pont operátor előtt. A 32-s sor a vakáció alatti cím, amire a vacationHomeAddress hivatkozik a pont operátor előtt.

A példában az Address-t osztálynak hívják, mivel ez definiálja az új osztályozását az adat objektumnak. A változók a homeAddress és a vacationHomeAddress, melyek objektumok, mivel az aktuális példányra vonatkoznak, az Address osztályban. Egy egyszerű objektum definíció ugyanaz, mint egy osztály példány. Mint ahogyan Bob és Nancy az Emberiség osztályának példányai.

Azzal, hogy használjuk www.pythontutor.com-t, képesek vagyunk elképzelni a kódot (lásd lentébb). Három változó van játékban. Az egyik az Address osztály definícióra mutat. A másik két változó viszont két másik cím objektumra mutat, és azok adataira.

fig.two_addresses
Figure 12.2: Két cím

Egy osztályba, ha sok adatmezőt teszünk, akkor könnyű azt egy funkcióba beledobálni. A lenti kódban, a függvény paraméterként kap egy címet, és kiírja azt a képernyőre. Nem szükséges minden cím mező paraméterét megadni a függvénynek.

# Kiír egy címet a képernyőre
def printAddress(address):
    print(address.name)
    # ha van egy line1 a címben, akkor kiírja
    if( len(address.line1) > 0 ):
        print (address.line1)
    # ha van egy line2 a címben, akkor kiírja
    if( len(address.line2) > 0 ):
        print( address.line2 )
    print( address.city+", "+address.state+" "+address.zip )

printAddress( homeAddress )
print()
printAddress( vacationHomeAddress )

12.3 Eljárás hozzáadása osztályhoz

Videó: Eljárások

Az attribútumokon túl az osztályok rendelkezhetnek eljárásokkal vagy metódusokkal. Az eljárás egy függvény, ami az osztályon belül létezik. A korábbi példát kibővítve, egy Dog(kutya) osztályt veszünk alapul, melyhez hozzáadunk egy metódust, mégpedig kutyaugatás eljárást.

class Dog():
    age = 0
    name = ""
    weight = 0

    def bark(self):
        print("Woof")

Az eljárás definíciója a 6-7-s sorban van. A metódusok definíciója egy osztályon belül eléggé hasonlít egy függvény definíciójára. A nagy különbség a self paraméter a hatodik sorban. Az első paraméter bármely osztályon belüli metódusnál a self kell legyen. Ez akkor is szükséges, ha a metódus nem is használja.

Itt vannak a fontos dolgok, amiket fejben kell tartani, amikor eljárást készítünk egy osztályhoz:

Az eljárások meghívása hasonlóan történik, vagyis az objektum attribútumaira hivatkozunk. Lásd az alábbi kódot:

myDog = Dog()

myDog.name = "Spot"
myDog.weight = 20
myDog.age = 3

myDog.bark()

Az első sor a kutyát alkotja meg. A 3-5-dik sor feltölti az objektumot. A hetedik sor, meghívja a bark(ugat) függvényt. Megjegyzendő, hogy az ugatás függvénynek egy paramétere van, a self, a hívása során ez nem megy át semmin. Ez azért van, mivel az első paraméter a kutya objektumre magára vonatkozik. A színfalak mögött, a Python egy ilyen hívást futtat le:

# A példa valójában nem legális!
Dog.bark(myDog)

Ha a bark függvény számára szükséges bármilyen referencia megadása az attribútomhoz, akkor az a self-t fogja referencia változóként használni. Például, megváltoztathatjuk a kutya osztályt úgyhogy akkor, amikor a kutya ugat, ki fogja írni a kutya nevét is. A lenti kódban, a név attribútum használja a pont operátort, és a self referenciát.

    def bark(self):
        print( "Woof says", self.name )

Attribútumok a melléknevek, és az eljárások az igék. Az osztály lerajzolása így néz ki: 12.3.

fig.dog_2_1
Figure 12.3: Kutya osztály

12.3.1 Példa: Labda osztály

Ez a példa kód használható Python/Pygame alatt kirajzolni egy labdát. Az összes paraméter az osztályban könnyebbé teszi az adatkezelést. A diagram a Labda osztályhoz alább látható: 12.4.

fig.ball_2_1
Figure 12.4: Labda osztály
class Ball():
    # --- osztály attribútumok ---
    # labda helyzete
    x = 0
    y = 0

    # labda vektorja
    change_x = 0
    change_y = 0

    # labda mérete
    size = 10

    # labda színe
    color = [255,255,255]

	# --- osztály eljárás függvénye ---
    def move(self):
        self.x += self.change_x
        self.y += self.change_y

    def draw(self, screen):
        pygame.draw.circle(screen, self.color, [self.x, self.y], self.size )

Alább van a kód, ami majd a főprogramba kell, ami majd megalkotja a labdát, és feltölti az attribútumokat:

theBall = Ball()
theBall.x = 100
theBall.y = 100
theBall.change_x = 2
theBall.change_y = 1
theBall.color = [255,0,0]

Ez a kód a főciklusba való, hogy mozgassa és kirajzolja a labdát:

theBall.move()
theBall.draw(screen)

12.4 Referenciák

Videó: Referenciák

Ezen a részen elválasztjuk az igazi programozót, attól, aki csak szeretne programozó lenni: az osztály referenciák megértése. Vess egy pillantást a következő kódra:

class Person:
    name = ""
    money = 0

bob = Person()
bob.name = "Bob"
bob.money = 100

nancy = Person()
nancy.name = "Nancy"

print(bob.name, "has", bob.money, "dollars.")
print(nancy.name, "has", nancy.money, "dollars.")

A fenti kód két Személy példányát kreálja, és használja a www.pythontutor.com, hogy el tudjuk képzelni a két osztályt az ábrán 12.5.

fig.two_persons
Figure 12.5: Két személy

A fenti kódban semmi új nincs. De a lentiben már annál inkább:

class Person:
    name = ""
    money = 0

bob = Person()
bob.name = "Bob"
bob.money = 100

nancy = bob
nancy.name = "Nancy"

print(bob.name, "has", bob.money, "dollars.")
print(nancy.name, "has", nancy.money, "dollars.")

Látod már a különbséget a kilencedik sorban?

Gyakori félreértés, hogy amikor objektummal dolgozik valaki, azt gondolja, hogy a bob változó a Személy objektum. Ez nem az az eset. A bob változó csak a referenciája a Személy objektumnak. Ez pedig tárolja a memória címét annak, hogy hol van az objektum, és nem az objektumot magát.

Ha bob valójában az objektum lett volna, akkor a kilencedik sornak csinálnia kellett volna egy másolatot az objektumról és akkor már két objektum létezne. A program kimenete az kellene, hogy legyen, hogy Nancynak és Bobnak is 100 dollárja van. De amikor lefut, a program kimenete, a következő lesz ehelyett:

Nancy has 100 dollars.
Nancy has 100 dollars.

Amit bob tartalmaz az a referenciája az objektumnak. A referenciát emellett, lehet hívni címnek, mutatónak, vagy kezelőnek is. A referencia egy cím a számítógép memóriájában, ahol az objektum tárolva van. Ez a cím hexadecimális szám, melyet, ha kiíratunk, akkor valami ilyet kapunk, hogy 0x1e504. Amikor a kilences sor fut le, akkor a cím lesz lemásolva, ahelyett, hogy a teljes objektum címére lenne mutatva. Lásd az alábbi ábrát: 12.6.

fig.ref_example1
Figure 12.6: Osztály referenciák

Ezt is lefuttathatjuk a www.pythontutor.com-n, hogy lássuk, hogy mely változók mutatnak ugyanarra az objektumra.

fig.one_person
Figure 12.7: Egy személy, két mutató

12.4.1 Függvények és referenciák

Vess egy pillantást a lenti kódra. Az első sor létre fog hozni egy függvényt, ami egy számot kap paraméterként. A money egy változó, ami egy adatmásolatot tárol, amikor arra van szükség. Ha 100-t adunk ehhez a számhoz, akkor nem változik meg a szám a bob.money-ban, a tizedik sorban. Így a kiíratott eredmény a tizenharmadik sorban 100-t fog megjeleníteni, s nem 200-t.

def giveMoney1(money):
    money += 100

class Person:
    name = ""
    money = 0

bob = Person()
bob.name = "Bob"
bob.money = 100

giveMoney1(bob.money)
print(bob.money)

Ha lefuttatjuk a PythonTutor-n, akkor láthatjuk, hogy két példányunk van a money változóból. Az egyik egy másolat és helyi változója a giveMoney1 függvénynek.

fig.function_references_1
Figure 12.8: Függvény referenciák

Nézd meg a lenti kiegészítő kódot. Ez a kód azt fogja okozni, hogy a bob.money megnövekszik és a print parancsunk 200-t fog kiíratni.

def giveMoney2(person):
    person.money += 100

giveMoney2(bob)
print(bob.money)

Miért lehetséges ez? Mivel a person tartalmazza az objektum memória címének másolatát, és nem az aktuális objektumot magát. Lehet erre úgy is gondolni, mint egy bankszámla számra. Szóval, ha lemásoljuk a bankszámla számot, és teszünk rá 100 dollárt, akkor Bob számlája nőni fog.

fig.function_references_2
Figure 12.9: Függvény referenciák

A tömb változó hasonlóan működik. Egy függvény ami tömb(lista) változót használ paraméternek, és módosítja a tömbben az értékeket, módosítani fogja ugyanazt a tömböt, amit a hívó kód alkotott. A tömb címe le van másolva, nem az egész tömb.

12.4.2 Kérdések áttekintése

  1. Készíts egy osztályt, ami Macskának nevezel el. Adj neki olyan attribútumokat, hogy név, szín, súly. Adj hozzá egy eljárást, amit nyávogásnak nevezel el.
  2. Készíts egy példányt a macska osztályból, adj értéket az attribútumoknak és hívd meg a nyávogás eljárást.
  3. Készíts egy osztályt, amit Szörnynek nevezel el. Adj neki név attribútumot és egy egész változót életerőnek. Készíts egy eljárást, amit életCsökkennek hívsz, aminek lesz egy paramétere, a nagyság, és annyival fog csökkenni az életerő, amennyi ez az érték. Ebben az eljárásban, legyen egy kiírás, ha az állat meghal, mikor az életereje nulla alá kerül.

12.5 Konstruktorok

Videó: Konstruktorok

Van egy szörnyű probléma a mi kutya osztályunkkal, amit lejjebb listáztunk ki. Amikor létrehozunk egy kutyát, akkor az alapértelmezett kutyának nincs neve. A kutyáknak lennie kell nevüknek! Nem engedhetjük, hogy a kutyák úgy szülessenek meg, hogy nem kapnak nevet! Mégis, az alábbi kódban egy olyan kutyánk lesz, aminek nem lesz neve sosem.

class Dog()
    name = ""

myDog = Dog()

A Python nem akarhatja, hogy ez történjen. Ezért van az, hogy a Python osztálynak van egy speciális függvénye, amit bármikor meghívhatunk, egy osztály esetén. Azáltal, hogy egy konstruktornak nevezett függvényt használunk, a programozó képes kódot adni a példányhoz minden alkalommal, automatikusan, amikor az osztály példánya létrejön. Lásd az alábbi konstruktor példát:

class Dog():
    name=""

    # Konstruktor
    # Akkor lesz meghívva, amikor egy ilyen típusú objektumot hoznak létre
    def __init__(self):
        print("A new dog is born!")

# ez hozza létre a kutyát
myDog = Dog()

A konstruktor a hatodik sorban indul el. Ezt el kell nevezni __init__-tel. Kettő aláhúzás van az __init__ előtt és utána is. Gyakori hiba, hogy csak egyet használnak.

A konstruktor felveszi a self értékét, az első paraméterétm, mint bármely más eljárás. Amikor a program lefut, akkor, ki fogja írni, hogy
A new dog is born!
Amikor a kutya objektumot megalkutjok a tizedik sorban, akkor az __init__ függvény automatikusan meghívja és kiíratja ezt az üzenetet.

Egy konstruktort lehet használni arra, hogy egy objektumot bevezessünk és megadjuk az értéket. A példa a kutya osztály, fentebb, szintén lehetővé teszi, hogy a név attribútomot üresen hagyjuk miután létrehoztuk a kutya objektumunkat. Hogyan tudnánk ezt megakadályozni? Sok objektumnak van szüksége arra, hogy értéket vegyen fel, amikor létre hozzák. A konstruktort tudjuk erre is használni. Lássuk az alábbi kódot:

class Dog():
    name = ""

    # Konstruktor
    # Akkor hívja meg, amikor ilyen típust hoz létre
    def __init__(self, newName):
        self.name = newName

# ezzel hozzuk létre a kutyát
myDog = Dog("Spot")

# írassuk ki a kutya nevét, ellenőrzésképpen 
print(myDog.name)

# ez a sor egy hibát küld, mivel
# nem lett név adva
herDog = Dog()

A hatodik sorban a konstruktor függvényben most már van egy új paraméterünk , amit newName-nek nveztünk el. Ennek a paraméternek az értéke fogja felvenni a hetedik sorban megadott kutya osztály név értékét. Most már nem hozhatunk létre kutya osztályt név nélkül. A tizenhetedik sorban ezt ellenőrízzük, és erre kapunk is egy nagy kövér hibaüzenetet. Gyakori hiba, hogy ugyanúgy nevezzük el az __init__ függvény paraméterét, és azt gondoljuk, hogy majd szinkronban lesz az osztály paraméterével. Ez azonban sosem történik meg.

A következő példában két különböző változó van, amit name-nek hívnak, Ezeket kiíratjuk a 8-s és 10-s sorban. Az első name változó úgy jön létre, mint egy eljárás paraméter a hatodik sorban. Az eljárás változó el is tűnik, amint az eljárás lefutott. A második name változó attribútumként lett létrehozva a második sorban. Ez egy teljesen más változó, mint amit a hatodik sorban hoztunk létre. A self.name változó utal arra az attribútumra, mely a kutya osztály példányáé. Az attribútum addig fog létezni, amíg a kutya osztály példánya.

class Dog():
    name = "Rover"

    # Konstruktor
    # ez lesz meghívva, amikor egy ilyen típust hozunk létre
    def __init__(self, name):
        # ez kiírja, hogy "Rover"
        print(self.name)
        # ez meg kiírja, hogy "Spot"
        print(name)

# ez alakítja meg a kutyát
myDog = Dog("Spot")

12.5.1 Kérdések áttekintése

  1. Az osztályok nevei kicsi vagy nagybetűvel kell, hogy kezdődjenek?
  2. Az eljárások nevei kicsi vagy nagybetűvel kell, hogy kezdődjenek?
  3. Az attribútumok nevei kis vagy nagybetűvel kéne, hogy kezdődjenek?
  4. Mit kell először listázni egy osztályban, az attribútumot vagy eljárást?
  5. Milyen más elnevezések vannak a referenciára?
  6. Milyen más elnevezés van még a példány változóra?
  7. Mi a neve a példánynak egy osztályban?
  8. Hozz létre egy osztályt Csillag néven, ami kiírja majd, hogy "Csillag születik", mindig amikor létrehozzák.
  9. Hozz létre egy Szörny osztályt, az életerő és a név attribútumokkal. Adj egy konstruktort az osztályhoz, ami az életerőt és a nevet feltölti adatokkal.

12.6 Leszármazás, örökítés

Videó: Leszármazás

Másik erős jellemzője az osztályok használatának és az objektumoknak, hogy képesek örökítésre. Lehetőség van arra, hogy létrehozzunk egy osztályt, és minden attribútumot és eljárást leörökítsünk egy szülő osztályból.

Például egy program létrehozhat egy osztályt, Hajó néven, aminek minden attribútuma megvan, ami kell egy játékba.

class Boat():
    tonnage = 0
    name = ""
    isDocked = True

    def dock(self):
        if self.isDocked:
            print("You are already docked.")
        else:
            self.isDocked = True
            print("Docking")

    def undock(self):
        if not self.isDocked:
            print("You aren't docked.")
        else:
            self.isDocked = False
            print("Undocking")

Teszteljük le a kódunkat:

b = Boat()

b.dock()
b.undock()
b.undock()
b.dock()
b.dock()

A kimenetek:

You are already docked.
Undocking
You aren't docked.
Docking
You are already docked.

(Ha végignézed a videót, ami ehhez a részhez tartozik, akkor észre fogod venni, hogy a hajó osztály nem fut ebben a videóban. A kód fentebb ki lett javítva, de nem javítottam át a videóban. Emlékezz majd erre, nem számít, hogy milyen egyszerű a kód, és milyen tapasztalt a programozó, szóval teszteld a kódod, mielőtt leszállítod.)

A programunknak szüksége lesz egy tengeralattjáróra. A mi tengeralattjárónk bármit megtehet, amit egy hajó is megtehet, valamint még szükségünk lesz az alámerülésre is. Az örökítés nélkül csak két lehetőségünk van.

Szerencsére van egyszerűbb módja is. A programunkat létrehozhatjuk gyerek osztályokból amik öröklik az összes attribútumot és eljárást a szülő osztályból. A gyermek osztályhoz azután adhatunk további mezőket, és eljárásokat, ha még szükség van rá. Például:

class Submarine(Boat):
    def submerge(self):
        print("Submerge!")

Az első sor a fontos. Egyszerűen odatesszük a Hajót zárójelek közt az osztály deklarálásakor. És automatikusan fel is vette minden attribútumát és eljárását, amit az osztály tud. Ha frissítjük a Hajó osztályt, akkor a gyermek osztály, a Tengeralattjáró is automatikusan megkapja ezeket. A leszármazás ilyen egyszerű!

A következő kód le van rajzolva az 12.10 ábrán.

fig.person1
Figure 12.10: Osztály diagram
class Person():
    name = ""

class Employee(Person):
    job_title = ""

class Customer(Person):
    email = ""

johnSmith = Person()
johnSmith.name = "John Smith"

janeEmployee = Employee()
janeEmployee.name = "Jane Employee"
janeEmployee.job_title = "Web Developer"

bobCustomer = Customer()
bobCustomer.name = "Bob Customer"
bobCustomer.email = "send_me@spam.com"

A Személy elhelyezése zárójelek közé a negyedik sorban és a hetedikben, a programozó arra utasította a számítógépet, hogy a Személy legyen a szülő osztálya a Dolgozóknak és a Vásárlóknak. Ez lehetővé teszi a programnak, hogy név attribútumot feltölthessék a 14 és 18 sorban.

Az eljárások is leszármaztathatók. A lenti kód ki fogja íratni, hogy "Személy létrehozva", háromszor, mivel a munkás és a dolgozó osztályok leszármaztatottak a konstruktorral a szülő osztályból:

class Person():
    name = ""

    def __init__(self):
        print("Személy létrehozva")

class Employee(Person):
    job_title = ""

class Customer(Person):
    email = ""

johnSmith = Person()
janeEmployee = Employee()
bobCustomer = Customer()

Az eljárásokat felülírhatja egy leszármaztatott gyermek osztály, hogy más funkciót tarthasson fenn. A lenti kódban, a gyermek osztálynak megvan a saját konstruktorha, így a szülő osztály nem fog lefutni.

class Person():
    name = ""

    def __init__(self):
        print("Person created")

class Employee(Person):
    job_title = ""

    def __init__(self):
        print("Employee created")

class Customer(Person):
    email = ""

    def __init__(self):
        print("Customer created")

johnSmith = Person()
janeEmployee = Employee()
bobCustomer = Customer()

Ha a programozó arra vágyik, hogy mind a szülő és a gyermek osztály eljárást lefuttassa, akkor a gyermek kifejezetten meghívhatja a szülő eljárást:

class Person():
    name = ""

    def __init__(self):
        print("Person created")

class Employee(Person):
    job_title = ""

    def __init__(self):
        Person.__init__(self)
        print("Employee created")

class Customer(Person):
    email = ""

    def __init__(self):
        Person.__init__(self)
        print("Customer created")

johnSmith = Person()
janeEmployee = Employee()
bobCustomer = Customer()

12.6.1 Benne van és Van neki kapcsolata

Az osztályoknak két nagyobb típusa van kapcsolat szerint. Ezek vagy kapcsolatban vannak, vagy van nekik egy kapcsolatuk..

Egy szülő osztálynak mindig általánosabbnak kell lennie, mint a gyermek osztálynak. Ezt a fajta gyermek-szülő kapcsolatot nevezik benne van egy kapcsolatbannak. Például, egy Állat nevű szülő osztálynak lehet egy Kutya nevű gyermek osztálya. A Kutya osztálynak lehet egy Pudli nevű gyermek osztálya. Másik példa, a delfin egy emlős (benne van az emlősök osztályában-a ford.) Ez visszafelé nem működik, egy emlős nem feltétlen delfin. Valamint egy Asztal osztály nem lehet a szülő osztálya a Szék osztálynak, mivel a szék nem asztal.

A másik típusú kapcsolat a van neki kapcsolata. Ezek a kapcsolatok megvalósultak a kódban az osztály attribútumok közt. Egy kutyának van neve, és így a Kutya osztálynak van egy név attribútuma. Valamint, egy személynek lehet egy kutyája, és ez leszármaztatható is, a Személy osztálynak lehet olyan attribútuma, hogy birtokol egy kutyát. A Személy osztályt nem vezethetjük le a Kutyából, mivel ez egyfajta inzultushoz is vezetne.

Nézzük meg a példa kódunkat:

12.7 Áttekintés

12.7.1 Kvízkérdések

Click here for a multiple-choice quiz.

12.7.2 Feladatlap

Click here for the chapter worksheet.

12.7.3 Labor feladat

Click here for the chapter lab.


You are not logged in. Log in here and track your progress.