8. Σύνθετες εντολές
*******************

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

Οι εντολές "if", "while" και "for" υλοποιούν παραδοσιακές δομές ροής
ελέγχου. Η "try" καθορίζει χειριστές εξαιρέσεων ή/και κώδικα
εκκαθάρισης για μια ομάδα εντολών, ενώ η δήλωση "with" επιτρέπει την
εκτέλεση κώδικα αρχικοποίησης και οριστικοποίησης γύρω από ένα μπλοκ
κώδικα. Οι ορισμοί συναρτήσεων και κλάσεων είναι επίσης συντακτικά
σύνθετες εντολές.

Μια σύνθετη δήλωση αποτελείται από μία ή περισσότερες ‘ρήτρες’. Μία
ρήτρα αποτελείται από μια κεφαλίδα και μία ‘σουίτα’. Οι κεφαλίδες των
ρητρών μιας συγκεκριμένης σύνθετης εντολής βρίσκονται όλες στο ίδιο
επίπεδο εσοχής. Κάθε κεφαλίδα της ρήτρας ξεκινά με μια μοναδική
λέξη-κλειδί αναγνώρισης και καταλήγει σε άνω και κάτω τελεία. Μία
σουίτα είναι μια ομάδα εντολών που ελέγχονται από μία ρήτρα. Μία
σουίτα μπορεί να είναι μία ή περισσότερες απλές εντολές χωρισμένες με
ερωτηματικό στην ίδια γραμμή με την κεφαλίδα, ακολουθώντας την άνω και
κάτω τελεία της κεφαλίδας, ή μπορεί να είναι μία ή περισσότερες
εντολές με εσοχή σε επόμενες γραμμές. Μόνο η δεύτερη μορφή μιας
σουίτας μπορεί να περιέχει εμφωλευμένες σύνθετες εντολές· το ακόλουθο
δεν είναι έγκυρο, κυρίως επειδή δεν θα ήταν σαφές σε ποια ρήτρα "if"
θα ανήκε μία ακόλουθη ρήτρα "else":

   if test1: if test2: print(x)

Σημειώστε επίσης ότι το ερωτηματικό έχει ισχυρότερη προτεραιότητα από
την άνω και κάτω τελεία σε αυτό το πλαίσιο, οπότε στο ακόλουθο
παράδειγμα, εκτελούνται είτε όλες είτε καμία από τις κλήσεις της
"print()":

   if x < y < z: print(x); print(y); print(z)

Συνοψίζοντας:

   compound_stmt: if_stmt
                  | while_stmt
                  | for_stmt
                  | try_stmt
                  | with_stmt
                  | match_stmt
                  | funcdef
                  | classdef
                  | async_with_stmt
                  | async_for_stmt
                  | async_funcdef
   suite:         stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
   statement:     stmt_list NEWLINE | compound_stmt
   stmt_list:     simple_stmt (";" simple_stmt)* [";"]

Σημειώστε ότι οι εντολές τελειώνουν πάντα με ένα "NEWLINE" πιθανώς
ακολουθούμενο από ένα "DEDENT". Σημειώστε επίσης ότι οι προαιρετικές
ρήτρες συνέχειας ξεκινούν πάντα με μια λέξη-κλειδί που δεν μπορεί να
ξεκινήσει μια δήλωση, επομένως δεν υπάρχουν ασάφειες (το πρόβλημα του
'εκκρεμούς "else"' λύνεται στην Python απαιτώντας οι εμφωλευμένες
εντολές "if" να έχουν εσοχή).

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


8.1. Η δήλωση "if"
==================

Η δήλωση "if" χρησιμοποιείται για εκτέλεση υπό συνθήκη:

   if_stmt: "if" assignment_expression ":" suite
            ("elif" assignment_expression ":" suite)*
            ["else" ":" suite]

Επιλέγει ακριβώς μία από τις σουίτες αξιολογώντας τις εκφράσεις μία
προς μία μέχρι να βρεθεί μία που να είναι αληθής (δείτε την ενότητα
Λογικές λειτουργίες για τον ορισμό του αληθούς και του ψευδούς)· στη
συνέχεια εκτελείται αυτή η σουίτα (και κανένα άλλο μέρος της εντολής
"if" δεν εκτελείται ή αξιολογείται). Εάν όλες οι εκφράσεις είναι
ψευδείς, εκτελείται η σουίτα της ρήτρας "else", εάν υπάρχει.


8.2. Η δήλωση "while"
=====================

Η δήλωση "while" χρησιμοποιείται για επαναλαμβανόμενη εκτέλεση εφόσον
μια έκφραση είναι αληθής:

   while_stmt: "while" assignment_expression ":" suite
               ["else" ":" suite]

Ελέγχει επανειλημμένα την έκφραση και, εάν είναι αληθής, εκτελεί την
πρώτη σουίτα· εάν η έκφραση είναι ψευδής (το οποίο μπορεί να συμβεί
την πρώτη φορά που ελέγχεται) εκτελείται η σουίτα της ρήτρας "else",
εάν υπάρχει, και ο βρόχος τερματίζεται.

Μια δήλωση "break" που εκτελείται στην πρώτη σουίτα τερματίζει τον
βρόχο χωρίς να εκτελέσει τη σουίτα της ρήτρας "else". Μια δήλωση
"continue" που εκτελείται στην πρώτη σουίτα παραλείπει το υπόλοιπο της
σουίτας και επιστρέφει στον έλεγχο της έκφρασης.


8.3. Η δήλωση "for"
===================

Η δήλωση "for" χρησιμοποιείται για την επανάληψη στα στοιχεία μιας
ακολουθίας (όπως ένα αλφαριθμητικό, μία πλειάδα ή μία λίστα) ή άλλου
iterable αντικειμένου:

   for_stmt: "for" target_list "in" starred_expression_list ":" suite
             ["else" ":" suite]

The "starred_expression_list" expression is evaluated once; it should
yield an *iterable* object. An *iterator* is created for that
iterable. The first item provided by the iterator is then assigned to
the target list using the standard rules for assignments (see Εντολές
ανάθεσης), and the suite is executed. This repeats for each item
provided by the iterator. When the iterator is *exhausted*, the suite
in the "else" clause, if present, is executed, and the loop
terminates.

Μια δήλωση "break" που εκτελείται στην πρώτη σουίτα τερματίζει τον
βρόχο χωρίς να εκτελέσει τη σουίτα της ρήτρας "else". Μια δήλωση
"continue" που εκτελείται στην πρώτη σουίτα παραλείπει το υπόλοιπο της
σουίτας και συνεχίζει με το επόμενο στοιχείο, ή με τη ρήτρα "else" εάν
δεν υπάρχει επόμενο στοιχείο.

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

   for i in range(10):
       print(i)
       i = 5             # this will not affect the for-loop
                         # because i will be overwritten with the next
                         # index in the range

Τα ονόματα στη λίστα-στόχο δεν διαγράφονται όταν τελειώσει ο βρόχος,
αλλά εάν η ακολουθία είναι κενή, δεν θα τους έχει γίνει καμία ανάθεση
από τον βρόχο. Υπόδειξη: ο ενσωματωμένος τύπος "range()" αναπαριστά
αμετάβλητες αριθμητικές ακολουθίες ακεραίων. Για παράδειγμα, η
επανάληψη του "range(3)" διαδοχικά αποφέρει 0, 1, και έπειτα 2.

Άλλαξε στην έκδοση 3.11: Τα στοιχεία με αστερίσκο επιτρέπονται πλέον
στη λίστα εκφράσεων.


8.4. Η δήλωση "try"
===================

Η δήλωση "try" καθορίζει χειριστές εξαιρέσεων ή/και κώδικα εκκαθάρισης
για μια ομάδα εντολών:

   try_stmt:  try1_stmt | try2_stmt | try3_stmt
   try1_stmt: "try" ":" suite
              ("except" [expression ["as" identifier]] ":" suite)+
              ["else" ":" suite]
              ["finally" ":" suite]
   try2_stmt: "try" ":" suite
              ("except" "*" expression ["as" identifier] ":" suite)+
              ["else" ":" suite]
              ["finally" ":" suite]
   try3_stmt: "try" ":" suite
              "finally" ":" suite

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

Άλλαξε στην έκδοση 3.14: Υποστήριξη για προαιρετική αφαίρεση των
παρενθέσεων ομαδοποίησης όταν χρησιμοποιούνται πολλαπλοί τύποι
εξαιρέσεων. Δείτε το **PEP 758**.


8.4.1. ρήτρα "except"
---------------------

Οι ρήτρες "except" καθορίζουν έναν ή περισσότερους χειριστές
εξαιρέσεων. Όταν δεν προκύπτει καμία εξαίρεση στη ρήτρα "try", κανένας
χειριστής εξαίρεσης δεν εκτελείται. Όταν προκύψει μια εξαίρεση στη
σουίτα του "try", ξεκινά μια αναζήτηση για χειριστή εξαίρεσης. Αυτή η
αναζήτηση εξετάζει τις ρήτρες "except" με τη σειρά μέχρι να βρεθεί μία
που ταιριάζει με την εξαίρεση. Μία ρήτρα "except" χωρίς έκφραση, εάν
υπάρχει, πρέπει να είναι τελευταία· ταιριάζει με οποιαδήποτε εξαίρεση.

Για μία ρήτρα "except" με μια έκφραση, η έκφραση πρέπει να
αξιολογείται σε έναν τύπο εξαίρεσης ή σε μία πλειάδα τύπων εξαιρέσεων.
Οι παρενθέσεις μπορούν να παραλειφθούν εάν παρέχονται πολλαπλοί τύποι
εξαιρέσεων και η ρήτρα "as" δεν χρησιμοποιείται. Η εξαίρεση που έγινε
raise ταιριάζει με μία ρήτρα "except" του οποίου η έκφραση
αξιολογείται στην κλάση ή σε μια *μη εικονική βασική κλάση* του
αντικειμένου εξαίρεσης, ή σε μία πλειάδα που περιέχει μια τέτοια
κλάση.

Εάν καμία ρήτρα "except" δεν ταιριάζει με την εξαίρεση, η αναζήτηση
για έναν χειριστή εξαίρεσης συνεχίζεται στον περιβάλλοντα κώδικα και
στη στοίβα κλήσεων.  [1]

Εάν η αξιολόγηση μιας έκφρασης στην κεφαλίδα μιας ρήτρας "except"
κάνει raise μια εξαίρεση, η αρχική αναζήτηση για χειριστή ακυρώνεται
και μια αναζήτηση ξεκινά για τη νέα εξαίρεση στον περιβάλλοντα κώδικα
και στη στοίβα κλήσεων (αντιμετωπίζεται σαν να έκανε raise την
εξαίρεση ολόκληρη η δήλωση "try").

Όταν βρεθεί μία ρήτρα "except" που να ταιριάζει, η εξαίρεση ανατίθεται
στον στόχο που καθορίζεται μετά τη λέξη-κλειδί "as" σε αυτή τη ρήτρα
"except", εάν υπάρχει, και η σουίτα της ρήτρας "except" εκτελείται.
Όλες οι ρήτρες "except" πρέπει να έχουν ένα εκτελέσιμο μπλοκ. Όταν
επιτευχθεί το τέλος αυτού του μπλοκ, η εκτέλεση συνεχίζεται κανονικά
μετά από ολόκληρη την δήλωση "try". (Αυτό σημαίνει ότι εάν υπάρχουν
δύο εμφωλευμένοι χειριστές για την ίδια εξαίρεση, και η εξαίρεση
συμβεί στη ρήτρα "try" του εσωτερικού χειριστή, ο εξωτερικός χειριστής
δεν θα χειριστεί την εξαίρεση.)

