Home » Εβδομαδιαίες Στήλες » Προγραμματισμός » Μαθήματα Προγραμματισμού Python Από Το PCsteps: #7

Μαθήματα Προγραμματισμού Python Από Το PCsteps: #7

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

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

Δείτε τις ενότητες του οδηγού

Προτάσεις συνεργασίας

Προωθήστε δυναμικά την επιχείρησή σας στο site του PCsteps και στο κανάλι μας στο YouTube.

Επικοινωνία

Γίνε VIP μέλος στο PCSteps

Τα μέλη υποστηρίζουν ενεργά το PCsteps για να συνεχίσει να λειτουργεί χωρίς διαφημίσεις για όλους.

Συμμετοχή

Για να δείτε όλα τα μαθήματα Python από την αρχή τους, αλλά και τα επόμενα, αρκεί να κάνετε κλικ εδώ.

String – Ομοιότητες με λίστες

Οι λίστες δεν είναι ο μόνος τύπος δεδομένων που ομαδοποιεί οργανωμένες ακολουθίες τιμών. Για παράδειγμα, τα string έχουν πολλά κοινά με τις λίστες. Μπορούμε να τα φανταστούμε σαν να αποτελούνται από μια “λίστα” χαρακτήρων.

Έτσι, πολλές από τις λειτουργίες που είδαμε για τις λίστες, έχουν την ίδια εφαρμογή και με τα string. Η εύρεση τιμών με δείκτες, η αξιοποίησή τους σε βρόχους for, η χρήση τους με τα in και not in, είναι μερικές από αυτές.

Μεταβλητοί και μη μεταβλητοί τύποι δεδομένων

Ωστόσο, οι λίστες και τα string έχουν μια σημαντική διαφορά. Η λίστα είναι μεταβλητός (mutable) τύπος δεδομένων: μπορούμε να της προσθέσουμε τιμές, να τις αφαιρέσουμε ή να τις αλλάξουμε. Αντίθετα, ένα string είναι αμετάβλητο (immutable): δεν μπορούμε να το τροποποιήσουμε κατ' αυτόν τον τρόπο.

Αυτό το βλέπουμε στην πράξη με το ακόλουθο παράδειγμα. Προσπαθώντας να αναθέσουμε σε κάποια θέση του string έναν χαρακτήρα, θα πάρουμε TypeError.

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

Όπως φαίνεται και από τις εκτυπώσεις, το αρχικό my_string έχει παραμείνει αμετάβλητο. Και η λίστα όμως, παρότι μεταβλητή, δεν θα αλλάξει με τον παρακάτω κώδικα:

Η λίστα της my_list, όπως βλέπουμε, δεν έχει τροποποιηθεί εδώ· απλά μια εντελώς νέα, με τιμές [4, 5, 6] γράφτηκε πάνω στην παλιά.

Έστω, όμως, ότι θέλαμε όντως να μεταβάλλουμε την αρχική λίστα που είναι αποθηκευμένη στη my_list, ώστε να περιέχει τα [4, 5, 6]. Θα έπρεπε να κάνουμε κάτι τέτοιο:

Επομένως, όταν αλλάζουμε την τιμή ενός μεταβλητού τύπου δεδομένων, όπως η λίστα (πχ με τα del και append(), στο παράδειγμά μας), αλλάζουμε τα ίδια τα αντικείμενά του. Δεν κάνουμε ανάθεση μιας νέας τιμής στην μεταβλητή στην οποία είναι αποθηκευμένη η λίστα.

Πλειάδες (Tuples)

Οι πλειάδες είναι σχεδόν πανομοιότυπες με τις λίστες, με δύο βασικές διαφορές. Πρώτον, χρησιμοποιούμε παρενθέσεις ( ), αντί για αγκύλες [ ]. Παραδείγματος χάριν:

Η κυριότερη διαφορά, ωστόσο, είναι ότι οι πλειάδες είναι, όπως και τα string, μη μεταβλητές. Δεν επιτρέπεται να αλλάξουμε, να διαγράψουμε, ή να προσθέσουμε τιμές.

Δοκιμάζοντας με tuple να κάνουμε κάτι παρόμοιο με όσα είδαμε στο προηγούμενο μάθημα για τη λίστα, θα πάρουμε error:

Να σημειώσουμε εδώ ότι, για να έχουμε πλειάδα με μία μόνο τιμή, θα τοποθετήσουμε ένα κόμμα μετά το (μοναδικό) αντικείμενο της πλειάδας. Ειδάλλως η Python θεωρεί ότι απλώς έχουμε βάλει μια κανονική τιμή εντός παρενθέσεων.

