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

Εισαγωγή

Η python είναι μια γλώσσα αντικειμενοστραφούς προγραμματισμού. Αντικειμενοστραφής προγραμματισμός είναι ο προγραμματισμός με την χρήση τάξεων - κατηγοριών - κλάσεων και των εμφανίσεών τους των αντικειμένων. Η ιστορική αναδρομή η οποία ακολουθεί βοηθάει στην κατανόηση αυτών των όρων (αν οι όροι σας είναι οικείοι προχωρήστε στα παραδείγματα εκμάθησης).

Ιστορική αναδρομή στις μεθόδους προγραμματισμού

Στην αρχή (έως την δεκαετία του 1960) κυριαρχούσε ογραμμικός τρόπος προγραμματισμού. Οι προγραμματιστές έγραφαν τις εντολές τους στην σειρά και όποτε χρειαζόταν μια διακλάδωση τότε χρησιμοποιούσαν την εντολή GOTO. Ο κώδικας ήταν συμπαγής εξαιρετικά γρήγορος αλλά είχε τεράστια μειονεκτήματα ιδίως στην δυνατότητα διαχείρισης, συντήρησης και εκσφαλμάτωσης του. Κύριες γλώσσες γραμμικού προγραμματισμού είναι η Assembly και άλλες γλώσσες της εποχής όπως η Basic και η Fortran V.

Την δεκαετία του 1970 επικράτησε οδομημένος προγραμματισμός ο οποίος κατάργησε την χρήση του GOTO. Αυτό επετεύχθη με την δημιουργία των προγραμματιστικών μονάδων δηλαδή των δομών και των υποπρογραμμάτων. Κάθε φορά που απαιτείται μια πρόσθετη εργασία αντί της διακλάδωσης επιλέγεται η χρήση μιας ομάδας εντολών σαφώς διακριτών από τις υπόλοιπες. Αυτές οι ομάδες είτε είναι τμήματα εντολών ελέγχου ή επανάληψης είτε είναι υποπρογράμματα. Περιέχουν δε οποιοδήποτε πλήθος ή συνδυασμό άλλων εντολών. Γλώσσες δομημένου προγραμματισμού οι οποίες παραμένουν έως σήμερα είναι η C και η Pascal.

Τέλος από την δεκαετία του 1990 και μετά άρχισε να κυριαρχεί ο αντικειμενοστραφής προγραμματισμός. Τώρα οι “ομάδες” του δομημένου ονομάστηκαν κατηγορίες-τάξεις-κλάσεις και εκτός από εντολές (αλγόριθμους) περιέχουν και μεταβλητές (δεδομένα). Στο πλαίσιο λειτουργιών ενός αντικειμένου (ή καλύτερα μιας κατηγορίας) συμπεριλαμβάνονται τόσο οι μέθοδοι (αλγόριθμοι) που το αφορούν με την μορφή υποπρογραμμάτων όσο και τα δεδομένα (μεταβλητές) που το περιγράφουν. Κάθε αντικείμενο είναι η στιγμιαία έκφραση μιας κατηγορίας και περιλαμβάνει το δικά του χαρακτηριστικά στις μεταβλητές της κατηγορίας του και δικαίωμα χρήσης των υποπρογραμμάτων-μεθόδων της. Σήμερα κύριες γλώσσες αντικειμενοστραφούς προγραμματισμού είναι η C++, η Python και η Java.

Βασικές Έννοιες

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

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

Γνωρίσματα (attributes) ή πεδία (fields) καλούνται οι μεταβλητές των μεθόδων.