When an exception has been assigned using "as target", it is cleared
at the end of the "except" clause.  This is as if:

   except E as N:
       foo

was translated to:

   except E as N:
       try:
           foo
       finally:
           del N

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

Πριν εκτελεστεί η σουίτα μιας ρήτρας "except", η εξαίρεση αποθηκεύεται
στο module "sys", όπου είναι προσβάσιμη μέσα από το σώμα της ρήτρας
"except" καλώντας την "sys.exception()". Όταν κλείνει ένας χειριστής
εξαίρεσης, η εξαίρεση που αποθηκεύτηκε στο module "sys" επαναφέρεται
στην προηγούμενη τιμή της:

   >>> print(sys.exception())
   None
   >>> try:
   ...     raise TypeError
   ... except:
   ...     print(repr(sys.exception()))
   ...     try:
   ...          raise ValueError
   ...     except:
   ...         print(repr(sys.exception()))
   ...     print(repr(sys.exception()))
   ...
   TypeError()
   ValueError()
   TypeError()
   >>> print(sys.exception())
   None


8.4.2. ρήτρα "except*"
----------------------

The "except*" clause(s) specify one or more handlers for groups of
exceptions ("BaseExceptionGroup" instances). A "try" statement can
have either "except" or "except*" clauses, but not both. The exception
type for matching is mandatory in the case of "except*", so "except*:"
is a syntax error. The type is interpreted as in the case of "except",
but matching is performed on the exceptions contained in the group
that is being handled. A "TypeError" is raised if a matching type is a
subclass of "BaseExceptionGroup", because that would have ambiguous
semantics.

Όταν μια ομάδα εξαιρέσεων γίνει raise στο μπλοκ try, κάθε ρήτρα
"except*" τη διαχωρίζει (δείτε τη "split()") στις υπο-ομάδες
ταιριαστών και μη ταιριαστών εξαιρέσεων. Εάν η ταιριαστή υπο-ομάδα δεν
είναι κενή, γίνεται η εξαίρεση υπό χειρισμό (η τιμή που επιστρέφεται
από την "sys.exception()") και ανατίθεται στον στόχο της ρήτρας
"except*" (εάν υπάρχει). Έπειτα, εκτελείται το σώμα της ρήτρας
"except*". Εάν η μη ταιριαστή υπο-ομάδα δεν είναι κενή, επεξεργάζεται
από το επόμενο "except*" με τον ίδιο τρόπο. Αυτό συνεχίζεται μέχρι να
ταιριάξουν όλες οι εξαιρέσεις στην ομάδα, ή να εκτελεστεί η τελευταία
ρήτρα "except*".

After all "except*" clauses execute, the group of unhandled exceptions
is merged with any exceptions that were raised or re-raised from
within "except*" clauses. This merged exception group propagates on:

   >>> try:
   ...     raise ExceptionGroup("eg",
   ...         [ValueError(1), TypeError(2), OSError(3), OSError(4)])
   ... except* TypeError as e:
   ...     print(f'caught {type(e)} with nested {e.exceptions}')
   ... except* OSError as e:
   ...     print(f'caught {type(e)} with nested {e.exceptions}')
   ...
   caught <class 'ExceptionGroup'> with nested (TypeError(2),)
   caught <class 'ExceptionGroup'> with nested (OSError(3), OSError(4))
     + Exception Group Traceback (most recent call last):
     |   File "<doctest default[0]>", line 2, in <module>
     |     raise ExceptionGroup("eg",
     |         [ValueError(1), TypeError(2), OSError(3), OSError(4)])
     | ExceptionGroup: eg (1 sub-exception)
     +-+---------------- 1 ----------------
       | ValueError: 1
       +------------------------------------

Εάν η εξαίρεση που έγινε raise από το μπλοκ "try" δεν είναι ομάδα
εξαιρέσεων και ο τύπος της ταιριάζει με μία από τις ρήτρες "except*",
τότε πιάνεται και περιτυλίγεται από μια ομάδα εξαιρέσεων με μία κενή
συμβολοσειρά μηνύματος. Αυτό διασφαλίζει ότι ο τύπος του στόχου "e"
είναι συνεπώς "BaseExceptionGroup":

   >>> try:
   ...     raise BlockingIOError
   ... except* BlockingIOError as e:
   ...     print(repr(e))
   ...
   ExceptionGroup('', (BlockingIOError(),))

Τα "break", "continue" και "return" δεν μπορούν να εμφανιστούν σε μία
ρήτρα "except*".


8.4.3. ρήτρα "else"
-------------------

Η προαιρετική ρήτρα "else" εκτελείται εάν η ροή ελέγχου αφήσει τη
σουίτα "try", δεν έγινε raise καμία εξαίρεση, και δεν εκτελέστηκε
καμία δήλωση "return", "continue", ή "break". Οι εξαιρέσεις στη ρήτρα
"else" δεν χειρίζονται από τις προηγούμενες ρήτρες "except".


8.4.4. ρήτρα "finally"
----------------------

Εάν το "finally" υπάρχει, καθορίζει έναν χειριστή 'εκκαθάρισης'. Η
ρήτρα "try" εκτελείται, συμπεριλαμβανομένων τυχόν ρητρών "except" και
"else". Εάν προκύψει εξαίρεση σε κάποια από τις ρήτρες και δεν υπάρξει
χειρισμός, η εξαίρεση αποθηκεύεται προσωρινά. Η ρήτρα "finally"
εκτελείται. Εάν υπάρχει μια αποθηκευμένη εξαίρεση, γίνεται re-raise
στο τέλος της ρήτρας "finally". Εάν η ρήτρα "finally" κάνει raise μια
άλλη εξαίρεση, η αποθηκευμένη εξαίρεση ορίζεται ως το πλαίσιο της νέας
εξαίρεσης. Εάν η ρήτρα "finally" εκτελεί μια δήλωση "return", "break"
ή "continue", η αποθηκευμένη εξαίρεση απορρίπτεται. Για παράδειγμα,
αυτή η συνάρτηση επιστρέφει 42.

   def f():
       try:
           1/0
       finally:
           return 42

Οι πληροφορίες εξαίρεσης δεν είναι διαθέσιμες στο πρόγραμμα κατά την
εκτέλεση της ρήτρας "finally".

Όταν μια δήλωση "return", "break" ή "continue" εκτελείται στη σουίτα
"try" μιας εντολής "try"..."finally", η ρήτρα "finally" εκτελείται
επίσης 'κατά την έξοδο'.

Η τιμή επιστροφής μιας συνάρτησης καθορίζεται από την τελευταία δήλωση
"return" που εκτελέστηκε. Εφόσον η ρήτρα "finally" εκτελείται πάντα,
μια δήλωση "return" που εκτελείται στη ρήτρα "finally" θα είναι πάντα
η τελευταία που θα εκτελεστεί. Η ακόλουθη συνάρτηση επιστρέφει
'finally'.

   def foo():
       try:
           return 'try'
       finally:
           return 'finally'

Άλλαξε στην έκδοση 3.8: Πριν από την Python 3.8, μια δήλωση "continue"
ήταν μη έγκυρη στη ρήτρα "finally" λόγω ενός προβλήματος με την
υλοποίηση.

Άλλαξε στην έκδοση 3.14: Ο compiler εκπέμπει ένα "SyntaxWarning" όταν
εμφανίζεται ένα "return", "break" ή "continue" σε ένα μπλοκ "finally"
(δείτε **PEP 765**).


8.5. Η δήλωση "with"
====================

Η δήλωση "with" χρησιμοποιείται για να περιτυλίξει την εκτέλεση ενός
μπλοκ με μεθόδους ορισμένες από έναν διαχειριστή πλαισίου (δείτε την
ενότητα Με τους Διαχειριστές Περιβάλλοντος Δήλωσης). Αυτό επιτρέπει
την ενθυλάκωση κοινών μοτίβων χρήσης "try"..."except"..."finally" για
βολική επαναχρησιμοποίηση.

   with_stmt:          "with" ( "(" with_stmt_contents ","? ")" | with_stmt_contents ) ":" suite
   with_stmt_contents: with_item ("," with_item)*
   with_item:          expression ["as" target]

Η εκτέλεση της εντολής "with" με ένα "αντικείμενο" προχωρά ως εξής:

1. Η έκφραση πλαισίου (η έκφραση που δίνεται στο "with_item")
   αξιολογείται για να ληφθεί ένας διαχειριστής πλαισίου.

2. Φορτώνεται η "__enter__()" του διαχειριστή πλαισίου για μελλοντική
   χρήση.

3. Φορτώνεται η "__exit__()" του διαχειριστή πλαισίου για μελλοντική
   χρήση.

4. Καλείται η μέθοδος "__enter__()" του διαχειριστή πλαισίου.

5. Εάν συμπεριλήφθηκε ένας στόχος στην δήλωση "with", η τιμή
   επιστροφής της "__enter__()" του ανατίθεται.

   Σημείωση:

     Η δήλωση "with" εγγυάται ότι εάν η μέθοδος "__enter__()"
     επιστρέψει το αποτέλεσμα χωρίς σφάλμα, τότε η "__exit__()" θα
     κληθεί πάντα. Επομένως, εάν προκύψει σφάλμα κατά την ανάθεση στη
     λίστα-στόχο, θα αντιμετωπιστεί με τον ίδιο τρόπο όπως ένα σφάλμα
     που προκύπτει μέσα στη σουίτα. Δείτε το βήμα 7 παρακάτω.

6. Η σουίτα εκτελείται.

7. Καλείται η μέθοδος "__exit__()" του διαχειριστή πλαισίου. Εάν μια
   εξαίρεση προκάλεσε την έξοδο από τη σουίτα, ο τύπος, η τιμή και η
   ιχνηλάτησή της περνούν ως ορίσματα στην "__exit__()". Διαφορετικά,
   παρέχονται τρία ορίσματα "None".

   Εάν υπήρξε έξοδος από τη σουίτα λόγω εξαίρεσης, και η τιμή
   επιστροφής από τη μέθοδο "__exit__()" ήταν false, η εξαίρεση
   γίνεται re-raise. Εάν η τιμή επιστροφής ήταν true, η εξαίρεση
   καταστέλλεται, και η εκτέλεση συνεχίζεται με την δήλωση που
   ακολουθεί την δήλωση "with".

   Εάν υπήρξε έξοδος από τη σουίτα για οποιονδήποτε λόγο εκτός από
   εξαίρεση, η τιμή επιστροφής από την "__exit__()" αγνοείται, και η
   εκτέλεση προχωρά στην κανονική θέση για το είδος της εξόδου που
   πραγματοποιήθηκε.

Ο ακόλουθος κώδικας:

   with EXPRESSION as TARGET:
       SUITE

είναι σημασιολογικά ισοδύναμος με:

   manager = (EXPRESSION)
   enter = manager.__enter__
   exit = manager.__exit__
   value = enter()
   hit_except = False

   try:
       TARGET = value
       SUITE
   except:
       hit_except = True
       if not exit(*sys.exc_info()):
           raise
   finally:
       if not hit_except:
           exit(None, None, None)

except that implicit special method lookup is used for "__enter__()"
and "__exit__()".

Με περισσότερα από ένα στοιχεία, οι διαχειριστές πλαισίου
επεξεργάζονται σαν να είχαν εμφωλευτεί πολλαπλές εντολές "with":

   with A() as a, B() as b:
       SUITE

είναι σημασιολογικά ισοδύναμος με:

   with A() as a:
       with B() as b:
           SUITE