Μπορούμε να ελέγξουμε αν ισχύει το παραπάνω, με την type(), που επιστρέφει τον τύπο των δεδομένων που της δίνουμε:

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

Μετατροπή τύπων – list() και tuple()

Γνωρίζουμε ήδη συναρτήσεις όπως η str() και η int(). Η str(10), για παράδειγμα, θα μετατρέψει τον αριθμό 10 στην αντίστοιχη αναπαράστασή του σε string, '10'.

Με όμοιο τρόπο, οι list() και tuple() επιστρέφουν την ανάλογη έκδοση σε λίστα και πλειάδα των τιμών που τους περνάμε αντίστοιχα.  Αν τις δοκιμάσουμε στον IDLE, θα δούμε ότι θα μας επιστρέψουν διαφορετικούς τύπους δεδομένων από αυτόν που είχαν ως όρισμα:

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

Αναφορές

Όπως έχουμε δει, μπορούμε να αποθηκεύσουμε σε μεταβλητές διάφορους τύπους δεδομένων, μεταξύ άλλων string και ακεραίους. Ας γράψουμε τον παρακάτω κώδικα στο κέλυφος της Python:

Θέτουμε αρχικά στη μεταβλητή num τον αριθμό 10, και μετά αντιγράφουμε την τιμή της num και την περνάμε στην μεταβλητή var. Όταν αργότερα αλλάξουμε την τιμή της num σε 99, αυτό δεν επηρεάζει τη var. Αυτό συμβαίνει επειδή οι num και var είναι διαφορετικές μεταβλητές, που περιέχουν διαφορετικές τιμές.

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

Ο παρακάτω κώδικας θα κάνει τη διάκριση αυτή πιο κατανοητή:

Το αποτέλεσμα δείχνει μάλλον παράδοξο. Αφού αλλάξαμε μόνο τη λίστα της num, για ποιον λόγο μεταβλήθηκαν και η num και η var?

Η απάντηση βρίσκεται στην έννοια της reference. Όταν δημιουργούμε τη λίστα, όπως βλέπουμε στην πρώτη γραμμή του κώδικά μας, ουσιαστικά περνάμε στη μεταβλητή var μια αναφορά στη λίστα αυτήν.

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

Για τις λίστες, οι μεταβλητές περιέχουν αναφορές προς αυτές, και όχι τις λίστες αυτές καθεαυτές. Αντίθετα, για string και ακεραίους, οι μεταβλητές περιέχουν το ίδιο το string ή τον αριθμό.

Πέρασμα αναφορών

Η έννοια της αναφοράς είναι ιδιαίτερα σημαντική για να κατανοήσουμε πώς περνιέται το όρισμα σε μια συνάρτηση. Όταν καλούμε μια συνάρτηση, οι τιμές των ορισμάτων αντιγράφονται στις μεταβλητές των παραμέτρων. Για τις λίστες όμως, (και για τα dictionaries, που θα δούμε παρακάτω) εκείνο που αντιγράφεται είναι η αναφορά.

Για να δούμε τις συνέπειες αυτής της ιδιότητας, μπορούμε να γράψουμε στον editor μας τον παρακάτω κώδικα, που δίνει την αντίστοιχη εκτύπωση.

Παρατηρούμε ότι όταν καλούμε τη fun(), δεν αναθέτουμε το αποτέλεσμα που επιστρέφει στην numbers. Αντιθέτως, η numbers τροποποιείται αμέσως επί τόπου.

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

Παρότι η numbers και η some_parameter περιέχουν διαφορετικές αναφορές, και οι δύο αναφέρονται στην ίδια λίστα.

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

Copy() και deepcopy()

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

Για τον σκοπό αυτό, η Python μας παρέχει ένα module, το copy, μέσω του οποίου έχουμε στη διάθεσή μας τις copy() και deepcopy(). Με την πρώτη, δημιουργούμε ένα αντίγραφο της λίστας, που όμως μπορεί να μεταβληθεί. Γράφουμε στον IDLE:

Εδώ οι μεταβλητές numbers και var αναφέρονται σε άλλη λίστα η καθεμιά. Γι' αυτό και βλέπουμε μόνο τη λίστα της var να αλλάζει, μετά την ανάθεση του 100 στη δεύτερη θέση.

Λεξικά (Dictionaries)

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

Οι δείκτες των λεξικών ονομάζονται κλειδιά. Ένα κλειδί, μαζί με την τιμή με την οποία συσχετίζεται, αποτελούν ένα ζεύγος κλειδιού-τιμής.

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

