Γραφικά υπολογιστών Εργαστήριο 9 Κλάσεις στην Python Σκοπός της 9ης άσκησης είναι να μάθουμε αντικειμενοστρεφή προγραμματισμό στην Python. 1. Εισαγωγή Κάθε χαρακτήρας σε ένα παιχνίδι χρειάζεται κάποια πληροφορία: ένα όνομα, την τοποθεσία στην οποία βρίσκεται, την κατεύθυνση προς την οποία κινείται, τις ενέργειες τις οποίες κάνει κλπ. Προκειμένου να μπορούμε να γράφουμε πιο καλό και καθαρό κώδικα και να μπορούμε εύκολα να τον τροποποιούμε, π.χ. να προσθέτουμε νέες ιδιότητες/ενέργειες κλπ στους χαρακτήρες μας, μια καλή πρακτική είναι να χρησιμοποιούμε κλάσεις. Η Python όπως έχουμε ήδη δει δεν απαιτεί την χρήση κλάσεων, αλλά με την προσθήκη τους μας βοηθά να γράψουμε πολύ καλύτερο κώδικα. 2. Η πρώτη μας κλάση Ας φτιάξουμε την πρώτη μας κλάση. Για ευκολία ας θεωρήσουμε ότι η κλάση αυτή θα χρησιμοποιείται για να αποθηκεύει όλα τα πεδία μιας διεύθυνσης. Εδώ, όπως έχουμε ήδη καταλάβει, η κλάση είναι η Address και διαθέτει τα πεδία name, line1, line2, city, state και zip. Θα πρέπει να προσέξουμε τα παρακάτω: Το def init (self)είναι ο constructor της κλάσης. Είναι η συνάρτηση η οποία τρέχει αυτόματα όταν δημιουργείται η κλάση. Θα δούμε σχετικά στη συνέχεια. Το self με απλά λόγια δηλώνει ότι τα συγκεκριμένα πεδία ανήκουν μόνο στην κλάση αυτή. Προσέξτε ότι μα βάση τη στοίχιση, βρίσκονται μέσα στον ορισμό της κλάσης Εάν έχετε πολλές κλάσεις, συνίσταται να φτιάχνετε ένα διάγραμμα που να περιλαμβάνει τις κλάσεις και τον τρόπο που συνδέονται μεταξύ τους, π.χ. για την περιγραφή της προηγούμενης κλάσης, αρκεί κάτι τέτοιο: Φυσικά, ο παραπάνω κώδικας απλά ορίζει το πώς μοιάζει μια κλάση, αλλά δεν φτιάχνει και κάποιο στιγμιότυπό της. Τονίζουμε ότι παρ όλο που δεν είναι υποχρεωτικό κάθε κλάση να έχει στιγμιότυπα, δεν έχει και ιδιαίτερο νόημα να ορίζουμε κλάσεις που δεν θα χρησιμοποιήσουμε. Ας φτιάξουμε λοιπόν ένα στιγμιότυπο της κλάσης address:
Καλώντας τον constructor έχουμε φτιάξει ένα αντικείμενο και στη συνέχεια, με τρόπο που μας φαίνεται οικείος έχουμε δώσει τιμές σε όλα τα πεδία του, με τη βοήθεια του dot operator (. ). Προσοχή, δεν μπορούμε να γράψουμε π.χ. Address.state: Ας φτιάξουμε τώρα μια συνάρτηση, η οποία θα τυπώνει το περιεχόμενο ενός στιγμιοτύπου της κλάσης Address: Δοκιμάστε να την καλέσετε! 3. Προσθήκη μεθόδων σε κλάσεις Εκτός από τις ιδιότητες, όπως ίσως περιμέναμε, οι κλάσεις έχουν και μεθόδους. Μια μέθοδος είναι μια συνάρτηση η οποία υπάρχει έξω από την κλάση. Ας φτιάξουμε μια απλή κλάση Dog και ας της προσθέσουμε μια μέθοδο:
Προσοχή, οι ορισμοί των μεθόδων μέσα σε μια κλάση είναι ακριβώς ίδιοι με αυτούς των συναρτήσεων. Η βασική διαφορά έιναι η προσθήκη της παραμέτρου self. Η πρώτη παράμετρος κάθε μεθόδου μέσα σε μια κλάση πρέπει να είναι η self. Απαιτείται ακόμη κι αν δε χρησιμοποιείται από τη συνάρτηση. Επίσης, θα πρέπει να προσέχουμε τα εξής: Πρώτα ορίζουμε ιδιότητες, έπειτα μεθόδους Η πρώτη παράμετρος κάθε μεθόδου πρέπει να είναι η self Οι ορισμοί των μεθόδων πρέπει να έχουν στοίχιση ίση με ένα tab stop Κατα τ άλλα, οι μέθοδοι χρησιμοποιούνται ακριβώς όπως και οι ιδιότητες: Προσέξτε ότι παρ ότι το self είναι το όρισμα της bark(), την καλούμε χωρίς όρισμα. Εσωτερικά η Python καλεί το εν λόγω αντικείμενο. Αν η συνάρτηση bark χρειαζόταν να χρησιμοποιήσει κάποια από τις ιδιότητες, τότε αυτό θα μπορούσε να γίνει με τη βοήθεια του self. Αλλάξτε την bark ως εξής: Δείτε τι συμβαίνει εάν καλέσετε ξανά τη μέθοδο bark: Μιας και αναφέραμε ότι ορισμένες φορές μας διευκολύνει να σχεδιάζουμε τις κλάσεις, στην περίπτωση που αυτές περιέχουν μεθόδους, αυτό θα γινόταν κάπως έτσι: Για να κατανοήσουμε καλύτερα τα παραπάνω, ας φτιάξουμε μια κλάση που θα αντιπροσωπεύει μια μπάλα, η οποία και θα κινείται στην οθόνη. Χρησιμοποιείστε το pygame_base_template.py και αρχικά τοποθετείστε έξω από τον κυρίως βρόχο τον ορισμό της κλάσης:
Πριν τον κυρίως βρόχο φτιάξτε ένα στιγμιότυπο της κλασης: Και στη συνέχεια, μέσα στον κυρίως βρόχο προσθέστε τον κώδικα που θα κινεί την μπάλα: 4. Constructors Η προηγούμενη κλάση Dog είχε καθορισμένο όνομα για κάθε σκύλο που γεννιέται. Στην πράξη δε θέλουμε κάτι τέτοιο. Αν απλώς ορίσουμε ότι η ιδιότητα name έχει τιμή ίση με, τότε θα γεννιούνται σκύλοι χωρίς όνομα! Για να ξεπεράσουμε τέτοιου τύπου προβλήματα, ο πιο ενδεδειγμένος τρόπος είναι να τροποποιήσουμε τον constructor έτσι ώστε να απαιτεί τη χρήση του ονόματος. Δοκιμάστε να καλέσετε τον constructor με και χωρίς όνομα για τον σκύλο σας!
5. Κληρονομικότητα Η κληρονομικότητα στην Python λειτουργεί ακριβώς με τον τρόπο που θα περιμεναμε. Αφού ορίσουμε μια κλάση, στη συνέχεια μπορούμε να ορίσουμε κλάσεις που κληρονομούν την αρχική. Δηλαδή, κληρονομούν τις ιδιότητες και ενδεχομένως προσθέτουν και νέες, κληρονομούν τις μεθόδους και ενδεχομένως προσθέτουν και νέες. Δείτε το ακόλουθο παράδειγμα: Η κλάση Person ορίζεται με τον κλασικό τρόπο. Ακολούθως, η κλάση Employee κληρονομεί την Person, άρα έχει name! Στη συνέχεια με την super(). init () καλεί την init της Person και ακολούθως ορίζει και μια περαπάνω ιδιότητα. Το ίδιο κάνει και η Customer. Δοκιμάστε να καλέσετε τους constructors: Με αντίστοιχο τρόπο κληρονομούνται και οι μέθοδοι. Προσοχή, οι θυγατρικές κλάσεις έχουν τη δυνατότητα να ορίσουν δικές τους μεθόδους για να αντικαταστήσουν αυτές των πατρικών, αλλά και να καλούν με τη super τις αντίστοιχες μεθόδους της πατρικής κλάσης. Δείτε το παρακάτω και κάντε τις απαραίτητες δοκιμές για να κατανοήσετε πώς λειτουργεί η κληρονομικότητα.