Μπορείτε επίσης να γράψετε διαχειριστές πλαισίου πολλαπλών στοιχείων
σε πολλές γραμμές, αν τα στοιχεία περικλείονται σε παρενθέσεις. Για
παράδειγμα:

   with (
       A() as a,
       B() as b,
   ):
       SUITE

Άλλαξε στην έκδοση 3.1: Υποστήριξη για πολλαπλές εκφράσεις πλαισίου.

Άλλαξε στην έκδοση 3.10: Υποστήριξη για χρήση παρενθέσεων ομαδοποίησης
ώστε να διασπαστεί η δήλωση σε πολλές γραμμές.

Δείτε επίσης:

  **PEP 343** - Η δήλωση "with"
     Οι προδιαγραφές, το υπόβαθρο και τα παραδείγματα για την δήλωση
     "with" της Python.


8.6. Η δήλωση "match"
=====================

Added in version 3.10.

Η δήλωση match χρησιμοποιείται για ταίριασμα προτύπων. Σύνταξη:

   match_stmt:   'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT
   subject_expr: flexible_expression "," [flexible_expression_list [',']]
                 | assignment_expression
   case_block:   'case' patterns [guard] ":" suite

Σημείωση:

  Αυτή η ενότητα χρησιμοποιεί μονά εισαγωγικά για να υποδηλώσει τα
  soft keywords.

Το ταίριασμα προτύπων παίρνει ένα πρότυπο ως είσοδο (μετά το "case")
και μια τιμή θέματος (μετά το "match"). Το πρότυπο (το οποίο μπορεί να
περιέχει υπο-πρότυπα) ταιριάζεται με την τιμή θέματος. Τα αποτελέσματα
είναι:

* Μια επιτυχία ή αποτυχία ταιριάσματος (επίσης ονομάζεται επιτυχία ή
  αποτυχία προτύπου).

* Πιθανή δέσμευση ταιριασμένων τιμών σε ένα όνομα. Οι προϋποθέσεις για
  αυτό συζητούνται περαιτέρω παρακάτω.

Οι λέξεις-κλειδιά "match" και "case" είναι soft keywords.

Δείτε επίσης:

  * **PEP 634** -- Ταίριασμα Δομικών Προτύπων: Προδιαγραφή

  * **PEP 636** -- Ταίριασμα Δομικών Προτύπων: Εγχειρίδιο


8.6.1. Επισκόπηση
-----------------

Ακολουθεί μια επισκόπηση της λογικής ροής μιας εντολής match:

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

2. Κάθε πρότυπο σε ένα "case_block" προσπαθεί να ταιριάξει με την τιμή
   του θέματος. Οι συγκεκριμένοι κανόνες για επιτυχία ή αποτυχία
   περιγράφονται παρακάτω. Η προσπάθεια ταιριάσματος μπορεί επίσης να
   δεσμεύσει κάποια ή όλα τα αυτόνομα ονόματα εντός του προτύπου. Οι
   ακριβείς κανόνες δέσμευσης προτύπων διαφέρουν ανά τύπο προτύπου και
   καθορίζονται παρακάτω. **Οι δεσμεύσεις ονομάτων, που γίνονται κατά
   τη διάρκεια ενός επιτυχημένου ταιριάσματος προτύπου, επιβιώνουν από
   το εκτελεσμένο μπλοκ και μπορούν να χρησιμοποιηθούν μετά την δήλωση
   match**.

   Σημείωση:

     Κατά τη διάρκεια αποτυχημένων ταιριασμάτων προτύπων, ορισμένα
     υπο-πρότυπα μπορεί να πετύχουν. Μην βασίζεστε στο ότι θα
     πραγματοποιηθούν δεσμεύσεις για ένα αποτυχημένο ταίριασμα.
     Αντίστροφα, μην βασίζεστε στο ότι οι μεταβλητές θα παραμείνουν
     αμετάβλητες μετά από ένα αποτυχημένο ταίριασμα. Η ακριβής
     συμπεριφορά εξαρτάται από την υλοποίηση και μπορεί να διαφέρει.
     Πρόκειται για μια σκόπιμη απόφαση ώστε να επιτραπεί σε
     διαφορετικές υλοποιήσεις να προσθέσουν βελτιστοποιήσεις.

3. Εάν το πρότυπο επιτύχει, αξιολογείται ο αντίστοιχος guard (εάν
   υπάρχει). Σε αυτήν την περίπτωση είναι εγγυημένο ότι έχουν
   πραγματοποιηθεί όλες οι δεσμεύσεις ονομάτων.

   * Εάν ο guard αξιολογηθεί ως αληθής ή λείπει, εκτελείται το "block"
     μέσα στο "case_block".

   * Διαφορετικά, δοκιμάζεται το επόμενο "case_block" όπως
     περιγράφεται παραπάνω.

   * Εάν δεν υπάρχουν περαιτέρω case μπλοκ, η δήλωση match
     ολοκληρώνεται.

Σημείωση:

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

Ένα παράδειγμα εντολής match:

   >>> flag = False
   >>> match (100, 200):
   ...    case (100, 300):  # Mismatch: 200 != 300
   ...        print('Case 1')
   ...    case (100, 200) if flag:  # Successful match, but guard fails
   ...        print('Case 2')
   ...    case (100, y):  # Matches and binds y to 200
   ...        print(f'Case 3, y: {y}')
   ...    case _:  # Pattern not attempted
   ...        print('Case 4, I match anything!')
   ...
   Case 3, y: 200

Σε αυτήν την περίπτωση, το "if flag" είναι ένας guard. Διαβάστε
περισσότερα για αυτό στην επόμενη ενότητα.


8.6.2. Guards
-------------

   guard: "if" assignment_expression

Ένας "guard" (που αποτελεί μέρος του "case") πρέπει να επιτύχει
προκειμένου να εκτελεστεί ο κώδικας μέσα στο μπλοκ "case". Παίρνει τη
μορφή: "if" ακολουθούμενο από μια έκφραση.

Η λογική ροή ενός μπλοκ "case" με έναν "guard" έχει ως εξής:

1. Ελέγχει ότι το πρότυπο στο μπλοκ "case" επέτυχε. Εάν το πρότυπο
   απέτυχε, ο "guard" δεν αξιολογείται και ελέγχεται το επόμενο μπλοκ
   "case".

2. Εάν το πρότυπο επέτυχε, αξιολογείται ο "guard".

   * Εάν η συνθήκη του "guard" αξιολογηθεί ως αληθής, επιλέγεται το
     μπλοκ case.

   * Εάν η συνθήκη του "guard" αξιολογηθεί ως ψευδής, το μπλοκ case
     δεν επιλέγεται.

   * Εάν ο "guard" κάνει raise μια εξαίρεση κατά την αξιολόγηση, η
     εξαίρεση ανεβαίνει προς τα πάνω.

Οι guards επιτρέπεται να έχουν παρενέργειες καθώς είναι εκφράσεις. Η
αξιολόγηση των guards πρέπει να προχωρά από το πρώτο έως το τελευταίο
case μπλοκ, ένα προς ένα, παραλείποντας τα case μπλοκ των οποίων τα
πρότυπα δεν επιτυγχάνουν όλα. (Δηλαδή, η αξιολόγηση των guards πρέπει
να γίνει με τη σειρά.) Η αξιολόγηση των guards πρέπει να σταματήσει
μόλις επιλεγεί ένα case μπλοκ.


8.6.3. Αδιάσειστα Case Blocks
-----------------------------

Ένα αδιάσειστο case μπλοκ είναι ένα case μπλοκ που ταιριάζει με τα
πάντα. Μια δήλωση match μπορεί να έχει το πολύ ένα αδιάσειστο case
μπλοκ, και πρέπει να είναι το τελευταίο.

Ένα case μπλοκ θεωρείται αδιάσειστο εάν δεν έχει guard και το πρότυπό
του είναι αδιάσειστο. Ένα πρότυπο θεωρείται αδιάσειστο εάν μπορούμε να
αποδείξουμε μόνο από τη σύνταξή του ότι θα επιτυγχάνει πάντα. Μόνο τα
ακόλουθα πρότυπα είναι αδιάσειστα:

* AS Πρότυπα των οποίων η αριστερή πλευρά είναι αδιάσειστη

* OR Πρότυπα που περιέχουν τουλάχιστον ένα αδιάσειστο πρότυπο

* Μοτίβα Δέσμευσης

* Μοτίβα Μπαλαντέρ

* παρενθετικά αδιάσειστα πρότυπα


8.6.4. Πρότυπα
--------------

Σημείωση:

  Αυτή η ενότητα χρησιμοποιεί σημειογραφίες γραμματικής πέρα από το
  τυπικό EBNF:

  * η σημειογραφία "SEP.RULE+" είναι συντομογραφία για το "RULE (SEP
    RULE)*"

  * η σημειογραφία "!RULE" είναι συντομογραφία για έναν αρνητικό
    ισχυρισμό lookahead

Η σύνταξη ανωτέρου επιπέδου για τα "patterns" είναι:

   patterns:       open_sequence_pattern | pattern
   pattern:        as_pattern | or_pattern
   closed_pattern: | literal_pattern
                   | capture_pattern
                   | wildcard_pattern
                   | value_pattern
                   | group_pattern
                   | sequence_pattern
                   | mapping_pattern
                   | class_pattern

Οι παρακάτω περιγραφές θα περιλαμβάνουν μια περιγραφή "με απλά λόγια"
του τι κάνει ένα πρότυπο για σκοπούς επεξήγησης (ευχαριστίες στον
Raymond Hettinger για ένα έγγραφο που ενέπνευσε τις περισσότερες
περιγραφές). Σημειώστε ότι αυτές οι περιγραφές προορίζονται καθαρά για
σκοπούς επεξήγησης και **ενδέχεται να μην** αντανακλούν την υποκείμενη
υλοποίηση. Επιπλέον, δεν καλύπτουν όλες τις έγκυρες μορφές.


8.6.4.1. OR Πρότυπα
~~~~~~~~~~~~~~~~~~~

Ένα OR πρότυπο αποτελείται από δύο ή περισσότερα πρότυπα χωρισμένα με
κάθετες γραμμές "|". Σύνταξη:

   or_pattern: "|".closed_pattern+

Μόνο το τελικό υπο-πρότυπο μπορεί να είναι αδιάσειστο, και κάθε
υπο-πρότυπο πρέπει να δεσμεύει το ίδιο σύνολο ονομάτων για να
αποφευχθεί η ασάφεια.

Ένα OR πρότυπο ταιριάζει με καθένα από τα υπο-πρότυπά του διαδοχικά με
την τιμή του θέματος, μέχρι κάποιο να επιτύχει. Το OR πρότυπο
θεωρείται τότε επιτυχημένο. Διαφορετικά, εάν κανένα από τα υπο-μοτίβα
δεν επιτύχει, το OR πρότυπο αποτυγχάνει.

Με απλά λόγια, το "P1 | P2 | ..." θα προσπαθήσει να ταιριάξει το "P1",
εάν αποτύχει θα προσπαθήσει να ταιριάξει το "P2", επιτυγχάνοντας
αμέσως εάν οποιοδήποτε πετύχει, αποτυγχάνοντας διαφορετικά.


8.6.4.2. AS Πρότυπα
~~~~~~~~~~~~~~~~~~~

Ένα AS πρότυπο ταιριάζει με ένα OR πρότυπο στα αριστερά της
λέξης-κλειδιού "as" έναντι ενός θέματος. Σύνταξη:

   as_pattern: or_pattern "as" capture_pattern

Εάν το OR πρότυπο αποτύχει, το AS πρότυπο αποτυγχάνει. Διαφορετικά, το
AS πρότυπο δεσμεύει το θέμα στο όνομα στα δεξιά της λέξης-κλειδιού as
και επιτυγχάνει. Το "capture_pattern" δεν μπορεί να είναι "_".

