post

Python el:Αντικειμενοστρεφής προγραμματισμός

Contents

Εισαγωγή

Όλα τα προγράμματα που γράψαμε μέχρι στιγμής, τα σχεδιάσαμε με τη χρήση συναρτήσεων, δηλαδή μπλοκ εντολών που χειρίζονται δεδομένα. Αυτή η μέθοδος αποκαλείται διαδικασιοστρεφής προγραμματισμός. Υπάρχει και άλλη μέθοδος συγγραφής προγραμμάτων, η οποία συνδυάζει δεδομένα και λειτουργικότητα εμπερικλείοντας τα σε ένα αντικείμενο. Η μέθοδος αυτή ονομάζεται αντικειμενοστρεφής προγραμματισμός. Συνήθως η χρήση διαδικασιοστρεφούς προγραμματισμού αρκεί, αλλά αν γράφετε μεγάλα προγράμματα ή αντιμετωπίζετε ένα πρόβλημα που εξυπηρετείται καλύτερα από αυτή τη μέθοδο, μπορείτε να χρησιμοποιήσετε τεχνικές αντικειμενοστρεφούς προγραμματισμού.

Οι κλάσεις και τα αντικείμενα είναι οι δύο κύριες πτυχές του αντικειμενοστρεφούς προγραμματισμού. Μια κλάση δημιουργεί ένα νέο τύπο, όπου τα αντικείμενα είναι υποστάσεις (instances) της κλάσης. Μια αναλογία θα ήταν με μεταβλητές του τύπου int και μεταφράζεται αντίστοιχα λέγοντας ότι οι μεταβλητές που αποθηκεύουν ακέραιους αριθμούς είναι υποστάσεις (αντικείμενα) της κλάσης int.

Σημείωση για προγραμματιστές στατικών γλωσσών
Προσέξτε ότι ακόμη και οι ακέραιοι αριθμοί αντιμετωπίζονται ως αντικείμενα (της κλάσης int). Σε αντίθεση με τη C++ και Java (πριν την έκδοση 1.5), όπου οι ακέραιοι είναι αρχέγονοι ατόφιοι τύποι δεδομένων (primitive native types). Δείτε την εντολή help(int) για περισσότερες λεπτομέρειες σχετικά με την κλάση.
Οι προγραμματιστές C# και Java 1.5 θα βρουν ομοιότητες με την boxing and unboxing έννοια.

Τα αντικείμενα αποθηκεύουν δεδομένα με τη χρήση κοινών μεταβλητών που ανήκουν στο αντικείμενο. Οι μεταβλητές που ανήκουν σε ένα αντικείμενο ή κλάση αναφέρονται ως πεδία (fields). Τα αντικείμενα μπορούν επίσης να είναι λειτουργικά με τη χρήση συναρτήσεων που ανήκουν σε μια κλάση. Τέτοιες συναρτήσεις αποκαλούνται μέθοδοι της κλάσης. Η ορολογία αυτή είναι σημαντική διότι μας επιτρέπει να ξεχωρίσουμε ανεξάρτητες συναρτήσεις και μεταβλητές από αυτές που ανήκουν σε ένα αντικείμενο ή κλάση. Καθολικά, τα πεδία και οι μέθοδοι αναφέρονται ως ιδιοχαρακτηριστικά (attributes) αυτής της κλάσης.

Τα πεδία είναι δύο τύπων -μπορεί να ανήκουν στην υπόσταση/αντικείμενο της κλάσης ή στην ίδια την κλάση. Αποκαλούνται μεταβλητές υπόστασης (instance variables) και μεταβλητές κλάσης αντίστοιχα.

Μια κλάση δημιουργείται με τη λέξη-κλειδί class. Τα πεδία και οι μέθοδοι της κλάσης απαριθμούνται σε μια πλοκάδα κώδικα σε εσοχή.

Η μεταβλητή self