Αντικείμενο (object) είναι το στιγμιότυπο (instance) μίας κλάσης, δηλαδή αυτή καθαυτή η δομή δεδομένων (με αποκλειστικά δεσμευμένο χώρο στη μνήμη) βασισμένη στο «καλούπι» που προσφέρει η κλάση. Παραδείγματος χάρη, σε μία αντικειμενοστρεφή γλώσσα προγραμματισμού θα μπορούσαμε να ορίσουμε κάποια κλάση ονόματι BankAccount, η οποία αναπαριστά έναν τραπεζικό λογαριασμό, και να δηλώσουμε ένα αντικείμενο της με όνομα MyAccount. Το αντικείμενο αυτό θα έχει δεσμεύσει χώρο στη μνήμη με βάση τις μεταβλητές και τις μεθόδους που περιγράψαμε όταν δηλώσαμε την κλάση. Έτσι, στο αντικείμενο θα μπορούσε να περιέχεται ένα γνώρισμα Balance (=υπόλοιπο) και μία μέθοδος GetBalance (=επέστρεψε το υπόλοιπο). Ακολούθως θα μπορούσαμε να δημιουργήσουμε ακόμα ένα ή περισσότερα αντικείμενα της ίδιας κλάσης τα οποία θα είναι διαφορετικές δομές δεδομένων (διαφορετικοί τραπεζικοί λογαριασμοί στο παράδειγμα). Ας σημειωθεί εδώ πως τα αντικείμενα μίας κλάσης μπορούν να προσπελάσουν τα ιδιωτικά περιεχόμενα άλλων αντικειμένων της ίδιας κλάσης.

Ενθυλάκωση (encapsulation) καλείται η ιδιότητα που προσφέρουν οι κλάσεις να «κρύβουν» τα ιδιωτικά δεδομένα τους από το υπόλοιπο πρόγραμμα και να εξασφαλίζουν πως μόνο μέσω των δημόσιων μεθόδων τους θα μπορούν αυτά να προσπελαστούν. Αυτή η τακτική παρουσιάζει μόνο οφέλη καθώς εξαναγκάζει κάθε εξωτερικό πρόγραμμα να φιλτράρει το χειρισμό που επιθυμεί να κάνει στα πεδία μίας κλάσης μέσω των ελέγχων που μπορούν να περιέχονται στις δημόσιες μεθόδους της κλάσης.

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

Κληρονομικότητα (inheritance) ονομάζεται η ιδιότητα των κλάσεων να επεκτείνονται σε νέες κλάσεις, ρητά δηλωμένες ως κληρονόμους (υποκλάσεις ή ‘θυγατρικές κλάσεις’), οι οποίες μπορούν να επαναχρησιμοποιήσουν τις μεταβιβάσιμες μεθόδους και ιδιότητες της γονικής τους κλάσης αλλά και να προσθέσουν δικές τους. Στιγμιότυπα των θυγατρικών κλάσεων μπορούν να χρησιμοποιηθούν όπου απαιτούνται στιγμιότυπα των γονικών (εφόσον η θυγατρική είναι κατά κάποιον τρόπο μία πιο εξειδικευμένη εκδοχή της γονικής), αλλά το αντίστροφο δεν ισχύει. Παράδειγμα κληρονομικότητας είναι μία γονική κλάση Vehicle (=Όχημα) και οι δύο πιο εξειδικευμένες υποκλάσεις της Car (=Αυτοκίνητο) και Bicycle (=Ποδήλατο), οι οποίες λέμε ότι “κληρονομούν” από αυτήν. Πολλαπλή κληρονομικότητα είναι η δυνατότητα που προσφέρουν ορισμένες γλώσσες προγραμματισμού μία κλάση να κληρονομεί ταυτόχρονα από περισσότερες από μία γονικές. Από μία υποκλάση μπορούν να προκύψουν νέες υποκλάσεις που κληρονομούν από αυτήν, με αποτέλεσμα μία ιεραρχία κλάσεων που συνδέονται μεταξύ τους “ανά γενιά” με σχέσεις κληρονομικότητας.

1ο Παράδειγμα

Ορισμός κατηγοριών με χαρακτηριστικά και μεθόδους. Δήλωση αντικειμένων και χρήση τους.

Έστω ότι έχουμε να δουλέψουμε με κύκλους. Για να δούμε ένα παράδειγμα:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
#Filename: cycle.py - 1ο/3 μέρη - 1η έκδοση
class cycle:
	'''Αυτή είναι η κατηγορία του κύκλου'''
def __init__(self,r=1):
	self.rad=r
	print('Αρχικοποιήθηκε κύκλος με ακτίνα :',self.rad)

def perimeter(self):
	return self.rad*2*pi

