4. Μοντέλο εκτέλεσης
********************


4.1. Δομή ενός προγράμματος
===========================

Ένα πρόγραμμα Python αποτελείται από μπλοκ κώδικα. Ένα *μπλοκ* είναι
ένα κομμάτι κειμένου προγράμματος Python που εκτελείται ως μια μονάδα.
Τα παρακάτω είναι μπλοκ: ένα module, το σώμα μιας συνάρτησης, ο ένας
ορισμός κλάσης. Κάθε εντολή που πληκτρολογείται διαδραστικά αποτελεί
μπλοκ. Ένα αρχείο δέσμης ενεργειών (ένα αρχείο που δίνεται ως τυπική
είσοδος στο διερμηνέα ή καθορίζεται ως όρισμα γραμμής εντολών στον
διερμηνέα) είναι ένα μπλοκ κώδικα. Μια script εντολή (μια εντολή που
καθορίζεται στο διερμηνέα με την επιλογή "-c") είναι ένα μπλοκ κώδικα.
Μια ενότητα που εκτελείται ως ανωτέρου επιπέδου script (ως module
"__main__") από τη γραμμή εντολών χρησιμοποιώντας ένα όρισμα "-m"
όρισμα είναι επίσης ένα μπλοκ κώδικα. Το όρισμα συμβολοσειράς που
περνάει στις ενσωματωμένες συναρτήσεις "eval()" και "exec()" είναι ένα
μπλοκ κώδικα.

Ένα μπλοκ κώδικα εκτελείται σε ένα *πλαίσιο εκτέλεσης*. Ένα πλαίσιο
περιέχει ορισμένες πληροφορίες διαχείρισης (που χρησιμοποιούνται για
αποσφαλμάτωση) και καθορίζει που και πως συνεχίζεται η εκτέλεση μετά
την ολοκλήρωση της εκτέλεσης του μπλοκ κώδικα.


4.2. Ονομασία και σύνδεση
=========================


4.2.1. Σύνδεση ονομάτων
-----------------------

*Names* αναφέρονται σε αντικείμενα. Τα ονόματα εισάγονται μέσω
λειτουργιών δέσμευσης ονομάτων.

Οι παρακάτω δομές δεσμεύουν ονόματα:

* τυπικές παράμετροι συναρτήσεων,

* ορισμοί κλάσεων,

* ορισμοί συναρτήσεων

* εκφράσεις ανάθεσης

* targets που είναι αναγνωριστικά αν εμφανίζονται σε μια ανάθεση:

  * επικεφαλίδα βρόχου "for",

  * μετά το "as" σε μια δήλωση "with", σε ρήτρα "except", σε ρήτρα
    "except*" ή στο as-pattern κατά τη δομική αντιστοίχησης μοτίβων,

  * σε ένα στιγμιότυπο μοτίβου κατά τη δομική αντιστοίχησης μοτίβων

* δηλώσεις "import".

Η δήλωση "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 για παραδείγματα.

If the "global" statement occurs within a block, all uses of the names
specified in the statement refer to the bindings of those names in the
top-level namespace.  Names are resolved in the top-level namespace by
searching the global namespace, i.e. the namespace of the module
containing the code block, and the builtins namespace, the namespace
of the module "builtins".  The global namespace is searched first.  If
the names are not found there, the builtins namespace is searched.
The "global" statement must precede all uses of the listed names.

Η δήλωση "global" έχει το ίδιο πεδίο με μια λειτουργία σύνδεσης
ονόματος στο ίδιο μπλοκ. Αν το πλησιέστερο περιβάλλον πεδίου για μια
ελεύθερη μεταβλητή περιέχει μια δήλωση global, η ελεύθερη μεταβλητή
αντιμετωπίζεται ως καθολική.

The "nonlocal" statement causes corresponding names to refer to
previously bound variables in the nearest enclosing function scope.
"SyntaxError" is raised at compile time if the given name does not
exist in any enclosing function scope.

Ο χώρος ονομάτων για ένα module δημιουργείται αυτόματα την πρώτη φορά
που το module εισάγεται Το κύριο module για ένα script ονομάζεται
πάντα "__main__".

Class definition blocks and arguments to "exec()" and "eval()" are
special in the context of name resolution. A class definition is an
executable statement that may use and define names. These references
follow the normal rules for name resolution with an exception that
unbound local variables are looked up in the global namespace. The
namespace of the class definition becomes the attribute dictionary of
the class. The scope of names defined in a class block is limited to
the class block; it does not extend to the code blocks of methods --
this includes comprehensions and generator expressions since they are
implemented using a function scope.  This means that the following
will fail:

   class A:
       a = 42
       b = list(a + i for i in range(10))


4.2.3. Ενσωματωμένες συναρτήσεις και περιορισμένη εκτέλεση
----------------------------------------------------------

**Λεπτομέρεια υλοποίησης CPython:** Οι χρήστες δεν θα πρέπει να
τροποποιούν το "__builtins__"· είναι αυστηρά μια λεπτομέρεια
υλοποίησης. Οι χρήστες που θέλουν να παρακάμψουν τιμές στον χώρο
ονομάτων των ενσωματωμένων συναρτήσεων θα πρέπει να κάνουν "import" το
module "builtins" και να τροποποιούν τα χαρακτηριστικά του κατάλληλα.

Ο χώρος ονομάτων των ενσωματωμένων συναρτήσεων που σχετίζεται με την
εκτέλεση ενός μπλοκ κώδικα βρίσκεται στην πραγματικότητα μέσω
αναζήτησης του ονόματος "__builtins__" στον καθολικό του χώρο
ονομάτων· αυτό θα πρέπει να είναι ένα λεξικό ή ένα module (στη δεύτερη
περίπτωση χρησιμοποιείται το λεξικό του module). Από προεπιλογή, όταν
βρισκόμαστε στο module "__main__", το "__builtins__" είναι το
ενσωματωμένο module "builtins"· όταν βρισκόμαστε σε οποιοδήποτε άλλο
module, το "__builtins__" είναι ένα ψευδώνυμο για το λεξικό του ίδιου
του module "builtins".


4.2.4. Αλληλεπίδραση με δυναμικές λειτουργίες
---------------------------------------------

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

   i = 10
   def f():
       print(i)
   i = 42
   f()

Οι συναρτήσεις "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
    μεταγλωττίζεται.