Οι μέθοδοι κλάσης έχουν μια συγκεκριμένη διαφορά από τις κοινές συναρτήσεις -πρέπει να έχουν ένα επιπλέον όνομα και πρέπει να προστεθεί στην αρχή της λίστας παραμέτρων, εσείς δε χρειάζεται να ορίσετε μια τιμή σε αυτή την παράμετρο όταν καλείτε τη μέθοδο, σας το παρέχει η Python. Αυτή η συγκεκριμένη μεταβλητή αναφέρεται στο ίδιο το αντικείμενο και κατά συνθήκη, της αποδίδεται το όνομα self.

Παρόλο που μπορείτε να δώσετε οποιοδήποτε όνομα σε αυτή την παράμετρο, συνιστάται το όνομα μεταβλητής self -οποιοδήποτε άλλο όνομα είναι απαξιωτικό. Υπάρχουν πολλά πλεονεκτήματα για τη χρήση ενός πρότυπου ονόματος μεταβλητής -ο κάθε αναγνώστης του κώδικα του προγράμματος σας θα το αναγνωρίσει άμεσα. Ακόμη και γραφικά περιβάλλοντα ανάπτυξης λογισμικού (Integrated Development Environments) θα σας συνδράμουν, αν χρησιμοποιείτε το όνομα μεταβλητής self.

Σημείωση για προγραμματιστές C++/Java/C#
Το όνομα μεταβλητής self στην Python ισούται με το δείκτη this στην C++ και την αναφορά this στην Java και C#.

Θα αναρωτιέστε πώς η Python ορίζει την τιμή για τη self και γιατί σας απαλλάσσει από τον χειροκίνητο ορισμό της. Ένα παράδειγμα θα το ξεκαθαρίσει. Ας πούμε ότι μια κλάση ονομάζεται MyClass και μια υπόσταση αυτής ονομάζεται myobject. Αν καλέσετε μια μέθοδο αυτού του αντικειμένου myobject.method(arg1, arg2), μετατρέπεται αυτόματα από την Python σε MyClass.method(myobject, arg1, arg2) -αυτή είναι και η ιδιαιτερότητα του ονόματος μεταβλητής self.

Αυτό σημαίνει επίσης ότι εάν έχετε μια μέθοδο η οποία δεν λαμβάνει ορίσματα, τότε θα πρέπει να έχει τουλάχιστον ένα όρισμα, τη μεταβλητή self.

Κλάσεις

Η απλούστερη κλάση φαίνεται στο παρακάτω παράδειγμα.

#!/usr/bin/python
# Filename: simplestclass.py

class Person:
    pass # Ένα κενό μπλοκ

p = Person()
print(p)

Έξοδος:

   $ python simplestclass.py
   <__main__.Person object at 0x019F85F0>

Πώς δουλεύει:

Δημιουργούμε μια νέα κλάση με την εντολή class και το όνομα της κλάσης. Αυτή ακολουθείται από μια πλοκάδα εντολών σε εσοχή που αποτελούν τον κορμό της κλάσης. Στην περίπτωσή μας έχουμε μια κενή πλοκάδα και δηλώνεται με την εντολή pass.

Στη συνέχεια, δημιουργούμε ένα αντικείμενο/υπόσταση αυτής της κλάσης με το όνομα αυτής ακολουθούμενο από ένα ζευγάρι παρενθέσεων. (Θα μάθουμε περισσότερα για τη δημιουργία υποστάσεων στην επόμενη ενότητα). Για επαλήθευση, επιβεβαιώνουμε τον τύπο της μεταβλητής με απλή εκτύπωση στην οθόνη. Μας αναφέρει ότι έχουμε μια υπόσταση της κλάσης Person στο άρθρωμα __main__.

Παρατηρήστε ότι η διεύθυνση μνήμης του υπολογιστή όπου αποθηκεύτηκε το αντικείμενο εκτυπώνεται επίσης. Η διεύθυνση θα έχει διαφορετική τιμή στον υπολογιστή σας διότι η Python αποθηκεύει το αντικείμενο όπου βρει διαθέσιμο χώρο.

Μέθοδοι αντικειμένου

Έχουμε ήδη συζητήσει πως οι κλάσεις/αντικείμενα δέχονται μεθόδους όπως και συναρτήσεις, εκτός της πρόσθετης μεταβλητής self. Ας δούμε ένα παράδειγμα.