Με απλά λόγια, το "P as NAME" θα ταιριάξει με το "P", και σε περίπτωση
επιτυχίας θα ορίσει "NAME = <subject>".


8.6.4.3. Πρότυπα Λεκτικών Σταθερών
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ένα πρότυπο λεκτικής σταθεράς αντιστοιχεί στα περισσότερα literals
στην Python. Σύνταξη:

   literal_pattern: signed_number
                    | signed_number "+" NUMBER
                    | signed_number "-" NUMBER
                    | strings
                    | "None"
                    | "True"
                    | "False"
   signed_number:   ["+" | "-"] NUMBER

Ο κανόνας "strings" και το token "NUMBER" ορίζονται στο standard
Python grammar. Υποστηρίζονται συμβολοσειρές με τριπλά εισαγωγικά.
Υποστηρίζονται ακατέργαστες συμβολοσειρές και byte συμβολοσειρές. Τα
f-strings και τα t-strings δεν υποστηρίζονται.

Οι μορφές "signed_number '+' NUMBER" και "signed_number '-' NUMBER"
είναι για την έκφραση μιγαδικών αριθμών· απαιτούν έναν πραγματικό
αριθμό αριστερά και έναν φανταστικό αριθμό δεξιά. Π.χ. "3 + 4j".

Με απλά λόγια, το "LITERAL" θα πετύχει μόνο εάν "<subject> ==
LITERAL". Για τα singletons "None", "True" και "False",
χρησιμοποιείται ο τελεστής "is".


8.6.4.4. Μοτίβα Δέσμευσης
~~~~~~~~~~~~~~~~~~~~~~~~~

Ένα μοτίβο δέσμευσης δεσμεύει την τιμή του θέματος σε ένα όνομα.
Σύνταξη:

   capture_pattern: !'_' NAME

Μία μόνο κάτω παύλα "_" δεν μοτίβο δέσμευσης (αυτό εκφράζει το
"!'_'"). Αντιθέτως, αντιμετωπίζεται ως "wildcard_pattern".

Σε ένα δεδομένο μοτίβο, ένα δεδομένο όνομα μπορεί να δεσμευτεί μόνο
μία φορά. Π.χ. το "case x, x: ..." είναι μη έγκυρο, ενώ το "case [x] |
x: ..." επιτρέπεται.

Τα μοτίβα δέσμευσης επιτυγχάνουν πάντα. Η δέσμευση ακολουθεί τους
κανόνες εύρους που καθιερώθηκαν από τον τελεστή έκφρασης ανάθεσης στο
**PEP 572**· το όνομα γίνεται μια τοπική μεταβλητή στο πλησιέστερο
περιέχουν εύρος συνάρτησης, εκτός εάν υπάρχει μια εφαρμόσιμη δήλωση
"global" ή "nonlocal".

Με απλά λόγια, το "NAME" θα πετυχαίνει πάντα και θα ορίζει το "NAME =
<subject>".


8.6.4.5. Μοτίβα Μπαλαντέρ
~~~~~~~~~~~~~~~~~~~~~~~~~

Ένα μοτίβο μπαλαντέρ επιτυγχάνει πάντα (ταιριάζει με τα πάντα) και δεν
δεσμεύει κανένα όνομα. Σύνταξη:

   wildcard_pattern: '_'

Το "_" είναι ένα soft keyword εντός οποιουδήποτε μοτίβου, αλλά μόνο
εντός μοτίβων. Είναι ένα αναγνωριστικό, ως συνήθως, ακόμη και εντός
των εκφράσεων θέματος στο "match", στα "guard", και στα μπλοκ "case".

Με απλά λόγια, το "_" θα επιτυγχάνει πάντα.


8.6.4.6. Μοτίβα Τιμής
~~~~~~~~~~~~~~~~~~~~~

Ένα μοτίβο τιμής αναπαριστά μια ονομασμένη τιμή στην Python. Σύνταξη:

   value_pattern: attr
   attr:          name_or_attr "." NAME
   name_or_attr:  attr | NAME

Το όνομα με τελείες στο μοτίβο αναζητείται χρησιμοποιώντας τους
τυπικούς κανόνες ανάλυσης ονομάτων της Python. Το πρότυπο επιτυγχάνει
εάν η τιμή που βρέθηκε συγκρίνεται ως ίση με την τιμή του θέματος
(χρησιμοποιώντας τον τελεστή ισότητας "==").

Με απλά λόγια, το "NAME1.NAME2" θα πετύχει μόνο εάν "<subject> ==
NAME1.NAME2"

Σημείωση:

  Εάν η ίδια τιμή εμφανίζεται πολλές φορές στην ίδια δήλωση match, ο
  διερμηνέας μπορεί να αποθηκεύσει στην προσωρινή μνήμη την πρώτη τιμή
  που βρέθηκε και να την επαναχρησιμοποιήσει αντί να επαναλάβει την
  ίδια αναζήτηση. Αυτή η προσωρινή μνήμη είναι αυστηρά συνδεδεμένη με
  μια δεδομένη εκτέλεση μιας δεδομένης εντολής match.


8.6.4.7. Μοτίβα Ομαδοποίησης
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

   group_pattern: "(" pattern ")"

Με απλά λόγια, το "(P)" έχει το ίδιο αποτέλεσμα με το "P".


8.6.4.8. Μοτίβα Ακολουθίας
~~~~~~~~~~~~~~~~~~~~~~~~~~

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

   sequence_pattern:       "[" [maybe_sequence_pattern] "]"
                           | "(" [open_sequence_pattern] ")"
   open_sequence_pattern:  maybe_star_pattern "," [maybe_sequence_pattern]
   maybe_sequence_pattern: ",".maybe_star_pattern+ ","?
   maybe_star_pattern:     star_pattern | pattern
   star_pattern:           "*" (capture_pattern | wildcard_pattern)

Δεν υπάρχει διαφορά, εάν χρησιμοποιούνται παρενθέσεις ή αγκύλες για τα
μοτίβα ακολουθίας (δηλαδή "(...)" έναντι "[...]").

Σημείωση:

  Ένα μεμονωμένο μοτίβο περικλειόμενο σε παρενθέσεις χωρίς τελικό
  κόμμα (π.χ. "(3 | 4)") είναι ένα μοτίβο ομαδοποίησης. Ενώ ένα
  μεμονωμένο μοτίβο περικλειόμενο σε αγκύλες (π.χ. "[3 | 4]")
  εξακολουθεί να είναι ένα μοτίβο ακολουθίας.

Μπορεί να υπάρχει το πολύ ένα υπο-μοτίβο με αστερίσκο σε ένα μοτίβο
ακολουθίας. Το υπο-μοτίβο με αστερίσκο μπορεί να εμφανιστεί σε
οποιαδήποτε θέση. Εάν δεν υπάρχει υπο-μοτίβο με αστερίσκο, το μοτίβο
ακολουθίας είναι σταθερού μήκους· διαφορετικά είναι μεταβλητού μήκους.

Ακολουθεί η λογική ροή για το ταίριασμα ενός μοτίβου ακολουθίας έναντι
μιας τιμής θέματος:

1. Εάν η τιμή του θέματος δεν είναι μια ακολουθία [2], το μοτίβο
   ακολουθίας αποτυγχάνει.

2. Εάν η τιμή του θέματος είναι στιγμιότυπο των "str", "bytes" ή
   "bytearray" το μοτίβο ακολουθίας αποτυγχάνει.

3. Τα επόμενα βήματα εξαρτώνται από το αν το μοτίβο ακολουθίας είναι
   σταθερού ή μεταβλητού μήκους.

   Εάν το μοτίβο ακολουθίας είναι σταθερού μήκους:

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

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

   Διαφορετικά, εάν το μοτίβο ακολουθίας είναι μεταβλητού μήκους:

   1. Εάν το μήκος της ακολουθίας θέματος είναι μικρότερο από τον
      αριθμό των υπο-μοτίβων χωρίς αστερίσκο, το μοτίβο ακολουθίας
      αποτυγχάνει.

   2. Τα αρχικά υπο-μοτίβα χωρίς αστερίσκο ταιριάζουν με τα αντίστοιχα
      στοιχεία τους όπως και για τις ακολουθίες σταθερού μήκους.

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

   4. Τα εναπομείναντα υπο-μοτίβα χωρίς αστερίσκο ταιριάζουν με τα
      αντίστοιχα στοιχεία του θέματος, όπως και για μια ακολουθία
      σταθερού μήκους.

   Σημείωση:

     Το μήκος της ακολουθίας θέματος λαμβάνεται μέσω της "len()"
     (δηλαδή μέσω του πρωτοκόλλου "__len__()"). Αυτό το μήκος μπορεί
     να αποθηκευτεί στην προσωρινή μνήμη από τον διερμηνέα με παρόμοιο
     τρόπο όπως τα μοτίβα τιμής.

Με απλά λόγια, το "[P1, P2, P3," ... ", P<N>]" ταιριάζει μόνο εάν
συμβούν όλα τα ακόλουθα:

* έλεγχος ότι το "<subject>" είναι μια ακολουθία

* "len(subject) == <N>"

* το "P1" ταιριάζει στο "<subject>[0]" (σημειώστε ότι αυτό το
  ταίριασμα μπορεί επίσης να δεσμεύσει ονόματα)

* το "P2" ταιριάζει στο "<subject>[1]" (σημειώστε ότι αυτό το
  ταίριασμα μπορεί επίσης να δεσμεύσει ονόματα)

* ... και ούτω καθεξής για το αντίστοιχο ζεύγος μοτίβου/στοιχείου.


8.6.4.9. Μοτίβα Αντιστοίχισης
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Ένα μοτίβο αντιστοίχισης περιέχει ένα ή περισσότερα μοτίβα
κλειδιού-τιμής. Η σύνταξη είναι παρόμοια με την κατασκευή ενός
λεξικού. Σύνταξη:

   mapping_pattern:     "{" [items_pattern] "}"
   items_pattern:       ",".key_value_pattern+ ","?
   key_value_pattern:   (literal_pattern | value_pattern) ":" pattern
                        | double_star_pattern
   double_star_pattern: "**" capture_pattern

Μπορεί να υπάρχει το πολύ ένα μοτίβο με διπλό αστερίσκο σε ένα μοτίβο
αντιστοίχισης. Το μοτίβο με διπλό αστερίσκο πρέπει να είναι το
τελευταίο υπο-μοτίβο στο μοτίβο αντιστοίχισης.

Δεν επιτρέπονται διπλότυπα κλειδιά σε μοτίβα αντιστοίχισης. Τα
διπλότυπα λεκτικά κλειδιά θα κάνουν raise ένα "SyntaxError". Δύο
κλειδιά που κατά τα άλλα έχουν την ίδια τιμή θα κάνουν raise ένα
"ValueError" κατά τον χρόνο εκτέλεσης.

Ακολουθεί η λογική ροή για το ταίριασμα ενός μοτίβου αντιστοίχισης
έναντι μιας τιμής θέματος:

1. Εάν η τιμή του θέματος δεν είναι μία αντιστοίχιση [3], το μοτίβο
   αντιστοίχισης αποτυγχάνει.

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

3. Εάν ανιχνευτούν διπλότυπα κλειδιά στο μοτίβο αντιστοίχισης, το
   μοτίβο θεωρείται μη έγκυρο. Γίνεται raise ένα "SyntaxError" για
   διπλότυπες λεκτικές τιμές· ή ένα "ValueError" για ονομασμένα
   κλειδιά με την ίδια τιμή.

