4.Μοντέλο εκτέλεσης¶
4.1.Δομή ενός προγράμματος¶
Ένα πρόγραμμα Python αποτελείται από μπλοκ κώδικα. Έναμπλοκ είναι ένα κομμάτι κειμένου προγράμματος Python που εκτελείται ως μια μονάδα. Τα παρακάτω είναι μπλοκ: ένα module, το σώμα μιας συνάρτησης, ο ένας ορισμός κλάσης. Κάθε εντολή που πληκτρολογείται διαδραστικά αποτελεί μπλοκ. Ένα αρχείο δέσμης ενεργειών (ένα αρχείο που δίνεται ως τυπική είσοδος στο διερμηνέα ή καθορίζεται ως όρισμα γραμμής εντολών στον διερμηνέα) είναι ένα μπλοκ κώδικα. Μια script εντολή (μια εντολή που καθορίζεται στο διερμηνέα με την επιλογή-c
) είναι ένα μπλοκ κώδικα. Μια ενότητα που εκτελείται ως ανωτέρου επιπέδου script (ως module__main__
) από τη γραμμή εντολών χρησιμοποιώντας ένα όρισμα-m
όρισμα είναι επίσης ένα μπλοκ κώδικα. Το όρισμα συμβολοσειράς που περνάει στις ενσωματωμένες συναρτήσειςeval()
καιexec()
είναι ένα μπλοκ κώδικα.
Ένα μπλοκ κώδικα εκτελείται σε έναπλαίσιο εκτέλεσης. Ένα πλαίσιο περιέχει ορισμένες πληροφορίες διαχείρισης (που χρησιμοποιούνται για αποσφαλμάτωση) και καθορίζει που και πως συνεχίζεται η εκτέλεση μετά την ολοκλήρωση της εκτέλεσης του μπλοκ κώδικα.
4.2.Ονομασία και σύνδεση¶
4.2.1.Σύνδεση ονομάτων¶
Names αναφέρονται σε αντικείμενα. Τα ονόματα εισάγονται μέσω λειτουργιών δέσμευσης ονομάτων.
Οι παρακάτω δομές δεσμεύουν ονόματα:
τυπικές παράμετροι συναρτήσεων,
ορισμοί κλάσεων,
ορισμοί συναρτήσεων
εκφράσεις ανάθεσης
targets που είναι αναγνωριστικά αν εμφανίζονται σε μια ανάθεση:
δηλώσεις
import
.δηλώσεις
type
.
Η δήλωσηimport
της μορφήςfrom...import*
συνδέει όλα τα ονόματα που ορίζονται στο εισαγόμενο module, εκτός από αυτά που ξεκινούν με μια κάτω παύλα. Αυτή η μορφή μπορεί να χρησιμοποιηθεί μόνο στο επίπεδο του module.
Ένας στόχος που εμφανίζεται σε μια δήλωσηdel
θεωρείται επίσης δεσμευμένος για αυτό τον σκοπό (αν και η πραγματική σημασιολογία είναι να αποσυνδέσει το όνομα).
Κάθε δήλωση ανάθεσης ή εισαγωγής συμβαίνει μέσα σε ένα μπλοκ που ορίζεται από έναν ορισμό κλάσης ή συνάρτησης ή στο επίπεδο του module (το μπλοκ κώδικα ανώτατου επιπέδου).
Αν ένα όνομα δεσμεύεται σε ένα μπλοκ, είναι μια τοπική μεταβλητή αυτού του μπλοκ, εκτός αν δηλωθεί ωςnonlocal
ήglobal
. Αν ένα όνομα δεσμεύεται στο επίπεδο του module, είναι μια καθολική μεταβλητή. (Οι μεταβλητές του μπλοκ του module είναι ταυτόχρονα τοπικές και καθολικές.) Αν μια μεταβλητή χρησιμοποιείται σε ένα μπλοκ κώδικα αλλά δεν ορίζεται εκεί, είναι μιαfree variable.
Κάθε εμφάνιση ενός ονόματος στο κείμενο του προγράμματος αναφέρεται στηbinding αυτού του ονόματος που καθορίζεται από τους παρακάτω κανόνες επίλυσης ονομάτων.
4.2.2.Επίλυση ονομάτων¶
Έναscope ορίζει την ορατότητα ενός ονόματος μέσα σε ένα μπλοκ. Αν μια τοπική μεταβλητή οριστεί σε ένα μπλοκ, το πεδίο της περιλαμβάνει το μπλοκ αυτό. Αν ο ορισμός συμβαίνει σε ένα μπλοκ συνάρτησης, το πεδίο επεκτείνεται σε οποιαδήποτε μπλοκ περιέχονται μέσα σε αυτό που την ορίζει, εκτός αν ένα περιεχόμενο μπλοκ εισάγει διαφορετική σύνδεση για το όνομα.
Όταν ένα όνομα χρησιμοποιείται σε ένα μπλοκ κώδικα, επιλύεται χρησιμοποιώντας το πλησιέστερο περιβάλλον πεδίο. Το σύνολο όλων των πεδίων που είναι ορατά σε ένα μπλοκ κώδικα ονομάζεταιenvironment του μπλοκ.
Όταν ένα όνομα δεν βρίσκεται καθόλου, γίνεται raise μια εξαίρεσηNameError
. Αν το τρέχον πεδίο είναι πεδίο συνάρτησης και το όνομα αναφέρεται σε μια τοπική μεταβλητή που δεν έχει ακόμα δεσμευτεί σε κάποια τιμή στο σημείο που χρησιμοποιείται το όνομα, γίνεται raise μια εξαίρεσηUnboundLocalError
. ΗUnboundLocalError
είναι μια υποκλάση τηςNameError
.
Αν μια λειτουργία σύνδεσης ονομάτων συμβεί οπουδήποτε μέσα σε ένα μπλοκ κώδικα, όλες οι χρήσεις του ονόματος μέσα στο μπλοκ αντιμετωπίζονται ως αναφορές στο τρέχον μπλοκ. Αυτό μπορεί να οδηγήσει σε σφάλματα όταν ένα όνομα χρησιμοποιείται μέσα σε ένα μπλοκ πριν δεσμευτεί. Αυτός ο κανόνας είναι λεπτός. Η Python δεν διαθέτει δηλώσεις και επιτρέπει τις λειτουργίες σύνδεση ονομάτων να συμβαίνουν οπουδήποτε μέσα σε ένα μπλοκ κώδικα. Οι τοπικές μεταβλητές ενός μπλοκ κώδικα μπορούν να προσδιοριστούν σαρώνοντας ολόκληρο το κείμενο του μπλοκ για λειτουργίες σύνδεσης ονομάτων. Δείτετην εγγραφή στο FAQ για το UnboundLocalError για παραδείγματα.
Αν η δήλωσηglobal
εμφανιστεί μέσα σε ένα μπλοκ, όλες οι χρήσεις των ονομάτων που καθορίζονται στη δήλωση αναφέρονται στις συνδέσεις αυτών των ονομάτων στον χώρο ονομάτων ανώτατου επιπέδου. Τα ονόματα επιλύονται στον χώρο ανώτατου επιπέδου αναζητώντας πρώτα στον καθολικό χώρο ονομάτων, δηλαδή τον χώρο ονομάτων του module που περιέχει το μπλοκ κώδικα, και στη συνέχεια στο χώρο ονομάτων των builtins, τον χώρο ονομάτων του modulebuiltins
. Ο καθολικός χώρος ονομάτων αναζητείται πρώτος. Αν τα ονόματα δεν βρεθούν εκεί, γίνεται αναζήτηση του ενσωματωμένου χώρου ονομάτων. Εάν τα ονόματα δεν βρίσκονται επίσης στον ενσωματωμένο χώρο ονομάτων, δημιουργούνται νέες μεταβλητές στον καθολικό χώρο ονομάτων. Η καθολική δήλωση πρέπει να προηγείται όλων των χρήσεων των ονομάτων που αναφέρονται.
Η δήλωσηglobal
έχει το ίδιο πεδίο με μια λειτουργία σύνδεσης ονόματος στο ίδιο μπλοκ. Αν το πλησιέστερο περιβάλλον πεδίου για μια ελεύθερη μεταβλητή περιέχει μια δήλωση global, η ελεύθερη μεταβλητή αντιμετωπίζεται ως καθολική.
Η δήλωσηnonlocal
προκαλεί τα αντίστοιχα ονόματα να αναφέρονται σε προηγουμένως δεσμευμένες μεταβλητές στο πλησιέστερο περιβάλλον πεδίου συνάρτησης. Μια εξαίρεσηSyntaxError
εγείρεται κατά το χρόνο μεταγλώττισης αν το συγκεκριμένο δεν υπάρχει σε κανένα περιβάλλον πεδίου συνάρτησης.Οι παράμετροι τύπου δεν μπορούν να δεσμευτούν εκ νέου με τη δήλωσηnonlocal
.
Ο χώρος ονομάτων για ένα module δημιουργείται αυτόματα την πρώτη φορά που το module εισάγεται Το κύριο module για ένα script ονομάζεται πάντα__main__
.
Τα μπλοκ ορισμού κλάσεων και τα ορίσματα στις συναρτήσειςexec()
καιeval()
είναι ειδικές περιπτώσεις στο πλαίσιο της επίλυσης ονομάτων. Ένας ορισμός κλάσης είναι μια εκτελέσιμη δήλωση που μπορεί να χρησιμοποιεί και να ορίζει ονόματα. Αυτές οι αναφορές ακολουθούν τους κανονικούς κανόνες επίλυσης ονομάτων, με την εξαίρεση ότι οι αδέσμευτες τοπικές μεταβλητές αναζητούνται στον καθολικό χώρο ονομάτων. Ο χώρος ονομάτων του ορισμού της κλάσης γίνεται το λεξικό χαρακτηριστικών της κλάσης. Το πεδίο των ονομάτων που ορίζονται σε ένα μπλοκ κλάσης περιορίζεται στο μπλοκ της κλάσης· δεν επεκτείνεται στα μπλοκ κώδικα των μεθόδων. Αυτό περιλαμβάνει συνθέσεις και εκφράσεις γεννητριών, αλλά δεν περιλαμβάνειπεδία σημειώσεων, τα οποία έχουν πρόσβαση στα περιβάλλοντα πεδία της περιβάλλουσας κλάσης. Αυτό σημαίνει ότι το παρακάτω θα αποτύχει:
classA:a=42b=list(a+iforiinrange(10))
Ωστόσο, το παρακάτω θα επιτύχει:
classA:typeAlias=NestedclassNested:passprint(A.Alias.__value__)# <type 'A.Nested'>
4.2.3.Σημειογραφία πεδία¶
ΤαAnnotations,Οι λίστες παραμέτρων τύπου και οι δηλώσειςtype
εισάγουνπεδία σημειογραφίας, τα οποία συμπεριφέρονται κυρίως όπως τα πεδία συναρτήσεων, αλλά με κάποιες εξαιρέσεις που συζητούνται παρακάτω.
Τα πεδία σημειογραφίας χρησιμοποιούνται στα παρακάτω συμφραζόμενα:
Λίστες παραμέτρων τύπου γιαgeneric type aliases.
Λίστες τύπου παραμέτρου γιαgeneric functions. Οι σημειογραφίες μιας γενικής συνάρτησης εκτελούνται μέσα στο πεδίο σημειώσεων, αλλά οι προεπιλογές και οι διακοσμητές της όχι.
Λίστες παραμέτρων τύπου γιαgeneric classes. Οι βασικές κλάσεις και τα ορίσματα λέξεων-κλειδιών μιας γενικής κλάσης εκτελούνται μέσα στο πεδίο σημειώσεων, αλλά οι διακοσμητές της όχι.
Τα όρια, οι περιορισμοί οι προεπιλεγμένες τιμές για παραμέτρους τύπου (lazily evaluated).
Η τιμή των ψευδωνύμων τύπου (lazily evaluated).
Τα πεδία σημειογραφίας διαφέρουν από τα πεδία συναρτήσεων με τους εξής τρόπους:
Τα πεδία σημειογραφίας έχουν πρόσβαση στον χώρο ονομάτων της περιβάλλουσας κλάσης. Αν ένα πεδίο σημειογραφίας βρίσκεται αμέσως μέσα σε έναν χώρο κλάσης ή μέσα σε ένα άλλο πεδίο σημειογραφίας που βρίσκεται αμέσως μέσα σε έναν χώρο κλάσης, ο κώδικας στο πεδίο σημειογραφίας μπορεί να χρησιμοποιεί ονόματα που έχουν οριστεί στον χώρο της κλάσης σαν να εκτελούνταν απευθείας στο σώμα της κλάσης. Αυτό έρχεται σε αντίθεση με τις κανονικές συναρτήσεις που ορίζονται μέσα σε κλάσεις, οι οποίες δεν μπορούν να έχουν πρόσβαση σε ονόματα που έχουν οριστεί στο χώρο της κλάσης.
Οι εκφράσεις σε πεδία σημειογραφίας δεν μπορούν να περιέχουν τις εκφράσεις
yield
,yieldfrom
,await
ή:=<python-grammar:assignment_expression
. (Αυτές οι εκφράσεις επιτρέπονται σε άλλα πεδία που περιέχονται μέσα στο πεδίο σημειογραφίας.)Τα ονόματα που ορίζονται σε πεδία σημειογραφίας δεν μπορούν να δεσμευτούν εκ νέου με δηλώσεις
nonlocal
σε εσωτερικά πεδία. Αυτό περιλαμβάνει μόνο παραμέτρους τύπου, καθώς και κανένα άλλο συντακτικό στοιχείο που μπορεί να εμφανιστεί μέσα σε πεδία σημειώσεων δεν μπορεί να εισαγάγει νέα ονόματα.Ενώ τα πεδία σημειογραφίας έχουν ένα εσωτερικό όνομα, αυτό το όνομα δεν αντικατοπτρίζεται στοqualified name των αντικειμένων που ορίζονται μέσα στο πεδίο.Αντίθετα, το
__qualname__
αυτών των αντικειμένων είναι σαν το αντικείμενο να είχε οριστεί στο περιβάλλων πεδίο.
Added in version 3.12:Τα πεδία σημειώσεων εισήχθησαν στην Python 3.12 ως μέρος τουPEP 695.
Άλλαξε στην έκδοση 3.13:Οι περιοχές σχολίων τύπου χρησιμοποιούνται επίσης για τις προεπιλεγμένες τιμές παραμέτρων τύπου, όπως εισάγεται από τοPEP 696.
4.2.4.Καθυστερημένη εκτίμηση¶
Τα περισσότερα πεδία annotationαξιολογούνται νωχελικά. Αυτό περιλαμβάνει annotations, τις τιμές των ψευδωνύμων τύπου που δημιουργούνται μέσω της δήλωσηςtype
και τα όρια, τους περιορισμούς και τις προεπιλεγμένες τιμές των μεταβλητών τύπου που δημιουργούνται μέσω της σύνταξης παραμέτρωνtype parameter syntax. Αυτό σημαίνει ότι δεν αξιολογούνται όταν δημιουργείται το ψευδώνυμο τύπου ή η μεταβλητή τύπου ή όταν δημιουργείται το αντικείμενο που φέρει σχολιασμούς. Αντίθετα, αξιολογούνται μόνο όταν είναι απαραίτητο, για παράδειγμα όταν γίνεται πρόσβαση στο χαρακτηριστικό__value__
σε ένα ψευδώνυμο τύπου.
Παράδειγμα:
>>>typeAlias=1/0>>>Alias.__value__Traceback (most recent call last):...ZeroDivisionError:division by zero>>>deffunc[T:1/0]():pass>>>T=func.__type_params__[0]>>>T.__bound__Traceback (most recent call last):...ZeroDivisionError:division by zero
Εδώ η εξαίρεση εγείρεται μόνο όταν γίνει πρόσβαση στο χαρακτηριστικό__value__
του ψευδωνύμου τύπου ή στο χαρακτηριστικό__bound__
της μεταβλητής τύπου.
Αυτή η συμπεριφορά είναι κυρίως χρήσιμη για αναφορές σε τύπους που δεν έχουν ακόμη οριστεί κατά τη δημιουργία του ψευδωνύμου τύπου ή της μεταβλητής τύπου. Για παράδειγμα, η καθυστερημένη εκτίμηση επιτρέπει τη δημιουργία αμοιβαίων αναδρομικών ψευδωνύμων τύπων:
fromtypingimportLiteraltypeSimpleExpr=int|ParenthesizedtypeParenthesized=tuple[Literal["("],Expr,Literal[")"]]typeExpr=SimpleExpr|tuple[SimpleExpr,Literal["+","-"],Expr]
Οι τιμές που αξιολογούνται καθυστερημένα αξιολογούνται στοπεδίο σημειογραφίας, που σημαίνει ότι τα ονόματα που εμφανίζονται μέσα στην καθυστερημένα αξιολογούμενη τιμή αναζητούνται σαν να χρησιμοποιήθηκαν στο αμέσως περιβάλλον πεδίο.
Added in version 3.12.
4.2.5.Ενσωματωμένες συναρτήσεις και περιορισμένη εκτέλεση¶
Οι χρήστες δεν θα πρέπει να τροποποιούν το__builtins__
· είναι αυστηρά μια λεπτομέρεια υλοποίησης. Οι χρήστες που θέλουν να παρακάμψουν τιμές στον χώρο ονομάτων των ενσωματωμένων συναρτήσεων θα πρέπει να κάνουνimport
το modulebuiltins
και να τροποποιούν τα χαρακτηριστικά του κατάλληλα.
Ο χώρος ονομάτων των ενσωματωμένων συναρτήσεων που σχετίζεται με την εκτέλεση ενός μπλοκ κώδικα βρίσκεται στην πραγματικότητα μέσω αναζήτησης του ονόματος__builtins__
στον καθολικό του χώρο ονομάτων· αυτό θα πρέπει να είναι ένα λεξικό ή ένα module (στη δεύτερη περίπτωση χρησιμοποιείται το λεξικό του module). Από προεπιλογή, όταν βρισκόμαστε στο module__main__
, το__builtins__
είναι το ενσωματωμένο modulebuiltins
· όταν βρισκόμαστε σε οποιοδήποτε άλλο module, το__builtins__
είναι ένα ψευδώνυμο για το λεξικό του ίδιου του modulebuiltins
.
4.2.6.Αλληλεπίδραση με δυναμικές λειτουργίες¶
Η επίλυση ονομάτων των ελεύθερων μεταβλητών συμβαίνει κατά το χρόνο εκτέλεσης, όχι κατά το χρόνο μεταγλώττισης. Αυτό σημαίνει ότι ο παρακάτω κώδικας θα εκτυπώσει το 42:
i=10deff():print(i)i=42f()
Οι συναρτήσειςeval()
καιexec()
δεν έχουν πρόσβαση στο πλήρες περιβάλλον για την επίλυση ονομάτων. Τα ονόματα μπορεί να επιλύονται στους τοπικούς και καθολικούς χώρους ονομάτων του καλούντος. Οι ελεύθερες μεταβλητές δεν επιλύονται στο πλησιέστερο περιβάλλον πεδίου, αλλά στον καθολικό χώρο ονομάτων.[1] Οι συναρτήσειςexec()
καιeval()
έχουν προαιρετικά ορίσματα για να παρακάμψουν τους καθολικούς και τοπικούς χώρους ονομάτων. Αν καθοριστεί μόνο ένας χώρος ονομάτων, χρησιμοποιείται και για τους δύο.
4.3.Εξαιρέσεις¶
Οι εξαιρέσεις είναι ένας τρόπος διακοπής της κανονικής ροής ελέγχου ενός μπλοκ κώδικα, προκειμένου να αντιμετωπιστούν σφάλματα ή άλλες εξαιρετικές συνθήκες. Μια εξαίρεσηγίνεται raise στο σημείο όπου εντοπίζεται το σφάλμα· μπορεί νααντιμετωπιστεί από το περιβάλλον μπλοκ κώδικα ή από οποιοδήποτε μπλοκ κώδικα που άμεσα ή έμμεσα εκτέλεσε το μπλοκ κώδικα όπου συνέβη το σφάλμα.
Ο διερμηνέας της Python εγείρει μια εξαίρεση όταν εντοπίσει ένα σφάλμα κατά την εκτέλεση(όπως η διαίρεση με το μηδέν). Ένα πρόγραμμα Python μπορεί επίσης να εγείρει ρητά μια εξαίρεση με τη δήλωσηraise
. Οι διαχειριστές εξαιρέσεων καθορίζονται με τη δήλωσηtry
…except
. Η ρήτραfinally
μιας τέτοιας δήλωσης μπορεί να χρησιμοποιηθεί για να καθοριστεί κώδικας καθαρισμού, ο οποίος δεν διαχειρίζεται την εξαίρεση αλλά εκτελείται ανεξάρτητα από το αν προηγήθηκε εξαίρεση ή όχι στον προηγούμενο κώδικα.
Η Python χρησιμοποιεί το μοντέλο διαχείρισης σφαλμάτων «τερματισμού»: ένας διαχειριστής εξαιρέσεων μπορεί να διαπιστώσει τι συνέβη και να συνεχίσει την εκτέλεση σε ένα εξωτερικό επίπεδο, αλλά δεν μπορεί να διορθώσει την αιτία του σφάλματος και να επαναλάβει τη λειτουργία που απέτυχε (εκτός αν επανεισαχθεί το προβληματικό κομμάτι κώδικα από την αρχή).
Όταν μια εξαίρεση δεν αντιμετωπιστεί καθόλου, ο διερμηνέας τερματίζει την εκτέλεση του προγράμματος ή επιστρέφει στον διαδραστικό κύριο βρόχο του. Και στις δύο περιπτώσεις, εκτυπώνει το ίχνος της στοίβας, εκτός αν η εξαίρεση είναιSystemExit
.
Οι εξαιρέσεις αναγνωρίζονται από στιγμιότυπα κλάσεων. Η ρήτραexcept
επιλέγεται ανάλογα με την κλάση του στιγμιότυπου: πρέπει να αναφέρεται στην κλάση του στιγμιότυπου ή σε μιαμη εικονική βασική κλάση αυτής. Το στιγμιότυπο μπορεί να παραληφθεί από τον διαχειριστή και να μεταφέρει πρόσθετες πληροφορίες σχετικά με την εξαιρετική συνθήκη.
Σημείωση
Τα μηνύματα εξαιρέσεων δεν αποτελούν μέρος του API της Python. Το περιεχόμενό τους μπορεί να αλλάξει από τη μία έκδοση της Python στην επόμενη χωρίς προειδοποίηση και δεν θα πρέπει να βασίζεται σε αυτά ο κώδικας που θα εκτελεστεί σε πολλαπλές εκδόσεις του διερμηνέα.
Δείτε επίσης την περιγραφή της δήλωσηςtry
στην ενότηταThe try statement και της δήλωσηςraise
στην ενότηταThe raise statement.
Υποσημειώσεις
[1]Αυτός ο περιορισμός προκύπτει επειδή ο κώδικας που εκτελείται από αυτές τις λειτουργίες δεν είναι διαθέσιμος τη στιγμή που το module μεταγλωττίζεται.