#!/usr/bin/python
# Filename: method.py

class Person:
    def sayHi(self):
        print('Hello, how are you?')

p = Person()
p.sayHi()

# Αυτό το σύντομο παράδειγμα θα μπορούσε να γραφτεί και ως Person().sayHi()

Έξοδος:

   $ python method.py
   Hello, how are you?

Πώς δουλεύει:

Εδώ βλέπουμε τη μεταβλητή self σε δράση. Παρατηρήστε πως η μέθοδος sayHi δε δέχεται παραμέτρους, αλλά εμπερικλείει τη μεταβλητή self στον ορισμό της συνάρτησης.

Η μέθοδος __init__

Υπάρχουν πολλά ονόματα μεθόδων που έχουν ειδική σημασία στις κλάσεις Python. Τώρα θα δούμε τη σημασία της μεθόδου __init__.

Η μέθοδος __init__ εκτελείται μόλις ένα αντικείμενο μιας κλάσης αρχικοποιείται. Η μέθοδος αυτή είναι χρήσιμη για την κατάλληλη αρχικοποίηση που επιθυμείτε για το αντικείμενο σας. Παρατηρήστε τις διπλές κάτω παύλες στην αρχή και στο τέλος του ονόματος.

Παράδειγμα:

#!/usr/bin/python
# Filename: class_init.py

class Person:
    def __init__(self, name):
        self.name = name
    def sayHi(self):
        print('Hello, my name is', self.name)

p = Person('Swaroop')
p.sayHi()

# Αυτό το σύντομο παράδειγμα μπορεί να γραφτεί και ως Person('Swaroop').sayHi()

Έξοδος:

   $ python class_init.py
   Hello, my name is Swaroop

Πώς δουλεύει:

Εδώ ορίζουμε τη μέθοδο __init__ να λαμβάνει ως παράμετρο την name (μαζί με τη γνωστή self). Τώρα, δημιουργούμε ένα νέο πεδίο που αποκαλείται επίσης name. Προσέξτε ότι πρόκειται για δύο διαφορετικές μεταβλητές παρότι αναφέρονται και οι δύο ως ‘name’. Δεν πρόκειται να υπάρξει σύγχιση εδώ διότι ο διάστικτος συμβολισμός (dotted notation) self.name σημαίνει ότι υπάρχει που λέγεται “name” και είναι μέρος του αντικειμένου που λέγεται “self” ενώ το άλλο name είναι μια τοπική μεταβλητή. Αποφεύγουμε τη σύγχιση μεταξύ των δύο, αφού υποδεικνύουμε ρητά σε ποιό name αναφερόμαστε.

Το σημαντικότερο, προσέξτε ότι δεν καλούμε ρητά τη μέθοδο __init__, αλλά μεταφέρουμε τα ορίσματα εντός των παρενθέσεων μετά το όνομα της κλάσης, όταν δημιουργούμε μια νέα υπόσταση της κλάσης. Αυτή είναι η ιδιαίτερη σημασία της μεθόδου.

Μπορούμε πλέον να χρησιμοποιήσουμε το πεδίο self.name στις μεθόδους μας και παρουσιάζεται στη μέθοδο sayHi.

Μεταβλητές κλάσης και αντικειμένου

Έχουμε ήδη συζητήσει τη λειτουργικότητα των κλάσεων και αντικειμένων (δηλαδή μεθόδων), ας μάθουμε τώρα για τα δεδομένα. Τα δεδομένα, δηλαδή τα πεδία, δεν είναι παρά συνηθισμένες μεταβλητές και οριοθετούνται από τους χώρους ονομάτων (namespaces) των κλάσεων και αντικειμένων. Αυτό σημαίνει πρακτικά ότι τα ονόματα αυτά είναι έγκυρα μόνο εντός αυτών των κλάσεων και αντικειμένων. Γι’ αυτό αποκαλούνται name spaces.

Υπάρχουν δύο τύποι πεδίων (fields) -μεταβλητές κλάσης και μεταβλητές αντικειμένων και οι οποίες ταξινομούνται ανάλογα με την κλάση ή αντικείμενο που τις κατέχει αντίστοιχα.