Σημείωση:

  Τα ζεύγη κλειδιού-τιμής ταιριάζονται χρησιμοποιώντας τη μορφή των
  δύο ορισμάτων της μεθόδου "get()" της αντιστοίχισης του θέματος. Τα
  ταιριασμένα ζεύγη κλειδιού-τιμής πρέπει να είναι ήδη παρόντα στην
  αντιστοίχιση, και να μην δημιουργούνται δυναμικά μέσω της
  "__missing__()" ή της "__getitem__()".

Με απλά λόγια, το "{KEY1: P1, KEY2: P2, ... }" ταιριάζει μόνο εάν
συμβούν όλα τα ακόλουθα:

* έλεγχος ότι το "<subject>" είναι μία αντιστοίχιση

* "KEY1 in <subject>"

* το "P1" ταιριάζει στο "<subject>[KEY1]"

* ... και ούτω καθεξής για το αντίστοιχο ζεύγος KEY/μοτίβου.


8.6.4.10. Μοτίβα Κλάσης
~~~~~~~~~~~~~~~~~~~~~~~

Ένα μοτίβο κλάσης αναπαριστά μια κλάση και τα ορίσματα θέσης και λέξης
κλειδιού της (εάν υπάρχουν). Σύνταξη:

   class_pattern:       name_or_attr "(" [pattern_arguments ","?] ")"
   pattern_arguments:   positional_patterns ["," keyword_patterns]
                        | keyword_patterns
   positional_patterns: ",".pattern+
   keyword_patterns:    ",".keyword_pattern+
   keyword_pattern:     NAME "=" pattern

Η ίδια λέξη-κλειδί δεν πρέπει να επαναλαμβάνεται στα μοτίβα κλάσης.

Ακολουθεί η λογική ροή για το ταίριασμα ενός μοτίβου κλάσης έναντι
μιας τιμής θέματος:

1. Εάν το "name_or_attr" δεν είναι στιγμιότυπο του ενσωματωμένου
   "type", γίνεται raise ένα "TypeError".

2. Εάν η τιμή του θέματος δεν είναι στιγμιότυπο του "name_or_attr"
   (ελέγχεται μέσω της "isinstance()"), το μοτίβο κλάσης αποτυγχάνει.

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

   Για έναν αριθμό ενσωματωμένων τύπων (καθορίζονται παρακάτω),
   γίνεται αποδεκτό ένα μεμονωμένο υπο-μοτίβο θέσης το οποίο θα
   ταιριάξει με ολόκληρο το θέμα· για αυτούς τους τύπους, τα μοτίβα
   λέξης-κλειδιού λειτουργούν επίσης όπως και για άλλους τύπους.

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

   1. Η λέξη-κλειδί αναζητείται ως χαρακτηριστικό πάνω στο θέμα.

      * Εάν κάνει raise μια εξαίρεση διαφορετική από το
        "AttributeError", η εξαίρεση ανεβαίνει προς τα πάνω.

      * Εάν κάνει raise το "AttributeError", το μοτίβο κλάσης έχει
        αποτύχει.

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

   2. Εάν όλα τα μοτίβα λέξης-κλειδιού επιτύχουν, το μοτίβο κλάσης
      επιτυγχάνει.

   Εάν υπάρχουν οποιαδήποτε μοτίβα θέσης, μετατρέπονται σε μοτίβα
   λέξης-κλειδιού χρησιμοποιώντας το χαρακτηριστικό "__match_args__"
   πάνω στην κλάση "name_or_attr" πριν από το ταίριασμα:

   1. Καλείται το ισοδύναμο της "getattr(cls, "__match_args__", ())".

      * Εάν κάνει raise μια εξαίρεση, η εξαίρεση ανεβαίνει προς τα
        πάνω.

      * Εάν η επιστρεφόμενη τιμή δεν είναι πλειάδα, η μετατροπή
        αποτυγχάνει και γίνεται raise το "TypeError".

      * Εάν υπάρχουν περισσότερα μοτίβα θέσης από το
        "len(cls.__match_args__)", γίνεται raise το "TypeError".

      * Διαφορετικά, το μοτίβο θέσης "i" μετατρέπεται σε ένα μοτίβο
        λέξης-κλειδιού χρησιμοποιώντας το "__match_args__[i]" ως
        λέξη-κλειδί. Το "__match_args__[i]" πρέπει να είναι
        συμβολοσειρά· εάν όχι, γίνεται raise το "TypeError".

      * Εάν υπάρχουν διπλότυπες λέξεις-κλειδιά, γίνεται raise το
        "TypeError".

      Δείτε επίσης:

        Προσαρμογή ορισμάτων θέσης στην αντιστοίχιση προτύπων κλάσης

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

   Για τους ακόλουθους ενσωματωμένους τύπους, ο χειρισμός των
   υπο-μοτίβων θέσης είναι διαφορετικός:

   * "bool"

   * "bytearray"

   * "bytes"

   * "dict"

   * "float"

   * "frozendict"

   * "frozenset"

   * "int"

   * "list"

   * "set"

   * "str"

   * "tuple"

   Αυτές οι κλάσεις δέχονται ένα μόνο όρισμα θέσης, και το μοτίβο εκεί
   ταιριάζεται έναντι ολόκληρου του αντικειμένου αντί για ένα
   χαρακτηριστικό. Για παράδειγμα το "int(0|1)" ταιριάζει με την τιμή
   "0", αλλά όχι με την τιμή "0.0".

Με απλά λόγια, το "CLS(P1, attr=P2)" ταιριάζει μόνο εάν συμβαίνουν τα
ακόλουθα:

* "isinstance(<subject>, CLS)"

* μετατροπή του "P1" σε μοτίβο λέξης-κλειδιού χρησιμοποιώντας το
  "CLS.__match_args__"

* Για κάθε όρισμα λέξης-κλειδιού "attr=P2":

  * "hasattr(<subject>, "attr")"

  * το "P2" ταιριάζει στο "<subject>.attr"

* ... και ούτω καθεξής για το αντίστοιχο ζεύγος ορίσματος
  λέξης-κλειδιού/μοτίβου.

Δείτε επίσης:

  * **PEP 634** -- Ταίριασμα Δομικών Προτύπων: Προδιαγραφή

  * **PEP 636** -- Ταίριασμα Δομικών Προτύπων: Εγχειρίδιο


8.7. Ορισμοί συναρτήσεων
========================

Ένας ορισμός συνάρτησης ορίζει ένα αντικείμενο συνάρτησης ορισμένο από
τον χρήστη (δείτε την ενότητα Η τυπική ιεραρχία τύπου):

   funcdef:                   [decorators] "def" funcname [type_params] "(" [parameter_list] ")"
                              ["->" expression] ":" suite
   decorators:                decorator+
   decorator:                 "@" assignment_expression NEWLINE
   parameter_list:            defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
                                | parameter_list_no_posonly
   parameter_list_no_posonly: defparameter ("," defparameter)* ["," [parameter_list_starargs]]
                              | parameter_list_starargs
   parameter_list_starargs:   "*" star_parameter ("," defparameter)* ["," [parameter_star_kwargs]]
                              | "*" ("," defparameter)+ ["," [parameter_star_kwargs]]
                              | parameter_star_kwargs
   parameter_star_kwargs:     "**" parameter [","]
   parameter:                 identifier [":" expression]
   star_parameter:            identifier [":" ["*"] expression]
   defparameter:              parameter ["=" expression]
   funcname:                  identifier

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

Ο ορισμός της συνάρτησης δεν εκτελεί το σώμα της συνάρτησης· αυτό
εκτελείται μόνο όταν κληθεί η συνάρτηση. [4]

Ένας ορισμός συνάρτησης μπορεί να περιτυλιχθεί από μία ή περισσότερες
εκφράσεις *decorator*. Οι εκφράσεις decorator αξιολογούνται όταν
ορίζεται η συνάρτηση, στο εύρος που περιέχει τον ορισμό της
συνάρτησης. Το αποτέλεσμα πρέπει να είναι ένα callable, το οποίο
καλείται με το αντικείμενο συνάρτησης ως το μοναδικό όρισμα. Η τιμή
που επιστρέφεται δεσμεύεται στο όνομα της συνάρτησης αντί για το
αντικείμενο συνάρτησης. Πολλοί decorators εφαρμόζονται με εμφωλευμένο
τρόπο. Για παράδειγμα, ο ακόλουθος κώδικας

   @f1(arg)
   @f2
   def func(): pass

είναι κατά προσέγγιση ισοδύναμο με το

   def func(): pass
   func = f1(arg)(f2(func))

εκτός του ότι η αρχική συνάρτηση δεν δεσμεύεται προσωρινά στο όνομα
"func".

Άλλαξε στην έκδοση 3.9: Οι συναρτήσεις μπορούν να διακοσμηθούν με
οποιοδήποτε έγκυρο "assignment_expression". Προηγουμένως, η γραμματική
ήταν πολύ πιο αυστηρή· δείτε το **PEP 614** για λεπτομέρειες.

Μια λίστα από παραμέτρους τύπου μπορεί να δοθεί μέσα σε αγκύλες μεταξύ
του ονόματος της συνάρτησης και της παρένθεσης ανοίγματος για τη λίστα
παραμέτρων της. Αυτό υποδεικνύει στους ελέγχους στατικού τύπου ότι η
συνάρτηση είναι γενική. Κατά τον χρόνο εκτέλεσης, οι παράμετροι τύπου
μπορούν να ανακτηθούν από το χαρακτηριστικό "__type_params__" της
συνάρτησης. Δείτε το Γενικές συναρτήσεις για περισσότερα.

Άλλαξε στην έκδοση 3.12: Οι λίστες παραμέτρων τύπου είναι νέες στην
Python 3.12.

Όταν μία ή περισσότερες *παράμετροι* έχουν τη μορφή *parameter* "="
*expression*, η συνάρτηση λέγεται ότι έχει "προεπιλεγμένες τιμές
παραμέτρων." Για μια παράμετρο με προεπιλεγμένη τιμή, το αντίστοιχο
*argument* μπορεί να παραλειφθεί από μια κλήση, οπότε αντικαθίσταται η
προεπιλεγμένη τιμή της παραμέτρου. Εάν μια παράμετρος έχει μια
προεπιλεγμένη τιμή, όλες οι επόμενες παράμετροι μέχρι το ""*"" πρέπει
επίσης να έχουν μια προεπιλεγμένη τιμή --- αυτός είναι ένας
συντακτικός περιορισμός που δεν εκφράζεται από τη γραμματική.

**Default parameter values are evaluated from left to right when the
function definition is executed.** This means that the expression is
evaluated once, when the function is defined, and that the same "pre-
computed" value is used for each call.  This is especially important
to understand when a default parameter value is a mutable object, such
as a list or a dictionary: if the function modifies the object (e.g.
by appending an item to a list), the default parameter value is in
effect modified.  This is generally not what was intended.  A way
around this is to use "None" as the default, and explicitly test for
it in the body of the function, for example:

   def whats_on_the_telly(penguin=None):
       if penguin is None:
           penguin = []
       penguin.append("property of the zoo")
       return penguin

