Πώς να χρησιμοποιήσετε τις συναρτήσεις lambda στην Python
ναρτήσεις lambda στην Python
Οι συναρτήσεις λάμδα αποτελούν μέθοδο λειτουργικής προγραμματισμού από την έκδοση Python 1.0. Ωστόσο, τα τελευταία χρόνια, άλλες τεχνικές έχουν αποκτήσει μεγαλύτερη δημοτικότητα και έχουν αντικαταστήσει σε μεγάλο βαθμό τις συναρτήσεις λάμδα. Παρ’ όλα αυτά, εξακολουθούν να υπάρχουν ορισμένες εξειδικευμένες χρήσεις των συναρτήσεων λάμδα που οι έμπειροι προγραμματιστές Python θα πρέπει να γνωρίζουν.
Τι είναι οι συναρτήσεις λάμδα στην Python;
Στην Python, η συνάρτηση lambda αναφέρεται σε μια ανώνυμη συνάρτηση. Η Python χρησιμοποιεί τη λέξη-κλειδί lambda για να δημιουργήσει μια συνάρτηση lambda. Μια έκφραση lambda αποτελείται από τη λέξη-κλειδί lambda ακολουθούμενη από μια λίστα ορίσματος, μια άνω και κάτω τελεία και μια μεμονωμένη έκφραση. Η έκφραση παρέχεται με τα ορίσματα και αξιολογείται όταν καλείται η συνάρτηση lambda:
lambda argument: expressionΟι συναρτήσεις είναι μια θεμελιώδης δομή γλώσσας σε σχεδόν όλες τις γλώσσες προγραμματισμού και αντιπροσωπεύουν τη μικρότερη επαναχρησιμοποιήσιμη μονάδα κώδικα. Συνήθως, οι συναρτήσεις στην Python ορίζονται με τη λέξη-κλειδί def. Θα σας δείξουμε τη συνάρτηση square που πολλαπλασιάζει έναν αριθμό με τον εαυτό του ως παράδειγμα:
# Define square function
def square(num):
return num * num
# Show that it works
assert square(9) == 81pythonΗ λέξη-κλειδί def είναι ένας γνωστός τρόπος για τον ορισμό συναρτήσεων στην Python, αλλά η γλώσσα διαθέτει επίσης τις λάμδα συναρτήσεις. Πρόκειται για ανώνυμες συναρτήσεις που ορίζουν μια έκφραση με παραμέτρους. Οι λάμδα συναρτήσεις μπορούν να χρησιμοποιηθούν οπουδήποτε απαιτείται μια συνάρτηση ή μπορούν να αντιστοιχιστούν σε ένα όνομα. Μπορείτε να δείτε την έκφραση λάμδα που αντιστοιχεί στη συνάρτηση τετραγώνου εδώ:
# Create square function
squared = lambda num: num * num
# Show that it works
assert squared(9) == 81pythonΠοια είναι η διαφορά μεταξύ lambda και def;
Μπορεί να φαίνεται παράξενο ότι η Python σας επιτρέπει να δημιουργείτε συναρτήσεις τόσο με lambda όσο και με def. Ωστόσο, Lambda δεν είναι δική του λειτουργία, αλλά απλώς ένας άλλος τρόπος για να δημιουργήσετε τοπικά σύντομες συναρτήσεις. Κάθε συνάρτηση που δημιουργείται με lambda μπορεί επίσης να δημιουργηθεί με def. Ωστόσο, το αντίστροφο δεν ισχύει.
Σε συντακτικό επίπεδο, lambda και def είναι και τα δύο λέξεις-κλειδιά. Μια βασική διαφορά μεταξύ τους είναι ο αυστηρός διαχωρισμός των δηλώσεων και των εκφράσεων στην Python. Οι δηλώσεις είναι βήματα στην εκτέλεση του κώδικα, ενώ οι εκφράσεις αξιολογούνται ως τιμή.
Def ξεκινά μια δήλωση, ή πιο συγκεκριμένα μια σύνθετη δήλωση, η οποία περιέχει περαιτέρω δηλώσεις. Μόνο return δηλώσεις μπορούν να εμφανίζονται μέσα σε μια def δήλωση. Μια return δήλωση επιστρέφει μια τιμή όταν καλείται η συνάρτηση που ορίζεται με def.
Σε αντίθεση με τη δήλωση def, lambda ξεκινά μια έκφραση που δεν μπορεί να περιέχει δηλώσεις. Η έκφραση lambda δέχεται ένα ή περισσότερα ορίσματα και επιστρέφει μια ανώνυμη συνάρτηση. Όταν καλείται η συνάρτηση lambda, η έκφραση που περιέχεται σε αυτήν αξιολογείται με τα ορίσματα που έχουν περάσει και επιστρέφεται.
Ποιοι είναι οι περιορισμοί των εκφράσεων lambda της Python;
Η Python έχει περιορίσει σκόπιμα τη χρησιμότητα των συναρτήσεων lambda, καθώς συνήθως είναι προτιμότερο να ονομάζουμε τις συναρτήσεις. Αυτό αναγκάζει τους προγραμματιστές να σκεφτούν τη σημασία της συνάρτησης και να διακρίνουν σαφώς τα μέρη της.
Τα λάμδα δεν μπορούν να περιέχουν εντολές, σε αντίθεση με το σώμα μιας συνάρτησης που ορίζεται με τη λέξη-κλειδί def. Επομένως , δεν είναι δυνατό να χρησιμοποιηθούν if, for κ.λπ. σε μια συνάρτηση λάμδα. Επίσης, δεν είναι δυνατό να προκληθεί μια εξαίρεση, καθώς αυτό απαιτεί μια δήλωση raise.
Οι συναρτήσεις Lambda στην Python μπορούν να περιέχουν μία μόνο έκφραση, η οποία αξιολογείται όταν καλείται. Οι σημειώσεις τύπου δεν μπορούν να χρησιμοποιηθούν εντός της έκφρασης lambda. Σήμερα, οι περισσότερες περιπτώσεις χρήσης των συναρτήσεων lambda στην Python χρησιμοποιούν άλλες τεχνικές, όπως οι συνειδητοποιήσεις.
Διαφορετικές χρήσεις των συναρτήσεων λάμδα στην Python
Τα λάμδα προέρχονται από τη λειτουργική προγραμματισμό. Σε ορισμένες γλώσσες, όπως η JavaScript, οι ανώνυμες συναρτήσεις χρησιμοποιούνται ευρέως χωρίς να απαιτείται ειδική λέξη-κλειδί. Στην Python, οι εκφράσεις λάμδα χρησιμοποιούνται για τη δημιουργία μικρών συναρτήσεων σε τοπικό επίπεδο. Παρακάτω θα εξετάσουμε τις πιο χρήσιμες εφαρμογές τους.
Πώς να συμπληρώσετε συναρτήσεις ανώτερης τάξης σε Python με λάμδα
Τα λάμδα χρησιμοποιούνται συχνά με συναρτήσεις ανώτερης τάξης, όπως map(), filter() και reduce(). Τα στοιχεία ενός επαναλήψιμου μπορούν να μετασχηματιστούν χωρίς τη χρήση βρόχων χάρη στα λάμδα. Οι συναρτήσεις ανώτερης τάξης είναι συναρτήσεις που λαμβάνουν συναρτήσεις ως παραμέτρους ή επιστρέφουν μια συνάρτηση.
Η συνάρτηση map() δέχεται ως παραμέτρους μια συνάρτηση και ένα επαναλήψιμο. Εκτελεί τη συνάρτηση για κάθε στοιχείο του επαναλήψιμου. Ας δοκιμάσουμε να δημιουργήσουμε τετράγωνα αριθμούς. Χρησιμοποιούμε τη συνάρτηση map() και περνάμε μια έκφραση λάμδα ως όρισμα, η οποία δημιουργεί τη συνάρτηση τετράγωνο. Η συνάρτηση τετράγωνο εφαρμόζεται σε κάθε στοιχείο της λίστας με map():
nums = [3, 5, 7]
# Square numbers using `map()` and `lambda`
squares = map(lambda num: num ** 2, nums)
# Show that it works
assert list(squares) == [9, 25, 49]pythonΑπό την έκδοση Python 3.0 και μετά, οι συναρτήσεις map() και filter() επιστρέφουν ένα επαναλήψιμο αντικείμενο αντί για μια λίστα. Μια κλήση list() χρησιμοποιείται μέσα στις δηλώσεις assert για να αποσυμπιέσει τα επαναλήψιμα αντικείμενα σε μια λίστα.
Οι λίστες κατανόησης προσφέρουν μια πιο σύγχρονη προσέγγιση για την επεξεργασία επαναλήψιμων στοιχείων. Αντί να καταφύγουμε στο map() και να δημιουργήσουμε μια συνάρτηση λάμδα, μπορούμε να περιγράψουμε την πράξη απευθείας:
nums = [3, 5, 7]
# Square numbers using list comprehension
squares = [num ** 2 for num in nums]
# Show that it works
assert squares == [9, 25, 49]pythonΗ συνάρτηση filter() μπορεί να χρησιμοποιηθεί για να φιλτράρει τα στοιχεία ενός επαναλήψιμου. Μπορούμε να επεκτείνουμε το παράδειγμά μας για να δημιουργήσουμε μόνο ζυγούς τετραγωνικούς αριθμούς:
# List of numbers 1-4
nums = [1, 2, 3, 4]
# Square each number
squares = list(map(lambda num: num ** 2, nums))
# Filter out the even squares
even_squares = filter(lambda square: square % 2 == 0, squares)
# Show that it works
assert list(even_squares) == [4, 16]pythonΔείχνουμε την προτιμώμενη προσέγγιση της χρήσης της κατανόησης λίστας για τη δημιουργία του ίδιου αποτελέσματος χωρίς τη χρήση λάμδα και συναρτήσεων ανώτερης τάξης. Το τμήμα if της κατανόησης χρησιμοποιείται για να φιλτράρει τους ζυγούς αριθμούς από τους παραγόμενους τετραγωνικούς αριθμούς:
# List of numbers 1-4 squared
squares = [num ** 2 for num in range(1, 5)]
# Filter out the even squares
even_squares = [square for square in squares if square % 2 == 0]
# Show that it works
assert even_squares == [4, 16]pythonΗ συνάρτηση reduce() της Python δεν περιλαμβάνεται στην τυπική βιβλιοθήκη από την έκδοση Python 3.0. Αυτή η συνάρτηση βρίσκεται στο module functools.
Πώς να εφαρμόσετε βασικές λειτουργίες σε Python με λάμδα
Οι συνειδητοποιήσεις έχουν αντικαταστήσει σε μεγάλο βαθμό τις κλασικές συναρτήσεις ανώτερης τάξης map() και filter() στην Python. Ωστόσο, οι βασικές συναρτήσεις μπορούν να χρησιμοποιηθούν για να δείξουν όλες τις δυνατότητες των λάμδα.
Οι συναρτήσεις σύγκρισης Python sorted(), min() και max() λειτουργούν σε επαναλήψιμα στοιχεία. Κάθε στοιχείο του επαναλήψιμου στοιχείου υποβάλλεται σε σύγκριση όταν καλείται. Οι τρεις συναρτήσεις λαμβάνουν μια συνάρτηση κλειδιού ως προαιρετική παράμετρο key. Η συνάρτηση κλειδιού καλείται για κάθε στοιχείο και επιστρέφει μια τιμή κλειδιού για τη λειτουργία σύγκρισης.
Ας εξετάσουμε το ακόλουθο πρόβλημα. Έχουμε έναν φάκελο με αρχεία εικόνων, τα ονόματα των οποίων αντιστοιχούν σε μια λίστα Python. Θέλουμε να ταξινομήσουμε τη λίστα. Όλα τα ονόματα αρχείων ξεκινούν με img, ακολουθούμενο από έναν αριθμό:
# List of image file names
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']pythonΑν χρησιμοποιήσουμε τη συνάρτηση sorted() της Python, χρησιμοποιείται η λεξικογραφική σειρά. Αυτή αντιμετωπίζει τα διαδοχικά ψηφία ως μεμονωμένους αριθμούς. Έτσι, οι αριθμοί ['1', '2', '100'] τοποθετούνται στη σειρά ['1', '100', '2']. Το αποτέλεσμα δεν είναι αυτό που περιμένουμε:
# Sort using lexicographic order
sorted_image = sorted(images)
# Show that it works
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']pythonΠερνάμε μια έκφραση lambda που παράγει μια συνάρτηση κλειδιού για να διασφαλίσουμε ότι η ταξινόμηση είναι σωστή. Η συνάρτηση κλειδιού εξάγει το αριθμητικό μέρος ενός ονόματος αρχείου, το οποίο χρησιμοποιείται ως κλειδί από sorted():
# Extract numeric component and sort as integers
sorted_image = sorted(images, key=lambda name: int(name[3:]))
# Show that it works
assert sorted_image == ['img1', 'img2', 'img3', 'img22', 'img30', 'img100']pythonΗ βασική λειτουργία χρησιμοποιείται τοπικά και μόνο μία φορά. Δεν είναι απαραίτητο να ορίσετε μια επιπλέον ονομασμένη λειτουργία για αυτήν. Οι λάμδα είναι ο σωστός τρόπος για τη δημιουργία βασικών λειτουργιών. Ας δούμε δύο ακόμη παραδείγματα.
Όπως και sorted(), οι ενσωματωμένες συναρτήσεις Python min() και max() δέχονται μια προαιρετική συνάρτηση κλειδιού. Οι συναρτήσεις βρίσκουν το μικρότερο και το μεγαλύτερο στοιχείο σε μια λίστα ή άλλο επαναλήψιμο αντικείμενο. Το μικρότερο ή το μεγαλύτερο στοιχείο είναι θέμα ορισμού και μπορεί να καθοριστεί χρησιμοποιώντας τη συνάρτηση κλειδιού.
Είναι σαφές τι σημαίνει μικρότερο ή μεγαλύτερο στοιχείο για λίστες απλών τιμών, όπως μια λίστα αριθμών. Σε αυτή την περίπτωση δεν χρειαζόμαστε μια ειδική συνάρτηση κλειδιού:
nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69pythonΕάν δεν μεταβιβαστεί καμία συνάρτηση κλειδιού, χρησιμοποιείται ως προεπιλογή η συνάρτηση ταυτότητας f(x) = x. Αυτό μπορεί εύκολα να οριστεί ως Python lambda με lambda x: x.
Αλλά τι γίνεται αν κάθε στοιχείο ενός επαναλήψιμου περιλαμβάνει πολλαπλές ημερομηνίες; Ας φανταστούμε μια λίστα λεξικών που αντιπροσωπεύουν άτομα με τα ονόματα και τις ηλικίες τους. Ποια είναι τα κριτήρια για min() και max() όταν αποφασίζουμε ποιο είναι το μικρότερο και το μεγαλύτερο στοιχείο; Εδώ είναι που μια βασική λειτουργία είναι χρήσιμη.
Χρειαζόμαστε δείγματα δεδομένων για να δείξουμε πώς λειτουργούν οι βασικές συναρτήσεις. Ας δημιουργήσουμε μια συνάρτηση Person() που θα λειτουργεί ως κατασκευαστής:
# Constructor function for dict representing a person
def Person(name, age):
return {'name': name, 'age': age}
# Check that it works as expected
assert Person('Jim', 42) == {'name': 'Jim', 'age': 42}pythonΔημιουργούμε μια λίστα ατόμων χρησιμοποιώντας τη συνάρτηση κατασκευαστή μας:
# Create list of people
people = [person('Jim', 42), person('Jack', 51), person('John', 69)]pythonΒρίσκουμε το παλαιότερο άτομο χρησιμοποιώντας την κλήση max(). Αυτό δημιουργεί μια βασική συνάρτηση χρησιμοποιώντας την έκφραση lambda, η οποία λαμβάνει ένα λεξικό ατόμων και εξάγει την ηλικία από αυτό ως στοιχείο σύγκρισης:
# Find the oldest person
oldest = max(people, key=lambda person: person['age'])
# Check that it works
assert oldest == Person('John', 69)pythonΗ προσέγγιση λειτουργεί ακριβώς το ίδιο για τη συνάρτηση min(). Σε αυτή την περίπτωση, θα ορίσουμε τη συνάρτηση κλειδιού εκτός της κλήσης min() και θα χρησιμοποιήσουμε ξανά μια έκφραση λάμδα. Αυτό βελτιώνει την αναγνωσιμότητα και αξίζει τον κόπο αν η συνάρτηση κλειδιού έχει πολλαπλές τοπικές χρήσεις:
# Define key function to compare people by age
by_age = lambda person: person['age']
# Find the youngest person
youngest = min(people, key=by_age)
# Check that it works
assert youngest == Person('Jim', 42)pythonΠώς να δημιουργήσετε κλεισίματα με Python lambdas
Οι λάμδα της Python χρησιμοποιούνται επίσης κατά τον ορισμό των κλεισίματος. Πρόκειται για συναρτήσεις που δημιουργούνται από άλλες συναρτήσεις και αποθηκεύουν μια τιμή. Τα κλεισίματα μπορούν να χρησιμοποιηθούν για τη δημιουργία οικογενειών παρόμοιων συναρτήσεων. Θα δείξουμε ένα συνηθισμένο παράδειγμα όπου δημιουργούνται συναρτήσεις δύναμης.
Οι συναρτήσεις δύναμης λαμβάνουν ένα όρισμα και το εκθέτουν σε εκθετική συνάρτηση. Η τετραγωνική συνάρτηση f(x) = x ^ 2 και η κυβική συνάρτηση f(x) = x ^ 3 είναι γνωστά παραδείγματα. Οι συναρτήσεις δύναμης μπορούν να δημιουργηθούν ως κλεισίματα χρησιμοποιώντας μια συνάρτηση κατασκευαστή. Θα χρησιμοποιήσουμε μια έκφραση λάμδα, πράγμα που σημαίνει ότι δεν χρειάζεται να ορίσουμε μια εσωτερική συνάρτηση με όνομα:
# Define constructor function for power functions
def power(n):
return lambda num: num ** n
# Create square and cubic functions as closures
square = power(2)
cubic = power(3)
# Show that it works
assert square(10) == 100
assert cubic(10) == 1000pythonΠώς να χρησιμοποιήσετε την έκφραση άμεσης κλήσης συνάρτησης (IIFE) με τις λάμδα συναρτήσεις της Python
Το IIFE, που προφέρεται «iffy», είναι ένα γνωστό μοτίβο στη JavaScript. Περιλαμβάνει τον ορισμό μιας ανώνυμης συνάρτησης και την άμεση εκτέλεσή της.
Οι λάμδα μπορούν να χρησιμοποιηθούν ως IIFE, αν και δεν είναι πολύ χρήσιμες λόγω των περιορισμών της Python. Το μόνο που χρειάζεται να κάνουμε είναι να βάλουμε παρενθέσεις γύρω από την έκφραση λάμδα:
(lambda num: num * num)pythonΚαι ένα άλλο ζεύγος παρενθέσεων που περιέχει το (τα) όρισμα (όρισματά)
assert (lambda num: num * num)(3) == 9python