Οι Μεταβλητές κλάσης είναι κοινόχρηστες -μπορούν να προσπελαστούν από όλες τις υποστάσεις αυτής της κλάσης. Υπάρχει μόνο ένα αντίγραφο της μεταβλητής κλάσης και όταν κάποιο αντικείμενο τροποποιήσει τη μεταβλητή αυτή, η τροποποίηση θα είναι εμφανής σε όλες τις υποστάσεις.

Οι μεταβλητές αντικειμένου ανήκουν μεμονωμένα σε κάθε αντικείμενο/υπόσταση της κλάσης. Στην περίπτωση αυτή, κάθε αντικείμενο έχει το δικό του αντίγραφο του πεδίου, δηλαδή δεν είναι κοινόχρηστες και δεν σχετίζονται σε καμία περίπτωση με το συνονόματο πεδίο σε μια διαφορετική υπόσταση. Ένα παράδειγμα θα μας βοηθήσει στην κατανόησή του:

#!/usr/bin/python
# Filename: objvar.py

class Robot:
    '''Represents a robot, with a name.'''

    # Μια μεταβλητή κλάσης, που μετρά τον αριθμό των ρομπότ
    population = 0

    def __init__(self, name):
        '''Initializes the data.'''
        self.name = name
        print('(Initializing {0})'.format(self.name))

        #Όταν δημιουργείται το άτομο, προστίθεται το ρομπότ στον πληθυσμό
        Robot.population += 1

    def __del__(self):
        '''I am dying.'''
        print('{0} is being destroyed!'.format(self.name))

        Robot.population -= 1

        if Robot.population == 0:
            print('{0} was the last one.'.format(self.name))
        else:
            print('There are still {0:d} robots working.'.format(Robot.population))

    def sayHi(self):
        '''Greeting by the robot.

        Yeah, they can do that.'''
        print('Greetings, my masters call me {0}.'.format(self.name))

    def howMany():
        '''Prints the current population.'''
        print('We have {0:d} robots.'.format(Robot.population))
    howMany = staticmethod(howMany)

droid1 = Robot('R2-D2')
droid1.sayHi()
Robot.howMany()

droid2 = Robot('C-3PO')
droid2.sayHi()
Robot.howMany()

print("nRobots can do some work here.n")

print("Robots have finished their work. So let's destroy them.")
del droid1
del droid2

Robot.howMany()

Έξοδος:

   (Initializing R2-D2)
   Greetings, my masters call me R2-D2.
   We have 1 robots.
   (Initializing C-3PO)
   Greetings, my masters call me C-3PO.
   We have 2 robots.

   Robots can do some work here.

   Robots have finished their work. So let's destroy them.
   R2-D2 is being destroyed!
   There are still 1 robots working.
   C-3PO is being destroyed!
   C-3PO was the last one.
   We have 0 robots.

Πώς δουλεύει:

Είναι μεγάλο το παράδειγμα αλλά βοηθά στην κατανόηση της φύσης των μεταβλητών κλάσεων και αντικειμένων. Η μεταβλητή population ανήκει στην κλάση Robot και συνεπώς είναι μια μεταβλητή κλάσης. Η μεταβλητή name ανήκει στο αντικείμενο (έχει ανατεθεί με τη χρήση της self) και είναι μια μεταβλητή αντικειμένου.

Άρα, αναφερόμαστε στη μεταβλητή κλάσης population ως Robot.population και όχι ως self.population. Αναφερόμαστε στη μεταβλητή αντικειμένου name με το συμβολισμό self.name των μεθόδων αυτού του αντικειμένου. Να θυμάστε αυτή την απλή διαφορά μεταξύ των μεταβλητών κλάσεων και αντικειμένων. Σημειώστε επίσης ότι μια μεταβλητή αντικειμένου με το ίδιο όνομα μιας μεταβλητής κλάσης θα αποκρύψει τη μεταβλητή κλάσης!