Η σημασιολογία των κλήσεων συναρτήσεων περιγράφεται λεπτομερέστερα
στην ενότητα Κλήσεις. Μια κλήση συνάρτησης αναθέτει πάντα τιμές σε
όλες τις παραμέτρους που αναφέρονται στη λίστα παραμέτρων, είτε από
ορίσματα θέσης, από ορίσματα λέξης-κλειδιού, είτε από προεπιλεγμένες
τιμές. Εάν η μορφή ""*identifier"" υπάρχει, αρχικοποιείται σε μία
πλειάδα που λαμβάνει τυχόν επιπλέον παραμέτρους θέσης, έχοντας ως
προεπιλογή την κενή πλειάδα. Εάν η μορφή ""**identifier"" υπάρχει,
αρχικοποιείται σε μία νέα ταξινομημένη αντιστοίχιση που λαμβάνει τυχόν
επιπλέον ορίσματα λέξης-κλειδιού, έχοντας ως προεπιλογή μία νέα κενή
αντιστοίχιση του ίδιου τύπου. Οι παράμετροι μετά το ""*"" ή το
""*identifier"" είναι μόνο παράμετροι λέξης-κλειδιού και μπορούν να
περαστούν μόνο από ορίσματα λέξης-κλειδιού. Οι παράμετροι πριν από το
""/"" είναι μόνο παράμετροι θέσης και μπορούν να περαστούν μόνο από
ορίσματα θέσης.

Άλλαξε στην έκδοση 3.8: Η σύνταξη παραμέτρων συνάρτησης "/" μπορεί να
χρησιμοποιηθεί για να υποδείξει μόνο παραμέτρους θέσης. Δείτε το **PEP
570** για λεπτομέρειες.

Οι παράμετροι μπορεί να έχουν ένα *annotation* της μορφής "":
expression"" μετά το όνομα της παραμέτρου. Οποιαδήποτε παράμετρος
μπορεί να έχει ένα annotation, ακόμα και αυτές της μορφής
"*identifier" ή "**identifier". (Ως ειδική περίπτωση, οι παράμετροι
της μορφής "*identifier" μπορεί να έχουν ένα annotation "":
*expression"".) Οι συναρτήσεις μπορεί να έχουν "return" annotation της
μορφής ""-> expression"" μετά τη λίστα παραμέτρων. Αυτά τα annotations
μπορούν να είναι οποιαδήποτε έγκυρη έκφραση της Python. Η παρουσία των
annotations δεν αλλάζει τη σημασιολογία μιας συνάρτησης. Δείτε το
Annotations για περισσότερες πληροφορίες.

Άλλαξε στην έκδοση 3.11: Οι παράμετροι της μορφής ""*identifier""
μπορεί να έχουν ένα annotation "": *expression"". Δείτε το **PEP
646**.

Είναι επίσης δυνατό να δημιουργηθούν ανώνυμες συναρτήσεις (συναρτήσεις
που δεν δεσμεύονται σε ένα όνομα), για άμεση χρήση σε εκφράσεις. Αυτό
χρησιμοποιεί εκφράσεις lambda, που περιγράφονται στην ενότητα
Εκφράσεις lambda. Σημειώστε ότι η έκφραση lambda είναι απλώς μια
συντομογραφία για έναν απλοποιημένο ορισμό συνάρτησης· μια συνάρτηση
που ορίζεται με την δήλωση ""def"" μπορεί να περαστεί ή να ανατεθεί σε
ένα άλλο όνομα ακριβώς όπως μια συνάρτηση που ορίζεται με μια έκφραση
lambda. Η μορφή ""def"" είναι στην πραγματικότητα πιο ισχυρή αφού
επιτρέπει την εκτέλεση πολλαπλών εντολών και annotations.

**Σημείωση για προγραμματιστές/τριες:** Οι συναρτήσεις είναι first-
class αντικείμενα. Μια δήλωση ""def"" που εκτελείται μέσα σε έναν
ορισμό συνάρτησης ορίζει μια τοπική συνάρτηση που μπορεί να επιστραφεί
ή να περαστεί αλλού. Οι ελεύθερες μεταβλητές που χρησιμοποιούνται στην
εμφωλευμένη συνάρτηση έχουν πρόσβαση στις τοπικές μεταβλητές της
συνάρτησης που περιέχει το def. Δείτε την ενότητα Ονομασία και σύνδεση
για λεπτομέρειες.

Δείτε επίσης:

  **PEP 3107** - Annotations Συνάρτησης
     Οι αρχικές προδιαγραφές για τα annotations συνάρτησης.

  **PEP 484** - Υποδείξεις Τύπου
     Ορισμός ενός τυποποιημένου νοήματος για τα annotations:
     υποδείξεις τύπου.

  **PEP 526** - Σύνταξη για Annotations Μεταβλητών
     Δυνατότητα για υποδείξεις τύπου στις δηλώσεις μεταβλητών,
     συμπεριλαμβανομένων των μεταβλητών κλάσης και των μεταβλητών
     στιγμιοτύπου.

  **PEP 563** - Αναβαλλόμενη Αξιολόγηση των Annotations
     Υποστήριξη για μελλοντική αναφορά μέσα στα annotations
     διατηρώντας τα annotations σε μορφή συμβολοσειράς κατά τον χρόνο
     εκτέλεσης αντί για άμεση αξιολόγηση.

  **PEP 318** - Decorators για Συναρτήσεις και Μεθόδους
     Εισήχθησαν οι decorators συναρτήσεων και μεθόδων. Οι decorators
     κλάσεων εισήχθησαν στο **PEP 3129**.


8.8. Ορισμοί κλάσεων
====================

Ο ορισμός μιας κλάσης ορίζει ένα αντικείμενο κλάσης (δείτε την ενότητα
Η τυπική ιεραρχία τύπου):

   classdef:    [decorators] "class" classname [type_params] [inheritance] ":" suite
   inheritance: "(" [argument_list] ")"
   classname:   identifier

Ένας ορισμός κλάσης είναι μια εκτελέσιμη δήλωση. Η λίστα
κληρονομικότητας συνήθως δίνει μια λίστα βασικών κλάσεων (δείτε το
Μετα-κλάσεις για πιο προχωρημένες χρήσεις), επομένως κάθε στοιχείο στη
λίστα θα πρέπει να αξιολογείται σε ένα αντικείμενο κλάσης που
επιτρέπει τη δημιουργία υπο-κλάσεων. Οι κλάσεις χωρίς λίστα
κληρονομικότητας κληρονομούν, εξ ορισμού, από τη βασική κλάση
"object"· επομένως, το

   class Foo:
       pass

είναι ισοδύναμο με το

   class Foo(object):
       pass

There may be one or more base classes; see Multiple inheritance below
for more information.

Η σουίτα της κλάσης στη συνέχεια εκτελείται σε ένα νέο πλαίσιο
εκτέλεσης (δείτε το Ονομασία και σύνδεση), χρησιμοποιώντας έναν
νεοδημιουργηθέντα τοπικό χώρο ονομάτων και τον αρχικό καθολικό χώρο
ονομάτων. (Συνήθως, η σουίτα περιέχει κυρίως ορισμούς συναρτήσεων.)
Όταν η σουίτα της κλάσης ολοκληρώσει την εκτέλεσή της, το πλαίσιο
εκτέλεσής της απορρίπτεται αλλά ο τοπικός χώρος ονομάτων της σώζεται.
[5] Ένα αντικείμενο κλάσης δημιουργείται στη συνέχεια χρησιμοποιώντας
τη λίστα κληρονομικότητας για τις βασικές κλάσεις και τον αποθηκευμένο
τοπικό χώρο ονομάτων για το λεξικό των χαρακτηριστικών. Το όνομα της
κλάσης δεσμεύεται σε αυτό το αντικείμενο κλάσης στον αρχικό τοπικό
χώρο ονομάτων.

Η σειρά με την οποία ορίζονται τα χαρακτηριστικά στο σώμα της κλάσης
διατηρείται στο "__dict__" της νέας κλάσης. Σημειώστε ότι αυτή είναι
αξιόπιστη μόνο αμέσως μετά τη δημιουργία της κλάσης και μόνο για
κλάσεις που ορίστηκαν χρησιμοποιώντας τη σύνταξη ορισμού.

Η δημιουργία κλάσεων μπορεί να προσαρμοστεί εκτενώς χρησιμοποιώντας
metaclasses.

Οι κλάσεις μπορούν επίσης να διακοσμηθούν: ακριβώς όπως με τους
decorators συναρτήσεων,

   @f1(arg)
   @f2
   class Foo: pass

είναι κατά προσέγγιση ισοδύναμο με το

   class Foo: pass
   Foo = f1(arg)(f2(Foo))

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

Άλλαξε στην έκδοση 3.9: Οι κλάσεις μπορούν να διακοσμηθούν με
οποιοδήποτε έγκυρο "assignment_expression". Προηγουμένως, η γραμματική
ήταν πολύ πιο αυστηρή· δείτε το **PEP 614** για λεπτομέρειες.

Μια λίστα από παραμέτρους τύπου μπορεί να δοθεί σε αγκύλες αμέσως μετά
το όνομα της κλάσης. Αυτό υποδεικνύει στους ελέγχους στατικού τύπου
ότι η κλάση είναι γενική. Κατά τον χρόνο εκτέλεσης, οι παράμετροι
τύπου μπορούν να ανακτηθούν από το χαρακτηριστικό "__type_params__"
της κλάσης. Δείτε το Γενικές κλάσεις για περισσότερα.

Άλλαξε στην έκδοση 3.12: Οι λίστες παραμέτρων τύπου είναι νέες στην
Python 3.12.

**Σημείωση για προγραμματιστές/τριες:** Οι μεταβλητές που ορίζονται
στον ορισμό της κλάσης είναι χαρακτηριστικά κλάσης· μοιράζονται μεταξύ
των στιγμιοτύπων. Τα χαρακτηριστικά στιγμιοτύπου μπορούν να οριστούν
σε μια μέθοδο με "self.name = value". Τόσο χαρακτηριστικά κλάσης όσο
και τα χαρακτηριστικά στιγμιοτύπου είναι προσβάσιμα μέσω της
σημειογραφίας ""self.name"", και ένα χαρακτηριστικό στιγμιοτύπου
κρύβει ένα χαρακτηριστικό κλάσης με το ίδιο όνομα όταν η πρόσβαση
γίνεται με αυτόν τον τρόπο. Τα χαρακτηριστικά κλάσης μπορούν να
χρησιμοποιηθούν ως προεπιλογές για τα χαρακτηριστικά στιγμιοτύπου,
αλλά η χρήση μεταβλητών τιμών μπορεί να οδηγήσει σε μη αναμενόμενα
αποτελέσματα. Τα Descriptors μπορούν να χρησιμοποιηθούν για τη
δημιουργία μεταβλητών στιγμιοτύπου με διαφορετικές λεπτομέρειες
υλοποίησης.

Δείτε επίσης:

  **PEP 3115** - Metaclasses στην Python 3000
     Η πρόταση που άλλαξε τη δήλωση των metaclasses στην τρέχουσα
     σύνταξη, και τη σημασιολογία για τον τρόπο κατασκευής κλάσεων με
     metaclasses.

  **PEP 3129** - Decorators Κλάσεων
     Η πρόταση που πρόσθεσε τους decorators κλάσεων. Οι decorators
     συναρτήσεων και μεθόδων είχαν εισαχθεί στο **PEP 318**.


8.8.1. Multiple inheritance
---------------------------

Python classes may have multiple base classes, a technique known as
*multiple inheritance*.  The base classes are specified in the class
definition by listing them in parentheses after the class name,
separated by commas. For example, the following class definition:

   >>> class A: pass
   >>> class B: pass
   >>> class C(A, B): pass

defines a class "C" that inherits from classes "A" and "B".

The *method resolution order* (MRO) is the order in which base classes
are searched when looking up an attribute on a class. See The Python
2.3 Method Resolution Order for a description of how Python determines
the MRO for a class.

Multiple inheritance is not always allowed. Attempting to define a
class with multiple inheritance will raise an error if one of the
bases does not allow subclassing, if a consistent MRO cannot be
created, if no valid metaclass can be determined, or if there is an
instance layout conflict. We'll discuss each of these in turn.