Με την εντολή class ορίζουμε την νέα κατηγορία αντικειμένων cycle. Η μέθοδος init (Προσοχή! Δεσμευμένο όνομα) εκτελείται με ΚΑΘΕ δήλωση ενός αντικειμένου κύκλου. self είναι ΠΑΝΤΑ το πρώτο όρισμα και αντιπροσωπεύει το κάθε αντικείμενο. Η διαδικασία αυτή ορίζει την ακτίνα ενός κύκλου rad ενώ αν δεν υπάρχει τιμή βάζει 1. Η μέθοδος perimeter υπολογίζει και επιστρέφει την περίμετρο ενός κύκλου.

Για να δούμε και 2-3 εντολές χρήσης:

#Filename: cycle.py - 2ο/3 μέρη - 1η έκδοση
a=cycle(5);
print('Η ακτίνα του κύκλου είναι:', a.rad)
print('Η περίμετρος του κύκλου είναι:', a.perimeter())

Εδώ ορίζουμε τον κύκλο a με ακτίνα 5. Εμφανίζουμε στην οθόνη την ακτίνα και την περίμετρό του.

#Filename: cycle.py - 3ο/3 μέρη - 1η έκδοση
b=cycle();
print('Η ακτίνα του κύκλου είναι:', b.rad)
print('Η περίμετρος του κύκλου είναι:', b.perimeter())

Εδώ ορίζουμε τον κύκλο a χωρίς ρύθμιση της ακτίνας και άρα θα πάρει την τιμή 1. Εμφανίζουμε στην οθόνη την ακτίνα και την περίμετρό και αυτού του κύκλου.

Παρατήρηση: Παρατηρούμε ότι η αναφορά στο χαρακτηριστικό rad του αντικειμένου a της κατηγορίας cycle γίνεται με την χρήση του b.rad ενώ για την μέθοδο perimeter χρησιμοποιείται η b.perimeter() (με παρενθέσεις). Επειδή αφενός η δήλωση των χαρακτηριστικών δεν είναι τόσο εμφανής όπως των μεθόδων και αφετέρου δεν είναι εύκολο να θυμόμαστε πάντα αν το στοιχείο rad ή perimeter είναι χαρακτηριστικό ή μέθοδος και άρα θέλει ή δεν θέλει παρένθεση μια καλή πρακτική είναι η εξής: για όλα τα χαρακτηριστικά τα οποία θέλουμε να είναι διαθέσιμα κατά την χρήση των αντικειμένων που τα περιέχουν φτιάχνουμε ανάλογες μεθόδους απόδοσης ή λήψης τιμής. Το παραπάνω παράδειγμα μετά και τον εξελληνισμό των αναγνωριστικών του παίρνει την ακόλουθη μορφή:

#!/usr/bin/python3
# -*- coding: UTF-8 -*-
#Filename: cycle.py - 1ο/1 μέρη - 2η έκδοση με Ελληνικά !
from math import pi
class Κύκλος:
'''Αυτή είναι η κατηγορία του κύκλου'''
def __init__(self,ρ=1):
	self.rad=ρ
	print('Αρχικοποιήθηκε κύκλος με ακτίνα :',self.rad)

def Βάλε_Ακτίνα(self,ρ=1):
	self.rad=ρ
	print('O κύκλος απέκτησε ακτίνα :',self.rad)

def Ακτίνα(self):
	return self.rad

def Περίμετρος(self):
	return self.rad*2*pi

Αλφα=Κύκλος(5);
print('Η ακτίνα του κύκλου είναι:', Αλφα.Ακτίνα())
print('Η περίμετρος του κύκλου είναι:', Αλφα.Περίμετρος())
Βήτα=Κύκλος();
Βήτα.Βάλε_Ακτίνα(3);
print('Η ακτίνα του κύκλου είναι:', Βήτα.Ακτίνα())
print('Η περίμετρος του κύκλου είναι:', Βήτα.Περίμετρος())

2ο Παράδειγμα

Κληρονομικότητα και Πολυμορφισμός
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
#Filename: Σχολές.py - Έκδοση με Ελληνικά !

class Ίδρυμα:
'''Αυτή είναι η κατηγορία ιδρύματος ανώτατης εκπαίδευσης'''
def __init__(self, Όνομα):
	self.τίτλος=Όνομα
	print('Αρχικοποιήθηκε το ίδρυμα :',self.τίτλος)

def Όνομα(self):
	return self.τίτλος

