Python Decorators Explained: From @property to Retry Logic σε 15 λεπτά (2026)
Οι διακοσμητές είναι το χαρακτηριστικό που διαχωρίζει το "γνωρίζει την Python" από το "διαβάζει άπταιστα την Python". Φαίνονται μαγικά, αλλά είναι μηχανικά: «@decorator» σε μια συνάρτηση είναι ακριβώς «f = διακοσμητής(f)». Αυτό είναι όλο. Όλα τα άλλα σε αυτό το σεμινάριο είναι ότι μια γραμμή εφαρμόζεται σε διαφορετικά σχήματα.
Η θεωρία της μίας γραμμής
Όταν γράφεις:
Η Python το μετατρέπει σε:
Αυτός είναι ο όλος μηχανικός. Το "@decorator_name" πάνω από ένα "def" εκτελεί το "def_name = decorator_name(def_name)" μετά τον ορισμό. Εάν το εσωτερικεύσετε αυτό, οι διακοσμητές παύουν να είναι για πάντα μυστηριώδεις.
Γράψτε τον πρώτο σας διακοσμητή (60 δευτερόλεπτα)
Διακοσμητής είναι κάθε δυνατότητα κλήσης που παίρνει μια συνάρτηση και επιστρέφει μια συνάρτηση. Το τυπικό σχήμα:
Το "args, *kwargs" στο περιτύλιγμα είναι ένα αμυντικό μοτίβο — επιτρέπει στον διακοσμητή να εργαστεί σε οποιαδήποτε λειτουργία ανεξάρτητα από την υπογραφή. Παραλείψτε το και θα λάβετε TypeError: το wrapper() παίρνει 0 ορίσματα θέσης αλλά δόθηκαν 2 τη στιγμή που κάποιος διακοσμεί μια συνάρτηση με παραμέτρους.
Η διόρθωση @functools.wraps
Ένα λεπτό σφάλμα: μετά τη διακόσμηση, το "add.__name__" είναι "wrapper"" και όχι "add"". Οι συμβολοσειρές εγγράφων και οι υποδείξεις τύπων εξαφανίζονται επίσης. Η επιδιόρθωση είναι μία εισαγωγή:
Κανόνας: κάθε διακοσμητής που γράφετε θα πρέπει να χρησιμοποιεί το `@functools.wraps(fn)`. Κοστίζει μία γραμμή και αποτρέπει μια ολόκληρη κατηγορία πόνου εντοπισμού σφαλμάτων (ενδοσκόπηση, εξαρτήματα «pytest», μορφοποιητές «logging», «pickle» — όλα σπάνε αθόρυβα χωρίς αυτό).
Οι τέσσερις διακοσμητές που θα δείτε σε κάθε βάση κώδικα
1. @property — υπολογισμένα χαρακτηριστικά
Το "@property" κάνει μια μέθοδο καλέσιμα σαν να ήταν χαρακτηριστικό. Ιδανικό για παράγωγες τιμές μόνο για ανάγνωση. Υπάρχει επίσης το "@area.setter" για τη διαδρομή εγγραφής, αλλά το 90% των χρήσεων "@property" είναι μόνο για ανάγνωση.
2. «@staticmethod» και «@classmethod».
Το «@classmethod» παίρνει «cls» (η ίδια η κλάση) και χρησιμοποιείται για εναλλακτικούς κατασκευαστές. Το @staticmethod δεν έχει τίποτα το ιδιαίτερο και είναι μια απλή συνάρτηση που τυχαίνει να βρίσκεται μέσα στον χώρο ονομάτων της κλάσης.
3. @functools.cache — απομνημόνευση
Ένας από τους πιο ισχυρούς διακοσμητές stdlib. Απομνημονεύει αυτόματα τη συνάρτηση με βάση τα ορίσματά της. Απαιτεί όλα τα args να μπορούν να κατακερματιστούν (χωρίς λίστες / εντολές ως ορίσματα - χρησιμοποιήστε πλειάδες).
4. @dataclasses.dataclass — εξάλειψη λέβητα
Το «@dataclass» διαβάζει τους σχολιασμούς τύπου σε επίπεδο τάξης και δημιουργεί αυτόματα τα «__init__», «__repr__», «__eq__» και (με «frozen=True») «__hash__». Είναι η μεγαλύτερη βελτίωση ποιότητας ζωής στην Python 3.7+.
Γράψτε έναν διακοσμητή «@retry» (πραγματικό παράδειγμα)
Ένας διακοσμητής που επαναλαμβάνει μια συνάρτηση σε περίπτωση αποτυχίας με εκθετική υποχώρηση:
Προσέξτε τις τρεις ένθετες συναρτήσεις: Το 'retry' δέχεται τα args διαμόρφωσης και επιστρέφει το 'decorator'. Το "decorator" αποδέχεται τη συνάρτηση και επιστρέφει το "wrapper". Το "wrapper" εκτελεί τον βρόχο επανάληψης. Αυτό το μοτίβο τριών επιπέδων μοιάζει με οποιονδήποτε διακοσμητή με επιχειρήματα — απομνημονεύστε το σχήμα, όχι το συγκεκριμένο παράδειγμα.
Διακοσμητές με βάση την τάξη (σπάνιες αλλά χρήσιμες)
Διακοσμητής είναι οποιοσδήποτε καλούμενος. Τα μαθήματα με "__call__" λειτουργούν επίσης:
Χρησιμοποιείται όταν ο διακοσμητής χρειάζεται να κρατήσει κατάσταση που διαρκεί περισσότερο από μία κλήση (ένας μετρητής, μια κρυφή μνήμη, ένας κάδος ορίου ρυθμού).
Συνήθεις παγίδες
1. Ξέχνα το `@functools.wraps` — η ενδοσκόπηση σπάει σιωπηλά.
2. Μεταβλητά προεπιλεγμένα ορίσματα στον ίδιο τον διακοσμητή — το κλασικό σφάλμα "def wrapper(x, cache=[])" δαγκώνει και εδώ.
3. Μέθοδοι διακόσμησης χωρίς αποδοχή του «εαυτού» — θυμηθείτε ότι ο «εαυτός» είναι απλώς ένα επιχείρημα θέσης. Το «args, *kwargs» το πιάνει μια χαρά.
4. Η παραγγελία έχει σημασία κατά τη στοίβαξη: «@a\n@b\ndef f()» είναι «f = a(b(f))». Διαβάστε τις στοίβες από κάτω προς τα πάνω.
Εξάσκηση
Γράψτε ένα διακοσμητικό «@timing» που εκτυπώνει πόσο χρόνο χρειάζεται για να εκτελεστεί η τυλιγμένη συνάρτηση και, στη συνέχεια, εφαρμόστε το σε μια συνάρτηση που υπολογίζει το «sum(range(10_000_000))». Ολόκληρος ο διακοσμητής είναι 8 σειρές με «functools.wraps» + «time.perf_counter».
Μόλις εσωτερικεύσετε ότι το «@x» είναι «f = x(f)», οι διακοσμητές γίνονται ένα από τα πιο παραγωγικά χαρακτηριστικά της Python. Υπάρχουν παντού σε πραγματικές βάσεις κωδικών: διαδρομές Flask/FastAPI (@app.route), εξαρτήματα pytest (@pytest.fixture), προβολές Django (@login_required), Pydantic validators (@field_validator). Το να μάθετε να τα γράφετε μόνοι σας ξεκλειδώνει τη δυνατότητα να διαβάζετε κάθε ένα από αυτά.
Επόμενο βήμα: 10 πρακτικά μαθήματα διακοσμητή — δημιουργήστε τα «@retry», «@memoise», «@rate_limit» και «@requires_auth» από την αρχή με την πραγματική Python να τρέχει στο πρόγραμμα περιήγησής σας.