First, all base classes must allow subclassing. While most classes
allow subclassing, some built-in classes do not, such as "bool":

   >>> class SubBool(bool):  # TypeError
   ...    pass
   Traceback (most recent call last):
      ...
   TypeError: type 'bool' is not an acceptable base type

In the resolved MRO of a class, the class's bases appear in the order
they were specified in the class's bases list. Additionally, the MRO
always lists a child class before any of its bases. A class definition
will fail if it is impossible to resolve a consistent MRO that
satisfies these rules from the list of bases provided:

   >>> class Base: pass
   >>> class Child(Base): pass
   >>> class Grandchild(Base, Child): pass  # TypeError
   Traceback (most recent call last):
      ...
   TypeError: Cannot create a consistent method resolution order (MRO) for bases Base, Child

In the MRO of "Grandchild", "Base" must appear before "Child" because
it is first in the base class list, but it must also appear after
"Child" because it is a parent of "Child". This is a contradiction, so
the class cannot be defined.

If some of the bases have a custom *metaclass*, the metaclass of the
resulting class is chosen among the metaclasses of the bases and the
explicitly specified metaclass of the child class. It must be a
metaclass that is a subclass of all other candidate metaclasses. If no
such metaclass exists among the candidates, the class cannot be
created, as explained in Προσδιορισμός της κατάλληλης μετακλάσης.

Finally, the instance layouts of the bases must be compatible. This
means that it must be possible to compute a *solid base* for the
class. Exactly which classes are solid bases depends on the Python
implementation.

**Λεπτομέρεια υλοποίησης CPython:** In CPython, a class is a solid
base if it has a nonempty "__slots__" definition. Many but not all
classes defined in C are also solid bases, including most builtins
(such as "int" or "BaseException") but excluding most concrete
"Exception" classes. Generally, a C class is a solid base if its
underlying struct is different in size from its base class.

Every class has a solid base. "object", the base class, has itself as
its solid base. If there is a single base, the child class's solid
base is that class if it is a solid base, or else the base class's
solid base. If there are multiple bases, we first find the solid base
for each base class to produce a list of candidate solid bases. If
there is a unique solid base that is a subclass of all others, then
that class is the solid base. Otherwise, class creation fails.

Example:

   >>> class Solid1:
   ...    __slots__ = ("solid1",)
   >>>
   >>> class Solid2:
   ...    __slots__ = ("solid2",)
   >>>
   >>> class SolidChild(Solid1):
   ...    __slots__ = ("solid_child",)
   >>>
   >>> class C1:  # solid base is `object`
   ...    pass
   >>>
   >>> # OK: solid bases are `Solid1` and `object`, and `Solid1` is a subclass of `object`.
   >>> class C2(Solid1, C1):  # solid base is `Solid1`
   ...    pass
   >>>
   >>> # OK: solid bases are `SolidChild` and `Solid1`, and `SolidChild` is a subclass of `Solid1`.
   >>> class C3(SolidChild, Solid1):  # solid base is `SolidChild`
   ...    pass
   >>>
   >>> # Error: solid bases are `Solid1` and `Solid2`, but neither is a subclass of the other.
   >>> class C4(Solid1, Solid2):  # error: no single solid base
   ...    pass
   Traceback (most recent call last):
     ...
   TypeError: multiple bases have instance lay-out conflict


8.9. Coroutines
===============

Added in version 3.5.


8.9.1. Ορισμός συνάρτησης coroutine
-----------------------------------

   async_funcdef: [decorators] "async" "def" funcname "(" [parameter_list] ")"
                  ["->" expression] ":" suite

Η εκτέλεση των Python coroutines μπορεί να ανασταλεί και να συνεχιστεί
σε πολλά σημεία (δείτε το *coroutine*). Οι εκφράσεις "await", το
"async for" και το "async with" μπορούν να χρησιμοποιηθούν μόνο στο
σώμα μιας συνάρτησης coroutine.

Οι συναρτήσεις που ορίζονται με τη σύνταξη "async def" είναι πάντα
συναρτήσεις coroutine, ακόμη και αν δεν περιέχουν τις λέξεις-κλειδιά
"await" ή "async".

Προκαλείται "SyntaxError" αν χρησιμοποιηθεί μια έκφραση "yield from"
μέσα στο σώμα μιας συνάρτησης coroutine.

Ένα παράδειγμα συνάρτησης coroutine:

   async def func(param1, param2):
       do_stuff()
       await some_coroutine()

Άλλαξε στην έκδοση 3.7: Το "await" και το "async" είναι πλέον
λέξεις-κλειδιά· προηγουμένως αντιμετωπίζονταν ως τέτοια μόνο εντός του
σώματος μιας συνάρτησης coroutine.


8.9.2. Η δήλωση "async for"
---------------------------

   async_for_stmt: "async" for_stmt

Ένα *asynchronous iterable* παρέχει μια μέθοδο "__aiter__" η οποία
επιστρέφει απευθείας έναν *asynchronous iterator*, ο οποίος μπορεί να
καλέσει ασύγχρονο κώδικα στη μέθοδο "__anext__" του.

Η δήλωση "async for" επιτρέπει τη βολική επανάληψη σε ασύγχρονα
iterables.

Ο ακόλουθος κώδικας:

   async for TARGET in ITER:
       SUITE
   else:
       SUITE2

Είναι σημασιολογικά ισοδύναμο με το:

   iter = (ITER).__aiter__()
   running = True

   while running:
       try:
           TARGET = await iter.__anext__()
       except StopAsyncIteration:
           running = False
       else:
           SUITE
   else:
       SUITE2

except that implicit special method lookup is used for "__aiter__()"
and "__anext__()".

Προκαλείται "SyntaxError" αν χρησιμοποιηθεί μια δήλωση "async for" έξω
από το σώμα μιας συνάρτησης coroutine.


8.9.3. Η δήλωση "async with"
----------------------------

   async_with_stmt: "async" with_stmt

Ένας *asynchronous context manager* είναι ένας *context manager* που
είναι ικανός να αναστείλει την εκτέλεση στις μεθόδους του *enter* και
*exit*.

Ο ακόλουθος κώδικας:

   async with EXPRESSION as TARGET:
       SUITE

είναι σημασιολογικά ισοδύναμος με:

   manager = (EXPRESSION)
   aenter = manager.__aenter__
   aexit = manager.__aexit__
   value = await aenter()
   hit_except = False

   try:
       TARGET = value
       SUITE
   except:
       hit_except = True
       if not await aexit(*sys.exc_info()):
           raise
   finally:
       if not hit_except:
           await aexit(None, None, None)

except that implicit special method lookup is used for "__aenter__()"
and "__aexit__()".

Προκαλείται "SyntaxError" αν χρησιμοποιηθεί μια δήλωση "async with"
έξω από το σώμα μιας συνάρτησης coroutine.

Δείτε επίσης:

  **PEP 492** - Coroutines με σύνταξη async και await
     Η πρόταση που έκανε τις coroutines μια σωστή, ανεξάρτητη έννοια
     στην Python, και πρόσθεσε την υποστηρικτική σύνταξη.


8.10. Λίστες παραμέτρων τύπου
=============================

Added in version 3.12.

Άλλαξε στην έκδοση 3.13: Προστέθηκε υποστήριξη για προεπιλεγμένες
τιμές (δείτε το **PEP 696**).

   type_params:  "[" type_param ("," type_param)* "]"
   type_param:   typevar | typevartuple | paramspec
   typevar:      identifier (":" expression)? ("=" expression)?
   typevartuple: "*" identifier ("=" expression)?
   paramspec:    "**" identifier ("=" expression)?

Οι Συναρτήσεις (συμπεριλαμβανομένων των coroutines), οι κλάσεις και τα
ψευδώνυμα τύπων μπορούν να περιέχουν μια λίστα παραμέτρων τύπου:

   def max[T](args: list[T]) -> T:
       ...

   async def amax[T](args: list[T]) -> T:
       ...

   class Bag[T]:
       def __iter__(self) -> Iterator[T]:
           ...

       def add(self, arg: T) -> None:
           ...

   type ListOrSet[T] = list[T] | set[T]

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

Οι παράμετροι τύπου δηλώνονται μέσα σε αγκύλες ("[]") αμέσως μετά το
όνομα της συνάρτησης, κλάσης ή του ψευδωνύμου τύπου. Οι παράμετροι
τύπου είναι προσβάσιμες εντός της εμβέλειας του γενικού αντικειμένου,
αλλά όχι αλλού. Επομένως, μετά από μια δήλωση "def func[T](): pass",
το όνομα "T" δεν είναι διαθέσιμο στο εύρος του module. Παρακάτω, η
σημασιολογία των γενικών αντικειμένων περιγράφεται με μεγαλύτερη
ακρίβεια. Το εύρος των παραμέτρων τύπου μοντελοποιείται με μια ειδική
συνάρτηση (τεχνικά, ένα annotation scope) η οποία περιτυλίγει τη
δημιουργία του γενικού αντικειμένου.

Οι γενικές συναρτήσεις, κλάσεις και τα ψευδώνυμα τύπων έχουν ένα
χαρακτηριστικό "__type_params__" που παραθέτει τις παραμέτρους του
τύπου τους.

Οι παράμετροι τύπου διακρίνονται σε τρία είδη:

* Το "typing.TypeVar", που εισάγεται από ένα απλό όνομα (π.χ. "T").
  Σημασιολογικά, αναπαριστά έναν μόνο τύπο σε έναν ελεγκτή τύπου.

* Το "typing.TypeVarTuple", που εισάγεται από ένα όνομα με πρόθεμα
  έναν απλό αστερίσκο (π.χ. "*Ts"). Σημασιολογικά, αντιπροσωπεύει μία
  πλειάδα οποιουδήποτε αριθμού τύπων.

* Το "typing.ParamSpec", που εισάγεται από ένα όνομα με πρόθεμα δύο
  αστερίσκους (π.χ. "**P"). Σημασιολογικά, αντιπροσωπεύει τις
  παραμέτρους ενός callable.