Τα λεξικά εντούτοις γράφονται με άγκιστρα { }. Μέσα στα άγκιστρα, μπαίνουν τα ζεύγη κλειδιού-τιμής. Μεταξύ τους, κλειδί και τιμή ενός ζεύγους χωρίζονται με άνω κάτω τελεία:

>>> my_dict = {'name': 'Kostas', 'age': 30, 'height': 1.80}

Με αυτήν την γραμμή κώδικα, αναθέτουμε στην μεταβλητή my_dict ένα λεξικό. Τα κλειδιά του λεξικού είναι τα ‘name', ‘age', ‘height', ενώ οι αντίστοιχες τιμές είναι οι ‘Kostas', 30, 1.80. Γενικότερα, έχουμε πρόσβαση στις τιμές αυτές μέσω των κλειδιών τους, μέσα σε αγκύλες, πάντα, όπως σε λίστες και tuples:

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

>>> my_dict = {1: 'x', 2345:'y', 300:'z'}

Λεξικά vs Λίστες

Τα λεξικά δεν έχουν τις τιμές τους σε συνεχόμενη σειρά, όπως οι λίστες. Το πρώτο αντικείμενο μιας λίστας, έστω της my_list, θα βρίσκεται στη θέση my_list[0]. Σε ένα λεξικό, όμως, δεν υπάρχει “πρώτο” αντικείμενο.  Και ενώ η σειρά των αντικειμένων μετράει για να εξετάσουμε αν δύο λίστες είναι ίδιες, δεν ισχύει το ίδιο για τη σειρά των ζευγών κλειδιού-τιμής στα λεξικά.

Ας ελέγξουμε τα παραπάνω στο διαδραστικό κέλυφος της Python:

Αν επιχειρήσουμε να αποκτήσουμε πρόσβαση σε ένα κλειδί που δεν υπάρχει στο λεξικό μας, θα πάρουμε KeyError. Πρόκειται για το αντίστοιχο του IndexError, για χρήση δείκτη εκτός της εμβέλειας της λίστας ή της πλειάδας.

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

Παράδειγμα Προγράμματος

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

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

Το πρόγραμμα είναι αρκετά απλό, αλλά ενδεικτικό των νέων δυνατοτήτων που μας δίνει το λεξικό.

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

Σε κάθε επανάληψη του βρόχου, ζητείται από τον χρήστη να εισάγει ένα όνομα, το οποίο κρατάμε στην name. Ο χρήστης μπορεί να αφήσει κενό στην απάντησή του, αν θέλει να τελειώσει η εκτέλεση του προγράμματος.

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

birthdays[name]

Αν δεν βρίσκεται στο λεξικό, μπορούμε να το εμπλουτίσουμε προσθέτοντάς το, πάλι χρησιμοποιώντας αγκύλες και τον τελεστή ανάθεσης:

birthdays[name] = day

Με αυτήν την εντολή, συσχετίζεται με το κλειδί που υποδεικνύει η name, η τιμή που φέρει η day. Εκτελώντας το πρόγραμμα, θα δούμε στην οθόνη μας κάτι τέτοιο:

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

Στο επόμενο μάθημα για τον προγραμματισμό Python

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

Σας άρεσε το σημερινό μάθημα για τον προγραμματισμό Python?

Πώς σας φάνηκε το σημερινό μάθημα για την Python? Αν θέλετε να μας αναφέρετε προτάσεις ή προβλήματα με κάποιο πρόγραμμα, αφήστε σχόλιο.

Για να δείτε όλα τα μαθήματα Python από την αρχή τους, αλλά και τα επόμενα, αρκεί να κάνετε κλικ εδώ.
Τα σχόλια του PCsteps έχουν μεταφερθεί στο Questions.pcsteps.gr. Αν έχετε απορίες για τη δημοσίευση ή οποιαδήποτε τεχνολογική ερώτηση, από προτάσεις αγορών μέχρι τεχνικά προβλήματα, γράψτε μας εκεί. Απαντάμε το αργότερο εντός 48 ωρών.

Οι Στήλες του PCsteps

Αγορά Laptop €449-€3.955: Τα Καλύτερα Της Εβδομάδας 25/10-31/10
Οδηγοί Αγοράς
QuickSteps#323 - Windows Παιχνίδια Σε Android Κινητό, Dark Mode Στο VLC, Απενεργοποίηση PC Με Σημειωματάριο
QuickSteps
GamingSteps#20240420 - Φορητό PlayStation 1, Επιστήμονας Βρήκε Τον Καλύτερο Οδηγό Του Mario Kart 8, Cities: Skylines II
GamingSteps