Το πεδίο howMany είναι πράγματι μια μέθοδος που ανήκει στην κλάση και όχι στο αντικείμενο. Αυτό σημαίνει ότι μπορούμε να οριστεί είτε ως classmethod ή ως staticmethod, ανάλογα με το αν θα πρέπει να γνωρίζουμε σε ποια κλάση ανήκει. Δεδομένου ότι δε χρειαζόμαστε τέτοιες πληροφορίες, θα επιλέξουμε τη staticmethod.

Θα είχαμε επίσης το ίδιο αποτέλεσμα με τη χρήση διακοσμητών (decorators):

    @staticmethod
    def howMany():
        '''Prints the current population.'''
        print('We have {0:d} robots.'.format(Robot.population))

Μπορούμε να φανταστούμε τους διακοσμητές ως συντομεύσεις για την κλήση μιας ρητής εντολής (explicit statement), όπως είδαμε σε αυτό το παράδειγμα.

Παρατηρήστε ότι η μέθοδος __init__ χρησιμοποιείται για την αρχικοποίηση της υπόστασης Robot με ένα όνομα. Σε αυτή τη μέθοδο, ο αριθμός του πληθυσμού population αυξάνεται κατά 1, προσθέτοντας ένα ακόμη ρομπότ. Παρατηρήστε επίσης ότι οι τιμές της κλάσης self.name είναι ειδικές για κάθε αντικείμενο, γεγονός που υποδεικνύει τη φύση των μεταβλητών αντικειμένου.

Θυμηθείτε ότι οφείλετε να αναφέρεστε στις μεταβλητές και μεθόδους του ιδίου αντικειμένου αποκλειστικά με τη χρήση της μεθόδου self . Αυτό αποκαλείται ως αναφορά ιδιοχαρακτηριστικού (attribute reference).

Σε αυτό το πρόγραμμα, βλέπουμε επίσης τη χρήση docstrings για κλάσεις αλλά και για μεθόδους. Μπορούμε να προσπελάσουμε τις docstring της κλάσης ενόσω τρέχει το πρόγραμμα χρησιμοποιώντας το Robot.__doc__ και τη μέθοδο docstring ως Robot.sayHi.__doc__

Ακριβώς όπως η μέθοδος __init__, υπάρχει η ειδική μέθοδος __del__ και καλείται όταν τερματίζεται ένα αντικείμενο, δηλαδή όταν αποδεσμεύεται και επιστρέφεται στο σύστημα για επαναχρησιμοποίηση αυτή η περιοχή μνήμης. Σε αυτή τη μέθοδο, μειώνουμε τον αριθμό των ρομπότ Robot.population κατά 1.

Η μέθοδος __del__ εκτελείται όταν το αντικείμενο δεν είναι σε χρήση πλέον και δεν εγγυάται πότε θα εκτελεστεί αυτή. Αν θέλετε να το δείτε σε δράση, πρέπει να χρησιμοποιήσετε την εντολή del και το έχουμε κάνει εδώ.

Σημείωση για προγραμματιστές C++/Java/C#
Όλα τα μέλη κλάσης (class members) (συμπεριλαμβανομένων και των μελών δεδομένων (data members)) είναι δημόσια (public) και όλες οι μέθοδοι είναι εικονικές (virtual) στην Python.
Μια εξαίρεση: Για την ονομασία μελών δεδομένων με τη χρήση του διπλού προθέματος κάτω παύλας (double underscore prefix), π.χ __privatevar, η Python χρησιμοποιεί κατάτμηση ονόματος (name-mangling) για να οριστεί η μεταβλητή ως ιδιωτική αποτελεσματικά.
Άρα, η σύμβαση που ακολουθείται είναι ότι η χρήση μιας μεταβλητής εντός αποκλειστικά μιας κλάσης ή ενός αντικειμένου, οφείλει να ξεκινά με μια κάτω παύλα και ότι όλα τα υπόλοιπα ονόματα είναι δημόσια (public) και μπορούν να χρησιμοποιηθούν από άλλες κλάσεις/αντικείμενα. Να θυμάστε ότι μιλάμε μόνο για μια σύμβαση και δεν επιβάλλεται από την Python (με εξαίρεση το διπλό πρόθεμα κάτω παύλας).