Οι δηλώσεις του "typing.TypeVar" μπορούν να ορίσουν *bounds* και
*constraints* με άνω και κάτω τελεία (":") ακολουθούμενη από μια
έκφραση. Μία μεμονωμένη έκφραση μετά την άνω και κάτω τελεία
υποδεικνύει ένα bound (π.χ. "T: int"). Σημασιολογικά, αυτό σημαίνει
ότι το "typing.TypeVar" μπορεί να αναπαριστά μόνο τύπους που είναι
υπότυπος αυτού του bound. Μία παρενθετική πλειάδα εκφράσεων μετά την
άνω και κάτω τελεία υποδεικνύει ένα σύνολο από constraints (π.χ. "T:
(str, bytes)"). Κάθε μέλος της πλειάδας θα πρέπει να είναι ένας τύπος
(και πάλι, αυτό δεν επιβάλλεται κατά τον χρόνο εκτέλεσης). Οι
constraint μεταβλητές τύπου μπορούν να λάβουν μόνο έναν από τους
τύπους στη λίστα των constraints.

Για τα "typing.TypeVar" που δηλώνονται χρησιμοποιώντας τη σύνταξη
λίστας παραμέτρων τύπου, τα bound και constraints δεν αξιολογούνται
όταν το γενικό αντικείμενο δημιουργείται, παρά μόνο όταν
πραγματοποιείται ρητή πρόσβαση στην τιμή μέσω των χαρακτηριστικών
"__bound__" και "__constraints__". Για να επιτευχθεί αυτό, τα bounds ή
constraints αξιολογούνται σε ένα ξεχωριστό annotation scope.

Τα "typing.TypeVarTuple" και τα "typing.ParamSpec" δεν μπορούν να
έχουν bounds ή constraints.

Και τα τρία είδη παραμέτρων τύπου μπορούν επίσης να έχουν μια
*προεπιλεγμένη τιμή*, η οποία χρησιμοποιείται όταν η παράμετρος τύπου
δεν παρέχεται ρητά. Αυτό προστίθεται προσαρτώντας ένα απλό σύμβολο
ίσον ("=") ακολουθούμενο από μια έκφραση. Όπως τα bounds και τα
constraints των μεταβλητών τύπου, η προεπιλεγμένη τιμή δεν
αξιολογείται κατά τη δημιουργία του αντικειμένου, παρά μόνο κατά την
πρόσβαση στο χαρακτηριστικό "__default__" της παραμέτρου τύπου. Για
τον σκοπό αυτό, η προεπιλεγμένη τιμή αξιολογείται σε ένα ξεχωριστό
annotation scope. Εάν δεν καθοριστεί προεπιλεγμένη τιμή για μια
παράμετρο τύπου, το χαρακτηριστικό "__default__" ορίζεται στο ειδικό
αντικείμενο φρουρό "typing.NoDefault".

Το ακόλουθο παράδειγμα υποδεικνύει το πλήρες σύνολο των επιτρεπόμενων
δηλώσεων παραμέτρων τύπου:

   def overly_generic[
      SimpleTypeVar,
      TypeVarWithDefault = int,
      TypeVarWithBound: int,
      TypeVarWithConstraints: (str, bytes),
      *SimpleTypeVarTuple = (int, float),
      **SimpleParamSpec = (str, bytearray),
   ](
      a: SimpleTypeVar,
      b: TypeVarWithDefault,
      c: TypeVarWithBound,
      d: Callable[SimpleParamSpec, TypeVarWithConstraints],
      *e: SimpleTypeVarTuple,
   ): ...


8.10.1. Γενικές συναρτήσεις
---------------------------

Οι γενικές συναρτήσεις δηλώνονται ως εξής:

   def func[T](arg: T): ...

Αυτή η σύνταξη είναι ισοδύναμη με το:

   annotation-def TYPE_PARAMS_OF_func():
       T = typing.TypeVar("T")
       def func(arg: T): ...
       func.__type_params__ = (T,)
       return func
   func = TYPE_PARAMS_OF_func()

Εδώ το "annotation-def" υποδηλώνει ένα annotation scope, το οποίο δεν
δεσμεύεται στην πραγματικότητα σε κανένα όνομα κατά τον χρόνο
εκτέλεσης. (Έχει ληφθεί άλλη μία ελευθερία στη μετάφραση: η σύνταξη
δεν περνά μέσω της πρόσβασης σε χαρακτηριστικό πάνω στο "typing"
module, αλλά δημιουργεί απευθείας ένα στιγμιότυπο της
"typing.TypeVar".)

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

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

   @decorator
   def func[T: int, *Ts, **P](*args: *Ts, arg: Callable[P, T] = some_default):
       ...

Εκτός από το lazy evaluation του "TypeVar" bound, αυτό είναι ισοδύναμο
με το:

   DEFAULT_OF_arg = some_default

   annotation-def TYPE_PARAMS_OF_func():

       annotation-def BOUND_OF_T():
           return int
       # In reality, BOUND_OF_T() is evaluated only on demand.
       T = typing.TypeVar("T", bound=BOUND_OF_T())

       Ts = typing.TypeVarTuple("Ts")
       P = typing.ParamSpec("P")

       def func(*args: *Ts, arg: Callable[P, T] = DEFAULT_OF_arg):
           ...

       func.__type_params__ = (T, Ts, P)
       return func
   func = decorator(TYPE_PARAMS_OF_func())

Τα κεφαλαιοποιημένα ονόματα όπως το "DEFAULT_OF_arg" δεν δεσμεύονται
στην πραγματικότητα κατά τον χρόνο εκτέλεσης.


8.10.2. Γενικές κλάσεις
-----------------------

Οι γενικές κλάσεις δηλώνονται ως εξής:

   class Bag[T]: ...

Αυτή η σύνταξη είναι ισοδύναμη με το:

   annotation-def TYPE_PARAMS_OF_Bag():
       T = typing.TypeVar("T")
       class Bag(typing.Generic[T]):
           __type_params__ = (T,)
           ...
       return Bag
   Bag = TYPE_PARAMS_OF_Bag()

Εδώ πάλι το "annotation-def" (δεν είναι πραγματική λέξη-κλειδί)
υποδεικνύει ένα annotation scope, και το όνομα "TYPE_PARAMS_OF_Bag"
δεν δεσμεύεται στην πραγματικότητα κατά τον χρόνο εκτέλεσης.

Οι γενικές κλάσεις κληρονομούν σιωπηρά την "typing.Generic". Οι
βασικές κλάσεις και τα ορίσματα λέξης-κλειδιού των γενικών κλάσεων
αξιολογούνται εντός του εύρους του τύπου για τις παραμέτρους τύπου,
και οι decorators αξιολογούνται έξω από αυτό το εύρος. Αυτό
απεικονίζεται από αυτό το παράδειγμα:

   @decorator
   class Bag(Base[T], arg=T): ...

Αυτό είναι ισοδύναμο με το:

   annotation-def TYPE_PARAMS_OF_Bag():
       T = typing.TypeVar("T")
       class Bag(Base[T], typing.Generic[T], arg=T):
           __type_params__ = (T,)
           ...
       return Bag
   Bag = decorator(TYPE_PARAMS_OF_Bag())


8.10.3. Ψευδώνυμα γενικού τύπου
-------------------------------

Η δήλωση "type" μπορεί επίσης να χρησιμοποιηθεί για τη δημιουργία ενός
ψευδωνύμου γενικού τύπου:

   type ListOrSet[T] = list[T] | set[T]

Με εξαίρεση το lazy evaluation της τιμής, αυτό είναι ισοδύναμο με το:

   annotation-def TYPE_PARAMS_OF_ListOrSet():
       T = typing.TypeVar("T")

       annotation-def VALUE_OF_ListOrSet():
           return list[T] | set[T]
       # In reality, the value is lazily evaluated
       return typing.TypeAliasType("ListOrSet", VALUE_OF_ListOrSet(), type_params=(T,))
   ListOrSet = TYPE_PARAMS_OF_ListOrSet()

Εδώ, το "annotation-def" (δεν είναι πραγματική λέξη-κλειδί)
υποδεικνύει ένα annotation scope. Τα κεφαλαιοποιημένα ονόματα όπως το
"TYPE_PARAMS_OF_ListOrSet" δεν δεσμεύονται στην πραγματικότητα κατά
τον χρόνο εκτέλεσης.


8.11. Annotations
=================

Άλλαξε στην έκδοση 3.14: Τα annotations πλέον αξιολογούνται νωχελικά
από προεπιλογή.

Οι μεταβλητές και οι παράμετροι συναρτήσεων μπορούν να φέρουν
*annotations*, που δημιουργούνται προσθέτοντας άνω και κάτω τελεία
μετά το όνομα, ακολουθούμενη από μια έκφραση:

   x: annotation = 1
   def f(param: annotation): ...

Οι συναρτήσεις μπορούν επίσης να φέρουν ένα annotation επιστροφής
ακολουθώντας ένα βέλος:

   def f() -> annotation: ...

Annotations are conventionally used for *type hints*, but this is not
enforced by the language, and in general annotations may contain
arbitrary expressions. The presence of annotations does not change the
runtime semantics of the code, except if some mechanism is used that
introspects and uses the annotations (such as "dataclasses" or
"@functools.singledispatch").

Από προεπιλογή, τα annotations αξιολογούνται νωχελικά σε ένα
annotation scope. Αυτό σημαίνει ότι δεν αξιολογούνται όταν
αξιολογείται ο κώδικας που περιέχει το annotation. Αντίθετα, ο
διερμηνέας αποθηκεύει πληροφορίες που μπορούν να χρησιμοποιηθούν για
να αξιολογηθεί το annotation αργότερα, εάν ζητηθεί. Το module
"annotationlib" παρέχει εργαλεία για την αξιολόγηση των annotations.

Εάν η μελλοντική δήλωση "from __future__ import annotations" είναι
παρούσα, όλα τα annotations αποθηκεύονται αντί αυτού ως συμβολοσειρές:

   >>> from __future__ import annotations
   >>> def f(param: annotation): ...
   >>> f.__annotations__
   {'param': 'annotation'}

Αυτή η μελλοντική δήλωση θα θεωρηθεί απαρχαιωμένη και θα αφαιρεθεί σε
μια μελλοντική έκδοση της Python, αλλά όχι προτού η Python 3.13 φτάσει
στο τέλος της ζωής της (δείτε το **PEP 749**). Όταν χρησιμοποιείται,
τα εργαλεία ενδοσκόπησης όπως η "annotationlib.get_annotations()" και
η "typing.get_type_hints()" είναι λιγότερο πιθανό να μπορούν να
επιλύσουν annotations κατά τον χρόνο εκτέλεσης.

-[ Υποσημειώσεις ]-

[1] Η εξαίρεση διαδίδεται στη στοίβα κλήσεων εκτός εάν υπάρχει μία
    ρήτρα "finally" η οποία τυχαίνει να κάνει raise μια άλλη εξαίρεση.
    Αυτή η νέα εξαίρεση προκαλεί την απώλεια της παλιάς.

[2] Στο ταίριασμα μοτίβων, μια ακολουθία ορίζεται ως ένα από τα
    ακόλουθα:

    * μια κλάση που κληρονομεί από την "collections.abc.Sequence"

    * μια Python κλάση που έχει εγγραφεί ως "collections.abc.Sequence"

    * μια ενσωματωμένη κλάση που έχει το "Py_TPFLAGS_SEQUENCE" bit της
      ρυθμισμένο (στην CPython)

    * μια κλάση που κληρονομεί οποιοδήποτε από τα παραπάνω

    Οι ακόλουθες κλάσεις της τυπικής βιβλιοθήκης είναι ακολουθίες:

    * "array.array"

    * "collections.deque"

    * "list"

    * "memoryview"

    * "range"

    * "tuple"

    Σημείωση:

      Τιμές θέματος τύπου "str", "bytes", και "bytearray" δεν
      ταιριάζουν με μοτίβα ακολουθίας.

[3] Στο ταίριασμα μοτίβων, μία αντιστοίχιση ορίζεται ως ένα από τα
    ακόλουθα:

    * μια κλάση που κληρονομεί την "collections.abc.Mapping"

    * μια Python κλάση που έχει εγγραφεί ως "collections.abc.Mapping"

    * μια ενσωματωμένη κλάση που έχει το "Py_TPFLAGS_MAPPING" bit της
      ρυθμισμένο (στην CPython)

    * μια κλάση που κληρονομεί οποιοδήποτε από τα παραπάνω

    Οι κλάσεις "dict" και "types.MappingProxyType" της τυπικής
    βιβλιοθήκης είναι αντιστοιχίσεις.

[4] Ένα λεκτικό συμβολοσειράς που εμφανίζεται ως η πρώτη δήλωση στο
    σώμα μιας συνάρτησης μετατρέπεται στο χαρακτηριστικό "__doc__" της
    συνάρτησης και κατά συνέπεια στο *docstring* της συνάρτησης.

[5] Ένα λεκτικό συμβολοσειράς που εμφανίζεται ως η πρώτη δήλωση στο
    σώμα μιας κλάσης μετατρέπεται στο στοιχείο "__doc__" του χώρου
    ονομάτων και κατά συνέπεια στο *docstring* της κλάσης.