def Τίτλος(self): # Ίδια με την προηγούμενη αλλά ορατή από την κατηγορία Σχολή
	return self.τίτλος

def Βάλε_Είδος(self,Είδος='AEI'):
	self.είδος=Είδος;
	print('Το ίδρυμα', self.τίτλος,' είναι : ',self.είδος)

def Είδος(self):
	return self.είδος

class Σχολή(Ίδρυμα): # ΚΛΗΡΟΝΟΜΙΚΟΤΗΤΑ: Η κατηγορία Σχολή είναι θυγατρική της κατηγορίας Ίδρυμα
'''Αυτή είναι η κατηγορία σχολής ενός ιδρύματος ανώτατης εκπαίδευσης'''
def __init__(self, Όνομα, ίδρυμα):
	self.όνομα=Όνομα
	self.τίτλος=ίδρυμα.τίτλος
	print('Αρχικοποιήθηκε η σχολή :',self.όνομα, 'του ιδρύματος',self.τίτλος)

def Όνομα(self): # ΠΟΛΥΜΟΡΦΙΣΜΟΣ: Μέθοδος με ίδιο όνομα με αυτό μητρικής κατηγορίας
	return self.όνομα

def Βάλε_Επίπεδο(self,Επίπεδο='Masters'):
	self.επίπεδο=Επίπεδο;
	print('Η σχολή', self.όνομα,'είναι επιπέδου : ',self.επίπεδο)

def Επίπεδο(self):
	return self.επίπεδο

ΕΜΠ=Ίδρυμα('ΕΘνικόν Μετσόβιον Πολυτεχνείον')
ΕΜΠ.Βάλε_Είδος('Α.Ε.Ι.')
print('Το ίδρυμα', ΕΜΠ.Όνομα(),' είναι : ', ΕΜΠ.Είδος())

ΣΑΤΜ=Σχολή('Αγρονόμων και Τοπογράφων Μηχανικών',ΕΜΠ)
ΣΑΤΜ.Βάλε_Επίπεδο()
print('Η σχολή ', ΣΑΤΜ.Όνομα(), 'του', ΣΑΤΜ.Τίτλος(), 'είναι επιπέδου : ', ΣΑΤΜ.Επίπεδο())

ΣΗΜΜΗΥ=Σχολή('Ηλεκτρολόγων Μηχανικών και Μηχανικών Ηλεκτρονικών Υπολογιστών',ΕΜΠ)
ΣΗΜΜΗΥ.Βάλε_Επίπεδο("Masters++ :-) ")
print('Η σχολή ', ΣΗΜΜΗΥ.Όνομα(), 'του', ΣΗΜΜΗΥ.Τίτλος(), 'είναι επιπέδου : ', ΣΗΜΜΗΥ.Επίπεδο())

if ΣΗΜΜΗΥ.Τίτλος() == ΣΑΤΜ.Τίτλος():
print('Η σχολή ', ΣΑΤΜ.Όνομα(), 'και η σχολή ',ΣΗΜΜΗΥ.Όνομα(), 'είναι στο ',ΣΗΜΜΗΥ.Τίτλος())

print('Η σχολή ', ΣΑΤΜ.Όνομα(), 'και η σχολή ',ΣΗΜΜΗΥ.Όνομα())
if ΣΗΜΜΗΥ.Επίπεδο() != ΣΑΤΜ.Επίπεδο():
print (' ΔΕΝ ')
print (' έχουν το ίδιο επίπεδο σπουδών.')

print('Η σχολή ')
if ΣΗΜΜΗΥ.Επίπεδο() > ΣΑΤΜ.Επίπεδο():
print(ΣΗΜΜΗΥ.Όνομα())
elif ΣΗΜΜΗΥ.Επίπεδο() < ΣΑΤΜ.Επίπεδο():
      print(ΣATM.Όνομα())
print('έχει υψηλότερο επίπεδο σπουδών. :-)')

Μελετήστε προσεκτικά το παράδειγμα αυτό και σχολιάστε μόν-οι/ες σας τις έννοιες της κληρονομικότητας και του πολυμορφισμού.

Καλό αντικειμενοστραφή κώδικα με Python.

Βιβλιογραφία

 
oopython.txt · Τελευταία τροποποίηση: 2014/05/07 14:25 από Sairin_Lote