Κληρονομικότητα (Inheritance)

Ένα από τα σημαντικά οφέλη του αντικειμενοστρεφούς προγραμματισμού είναι η επαναχρησιμοποίηση (reuse) του κώδικα και ένας από τους τρόπους που επιτυγχάνεται είναι μέσω του μηχανισμού της κληρονομικότητας.Την υλοποίηση της κληρονομικότητας μπορούμε να τη φανταστούμε καλύτερα ως μια συγγένεια τύπου και υποτύπου (type and subtype) μεταξύ των κλάσεων.

Ας υποθέσουμε ότι θέλετε να γράψετε ένα πρόγραμμα που καταγράφει τους καθηγητές και τους μαθητές ενός κολλεγίου. Έχουν κάποια κοινά χαρακτηριστικά – ονοματεπώνυμο, ηλικία και διεύθυνση κατοικίας. Επίσης, έχουν ιδιαίτερα χαρακτηριστικά – μισθοδοσία, μαθήματα και άδειες για τους καθηγητές, βαθμολογία και δίδακτρα για τους μαθητές.

Μπορείτε να δημιουργήσετε δύο ανεξάρτητες κλάσεις για κάθε τύπο και να τις επεξεργαστείτε, αλλά η προσθήκη ενός νέου κοινού χαρακτηριστικού θα απαιτούσε την προσθήκη του και στις δύο αυτές ανεξάρτητες κλάσεις. Καταντά δύσχρηστη αυτή η προσέγγιση.

Μια καλύτερη λύση θα ήταν να δημιουργηθεί μια κοινή κλάση με το όνομα SchoolMember και κατόπιν οι κλάσεις καθηγητές και μαθητές να κληρονομήσουν από αυτή, δηλαδή να γίνουν υποτύποι αυτού του τύπου (κλάση) και στη συνέχεια να προσθέσουμε ειδικά χαρακτηριστικά σε αυτούς τους υποτύπους.

Υπάρχουν πολλά πλεονεκτήματα στην προσέγγιση αυτή. Εάν προσθέσουμε/αλλάξουμε κάποια λειτουργία στην κλάση SchoolMember, αυτομάτως ενημερώνονται και οι υποτύποι. Για παράδειγμα, ένα πεδίο αριθμού ταυτότητας για τους μαθητές και τους καθηγητές είναι εφικτό εύκολα με την προσθήκη του στην κλάση SchoolMember. Ωστόσο, οι αλλαγές σε έναν υποτύπο δεν επηρεάζουν τους άλλους υποτύπους. Ένα άλλο πλεονέκτημα είναι ότι εάν μπορούμε να αναφερθούμε σε ένα αντικείμενο καθηγητή ή μαθητή ως αντικείμενο SchoolMember, θα μας φανεί χρήσιμο σε καταστάσεις για τον υπολογισμό του συνολικού αριθμού των μελών του κολλεγίου. Η ιδιότητα αυτή αποκαλείται πολυμορφισμός (polymorphism) όπου ένας υποτύπος μπορεί να αντικατασταθεί σε κάθε περίπτωση που περιμένουμε ένα γονικό τύπο, δηλαδή το αντικείμενο μπορούμε να το χειριστούμε σαν μια υπόσταση της γονικής κλάσης.

Παρατηρήστε επίσης πώς επαναχρησιμοποιούμε τον κώδικα της γονικής κλάσης και δε χρειάζεται να τον επαναλαμβάνουμε, σε αντίθεση με την περίπτωση που θα χρησιμοποιούσαμε ανεξάρτητες κλάσεις.

Η κλάση SchoolMember σε αυτή την περίπτωση ονομάζεται βασική κλάση (base class) ή υπερκλάση (superclass). Οι κλάσεις Teacher και Student αποκαλούνται παράγωγες κλάσεις (derived classes) ή υποκλάσεις (subclasses).

Θα δούμε το παράδειγμα αυτό τώρα σε ένα πρόγραμμα.

#!/usr/bin/python
# Filename: inherit.py

