flowchart TB
subgraph G ["καθολικός χώρος (global)"]
gx["x = 50"]
gf["change_x (συνάρτηση)"]
subgraph L ["τοπικός χώρος της change_x (μόνο όσο τρέχει)"]
lx["x = 2 ← νέο τοπικό x, εκτός αν δηλώσουμε 'global x'"]
end
end
Πληροφορική Ι
Εβδομάδα 7 · Συναρτήσεις (Μέρος Β΄) · Χειρισμός Σφαλμάτων
(Οδηγίες χρήσης του διαδραστικού κώδικα: δείτε την αρχική σελίδα.)
1 Συναρτήσεις (Μέρος Β΄): Έτοιμες Συναρτήσεις, Εμβέλεια, Χειρισμός Σφαλμάτων
1.1 Έτοιμες συναρτήσεις: τα modules math και random
Πολλές έτοιμες συναρτήσεις της Python οργανώνονται σε modules (βιβλιοθήκες), τα οποία πρέπει πρώτα να φορτωθούν με την εντολή import. Το module math περιέχει μαθηματικές συναρτήσεις όπως sqrt, log, floor, ceil, sin, cos, και σταθερές όπως math.pi:
Το module random παράγει ψευδοτυχαίους αριθμούς: random.randint(x, y) (ακέραιος στο \([x,y]\)), random.random() (πραγματικός στο \([0,1)\)), random.uniform(x, y) (πραγματικός στο \([x,y)\)):
«Ψευδοτυχαίοι» σημαίνει ότι, σε βάθος πολλών κλήσεων, οι τιμές είναι ομοιόμορφα κατανεμημένες. Ας ρίξουμε ένα ζάρι 20.000 φορές και ας μετρήσουμε πόσες φορές ήρθε κάθε όψη (γράφημα με το matplotlib):
Σημειώστε ότι οι abs(), pow() και round() δεν ανήκουν στο module math, αλλά είναι απευθείας διαθέσιμες, όπως η print ή η len.
1.2 Τοπικές και καθολικές μεταβλητές
Μια μεταβλητή που δημιουργείται μέσα σε μια συνάρτηση είναι τοπική (local) και δεν είναι προσπελάσιμη έξω από αυτήν. Μια μεταβλητή που δημιουργείται έξω από κάθε συνάρτηση είναι καθολική (global) και είναι προσπελάσιμη (για ανάγνωση) από οπουδήποτε. Κάθε κλήση συνάρτησης φτιάχνει τον δικό της «χώρο» τοπικών ονομάτων, που ζει όσο τρέχει η συνάρτηση και μετά εξαφανίζεται:
Από μέσα προς τα έξω η ανάγνωση επιτρέπεται· η τροποποίηση μιας καθολικής χρειάζεται ρητή δήλωση global:
Χωρίς τη δήλωση global, η x = 2 μέσα στη συνάρτηση θα έφτιαχνε μια νέα, τοπική x, αφήνοντας την καθολική ανέπαφη.
Γενικά, αποφεύγουμε τις καθολικές μεταβλητές: προτιμάμε να περνάμε τιμές ως ορίσματα και να επιστρέφουμε αποτελέσματα με return.
Προσοχή: το global χρειάζεται μόνο για επανεκχώρηση, όχι για μεταβολή
Η δήλωση global απαιτείται μόνο για επανεκχώρηση — όταν θέλουμε να αλλάξουμε σε ποιο αντικείμενο δείχνει μια καθολική μεταβλητή.
Αν η καθολική είναι μεταβλητό (mutable) αντικείμενο (μια λίστα), μπορούμε να τροποποιήσουμε τα στοιχεία της χωρίς global: δεν αλλάζουμε το όνομα totals, μόνο το αντικείμενο στο οποίο ήδη δείχνει — ίδια λογική με τα ορίσματα λιστών στην Εβδομάδα 6.
Αν όμως προσπαθήσουμε να επανεκχωρήσουμε έναν καθολικό ακέραιο χωρίς global, η Python δεν αγγίζει καθόλου την καθολική. Επειδή υπάρχει εκχώρηση στο όνομα κάπου μέσα στη συνάρτηση, το θεωρεί τοπικό σε ολόκληρη τη συνάρτηση — και η ανάγνωση πριν την πρώτη τιμή δίνει σφάλμα:
1.3 Χειρισμός σφαλμάτων: try / except / raise
Έχουμε ήδη συναντήσει πολλά σφάλματα εκτέλεσης (exceptions): ZeroDivisionError (Εβδομάδα 2), ValueError από την int('γεια') (Εβδομάδα 1), IndexError, KeyError (Εβδομάδα 13). Ένα σφάλμα σταματάει αμέσως το πρόγραμμα — εκτός αν το πιάσουμε.
try / except
Η ροή: η Python εκτελεί το try. Αν προκύψει σφάλμα του τύπου που αναφέρει το except, εγκαταλείπει το try και τρέχει το except. Αν δεν προκύψει σφάλμα, το except παραλείπεται.
Μπορούμε να πιάσουμε διαφορετικούς τύπους ξεχωριστά, και με as να δούμε το ίδιο το αντικείμενο-σφάλμα:
Δύο προαιρετικά μπλοκ: το else: τρέχει μόνο αν δεν προέκυψε σφάλμα, και το finally: τρέχει πάντα (χρήσιμο για «καθάρισμα», π.χ. κλείσιμο αρχείου).
raise: προκαλούμε εμείς ένα σφάλμα
Μια συνάρτηση με άκυρη είσοδο δεν πρέπει να επιστρέψει σιωπηλά λάθος αποτέλεσμα — καλύτερα να σηκώσει σφάλμα με raise:
Έτσι, ο καλών αποφασίζει τι να κάνει με το σφάλμα — να το πιάσει, ή να το αφήσει να διαδοθεί. Το ίδιο μοτίβο χρησιμοποιεί ήδη η gauss_solve της Εβδομάδας 8 (raise ValueError('Ασύμβατες διαστάσεις')).
Πιάνετε συγκεκριμένους τύπους σφαλμάτων. Ένα γενικό except: που τα καταπίνει όλα κρύβει και τα δικά σας bugs.
1.4 Τετραγωνική ρίζα με τη μέθοδο Newton
Η μέθοδος Newton είναι μια κλασική αριθμητική μέθοδος εύρεσης ρίζας μιας συνάρτησης \(f\). Ξεκινώντας από μια αρχική εκτίμηση \(x_0\), παράγει διαδοχικά καλύτερες προσεγγίσεις με τον αναδρομικό τύπο
\[ x_{k+1} = x_k - \frac{f(x_k)}{f'(x_k)}. \]
Ο υπολογισμός \(\sqrt{\alpha}\) ισοδυναμεί με την εύρεση της θετικής ρίζας του \(f(x) = x^2 - \alpha\). Αντικαθιστώντας \(f(x)=x^2-\alpha\) και \(f'(x) = 2x\) στον τύπο του Newton, παίρνουμε
\[ x_{k+1} = x_k - \frac{x_k^2 - \alpha}{2x_k} = \frac{x_k + \alpha/x_k}{2}, \]
δηλαδή κάθε νέα προσέγγιση είναι ο μέσος όρος της τρέχουσας εκτίμησης και του \(\alpha\) διαιρεμένου με αυτήν — μια εντυπωσιακά απλή επαναληπτική διαδικασία. Σταματάμε όταν το σχετικό σφάλμα \(|x_k - \alpha/x_k|/x_k\) γίνει μικρότερο από μια επιθυμητή ακρίβεια epsilon:
Ας δούμε τις διαδοχικές εκτιμήσεις και το σφάλμα τους:
Παρατηρήστε: το σφάλμα δεν μικραίνει απλώς — ο εκθέτης του (το e-XX) περίπου διπλασιάζεται σε κάθε γραμμή. Αυτό λέγεται τετραγωνική σύγκλιση: το πλήθος των σωστών δεκαδικών ψηφίων περίπου διπλασιάζεται σε κάθε επανάληψη. Σε λογαριθμικό άξονα φαίνεται ακόμα καθαρότερα (γράφημα με το matplotlib):
Δοκιμάστε διαφορετικές τιμές του a, καθώς και διαφορετικά epsilon (π.χ. newton_sqrt(a, 1e-3)) στην κλήση της συνάρτησης παραπάνω.
2 Σύνοψη
Σε αυτή την εβδομάδα είδαμε:
- Modules της πρότυπης βιβλιοθήκης (
math,random) και την εντολήimport. - Τοπικές και καθολικές μεταβλητές, και πότε χρειάζεται πραγματικά η δήλωση
global. - Χειρισμό σφαλμάτων:
try/except(μεelse/finally) για να πιάνουμε σφάλματα, καιraiseγια να σηκώνουμε δικά μας. - Μια πρώτη επαναληπτική αριθμητική μέθοδο (iterative approximation): ξεκινάμε από μια εκτίμηση και τη βελτιώνουμε σταδιακά, μέχρι σύγκλιση.
⤺ Πίσω στην αρχική σελίδα / πρόγραμμα μαθήματος · Διαφάνειες αυτής της εβδομάδας