class SchoolMember:
    '''Represents any school member.'''
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print('(Initialized SchoolMember: {0})'.format(self.name))

    def tell(self):
        '''Tell my details.'''
        print('Name:"{0}" Age:"{1}"'.format(self.name, self.age), end=" ")

class Teacher(SchoolMember):
    '''Represents a teacher.'''
    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)
        self.salary = salary
        print('(Initialized Teacher: {0})'.format(self.name))

    def tell(self):
        SchoolMember.tell(self)
        print('Salary: "{0:d}"'.format(self.salary))

class Student(SchoolMember):
    '''Represents a student.'''
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)
        self.marks = marks
        print('(Initialized Student: {0})'.format(self.name))

    def tell(self):
        SchoolMember.tell(self)
        print('Marks: "{0:d}"'.format(self.marks))

t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 25, 75)

print() # εκτυπώνει μια κενή γραμμή

members = [t, s]
for member in members:
    member.tell() # works for both Teachers and Students

Έξοδος:

   $ python inherit.py
   (Initialized SchoolMember: Mrs. Shrividya)
   (Initialized Teacher: Mrs. Shrividya)
   (Initialized SchoolMember: Swaroop)
   (Initialized Student: Swaroop)

   Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
   Name:"Swaroop" Age:"25" Marks: "75"

Πώς δουλεύει:

Για να χρησιμοποιήσουμε κληρονομικότητα, μετά τον ορισμό του ονόματος της υπερκλάσης, προσδιορίζουμε τα ονόματα της σε μια πλειάδα. Στη συνέχεια, παρατηρούμε ότι η μέθοδος __init__ της υπερκλάσης καλείται ρητά με τη χρήση της μεταβλητής self για την αρχικοποίηση του τμήματος της υπερκλάσης που αντιστοιχεί στο αντικείμενο. Είναι σημαντικό να θυμάστε ότι η Python δεν καλεί αυτόματα τον κατασκευαστή της υπερκλάσης, πρέπει να κληθεί από εμάς.

Παρατηρούμε επίσης ότι μπορούμε να καλέσουμε μεθόδους της υπερκλάσης με πρόθεμα στο όνομα της κλάσης, όταν καλούμε τη μέθοδο και στη συνέχεια περνά η μεταβλητή self μαζί με τυχόν εντολές.

Προσέξτε πώς μπορούμε να μεταχειριστούμε τις υποστάσεις Teacher ή Student ως απλές υποστάσεις της κλάσης SchoolMember, όταν χρησιμοποιούμε τη μέθοδο tell της κλάσης SchoolMember.

Επίσης, παρατηρήστε ότι καλείται η μέθοδος tell του υποτύπου και όχι η μέθοδος tell της κλάσης SchoolMember. Ένας τρόπος για να γίνει κατανοητό είναι ότι η Python αρχίζει να ψάχνει πάντα για μεθόδους στον πραγματικό τύπο, όπως και κάνει σε αυτή την περίπτωση. Αν δεν βρει τη μέθοδο, αρχίζει να αναζητά στις μεθόδους που ανήκουν στις υπερκλάσεις με τη σειρά που έχουν οριστεί στην πλειάδα.

Μια σημείωση σχετικά με την ορολογία – αν περισσότερες από μία κλάσεις παρατίθενται στην πλειάδα κληρονομικότητας, αποκαλείται τότε πολλαπλή κληρονομικότητα.

Σύνοψη

Έχουμε ως τώρα εξερευνήσει τις διάφορες πτυχές των κλάσεων και αντικειμένων, όπως επίσης και τις σχετικές ορολογίες. Έχουμε εξετάσει επίσης τα ωφέλη και τις παγίδες του αντικειμενοστρεφούς προγραμματισμού. Η Python είναι ιδιαίτερα αντικειμενοστρεφής και η προσεκτική κατανόηση αυτών των εννοιών θα σας ωφελήσει μακροπρόθεσμα.

Στη συνέχεια θα μάθουμε πώς να χειριστούμε την είσοδο/έξοδο και πώς την προσπέλαση αρχείων στην Python.


Πίσω στα περιεχόμενα

Advertisements