Τι είναι οι συναρτήσεις¶
Οι συναρτήσεις (functions) είναι μια επαναχρησιμοποιούμενη ομάδα εντολών η οποία εκτελείται μόνο όταν κληθεί. Στο σύνολο αυτό των εντολών δίνεται ένα όνομα με το οποίο είναι αναγνωρίσιμο. Μπορούμε να καλέσουμε μια συνάρτηση όσες φορές θέλουμε στο πρόγραμμά μας.Μια συνάρτηση μπορεί να δέχεται παραμέτρους δηλαδή δεδομένα εισόδου και να παράγει αποτελέσματα δηλαδή δεδομένα εξόδου. Με την χρήση συναρτήσεων επιτυγχάνεται, αρθρωτή δομή (modularity), λιγότερη επανάληψη κώδικα (code reusing), ευκολότερη αποσφαλμάτωση, αναγνωσιμότητα και ευκολία διόρθωσης. Πέρα από τις συναρτήσεις που μπορεί να συντάξει ο προγραμματιστής (user-defined functions), η Python προσφέρει ήδη έτοιμες συναρτήσεις (built-in functions).
Η βασική ιδέα με την χρήση των συναρτήσεων είναι να απομονώσουμε ένα κομμάτι κώδικα που επιτελεί πολύ συγκεκριμένη λειτουργία και να το καλούμε όταν μας είναι αναγκαίο. Για παράδειγμα αν σε ένα πρόγραμμα απαιτείται ο τακτικός υπολογισμός του Πυθαγόρειου θεωρήματος, αντί να επιλύουμε κάθε φορά την αντιστοίχη εξίσωση αρκεί να δημιουργήσουμε μια συνάρτηση που θα δέχεται σαν παραμέτρους τα μήκη δυο καθέτων πλευρών του ορθογωνίου τριγώνου και θα επιστρέφει το τετράγωνο της υποτείνουσας. Οπότε κάθε φορά που θα χρειάζεται η επίλυση του Πυθαγόρειου θεωρήματος αρκεί η κλήση της συνάρτησης και ο ορισμός των αντίστοιχων παραμέτρων σε αυτήν. Αν διαπιστώσουμε ότι ο μαθηματικός τύπος που έχουμε χρησιμοποιήσει είναι λάθος τότε αρκεί η διόρθωση μόνο σε ένα σημείο του κώδικα, σε αυτό της συνάρτησης. Αν αντιθέτως στο πρόγραμμά μας αντι για συνάρτηση είχαμε χρησιμοποιήσει ξεχωριστά την επίλυση της ίδιας εξίσωσης τότε θα έπρεπε να εντοπίσουμε και να διορθώσουμε όλα αυτά τα επιμέρους σημεία του κώδικα.
Τρόπος σύνταξης και κλήσης¶
Ο ορισμός μιας συνάρτησης στην Python ξεκινάει με την δεσμευμένη λέξη def, στην συνέχεια δίνεται ένα όνομα για την συνάρτηση, ακολουθούν οι παρενθέσεις (εντός τους μπορεί να ορίζονται και οι παράμετροι) και ακολουθεί η άνω/κάτω τελεία (colon). Στην συνέχεια ακολουθεί (με εσοχές 4 space) μια σύντομη περιγραφή (docstrings) για το τι κάνει η συνάρτηση (προαιρετικά), και το σχετικό κομμάτι εντολών. Μπορεί κατά την ολοκλήρωση, επίσης προαιρετικά, η συνάρτηση να επιστρέφει κάποια τιμή μέσω της λέξης-κλειδί return. Σε κάθε περίπτωση όταν το return καλείται μέσα στην συνάρτηση τότε αυτή σταματάει την εκτέλεση του κώδικα που περιέχει και επιστρέφει στο σημείο απ’ όπου καλέστηκε.
Η ονοματολογία των συναρτήσεων υπακούει στους κανόνες ονοματολογίας των μεταβλητών και συνήθως περιγράφουν τι κάνουν.
Προηγείται ο ορισμός μια συνάρτησης και μετά η κλήση της. Γι’ αυτό τον λόγο οι συναρτήσεις δηλώνονται πρώτα σε ένα πρόγραμμα και μετά ακολουθεί το κυρίως σώμα του κώδικα μέσα στον οποίο μπορούμε να τις καλέσουμε.
Παρακάτω δίνεται μια απλουστευτική μορφή της σύνταξης μιας συνάρτησης.
def function_name(parameters):
"""docstring"""
statement(s)Ας δούμε ένα πιο πρακτικό παράδειγμα. Παρακάτω ακολουθεί η σύνταξη μιας απλής συνάρτηση όπου δεν ορίζονται κάποιοι παράμετροι ούτε επιστρέφεται κάποια τιμή.
def sayHello():
'''Μια συνάρτηση που χαιρετά τον κόσμο.'''
print("Hello World!")Στην συνέχεια ακολουθεί η κλήση της όπου ουσιαστικά εκτελείται το σώμα της συνάρτησης. Η κλήση της γίνεται ορίζοντας το όνομά της και στην συνέχεια ακολουθούν παρενθέσεις:
sayHello()Hello World!
Συνάρτηση με παραμέτρους¶
Σε αρκετές περιπτώσεις μια συνάρτηση μπορεί να περιλαμβάνει δεδομένα εισόδου (παράμετροι) τα οποία είναι χρήσιμα κατά την εκτέλεση του κώδικά της. Οι παράμετροι αυτοί ορίζονται κατά την σύνταξη της συνάρτησης, μέσα στις παρενθέσεις που ακολουθούν το όνομα της. Κατά την κλήση οι παράμετροι αυτοί λαμβάνουν τιμές ή μεταβλητές και ονομάζονται ορίσματα.
def sayHelloUser(name):
'''
Μια συνάρτηση που χαιρετά τον κάποιο.
Παράμετροι:
name(str): ένα όνομα
Επιστρέφει:
Τίποτα
'''
print("Hello", name, "!")Στην παραπάνω συνάρτηση με το ονομα sayHelloUser ορίσαμε την παράμετρο name όπου την χρησιμοποιούμε στην συνέχεια στο κυρίως σώμα της συνάρτησης.
Στην συνέχεια καλούμε την συνάρτηση δίνοντας σαν όρισμα (τιμή στην παράμετρο) την συμβολοσειρά “Κώστας”.
Έτσι η παράμετρος name δέχεται όρισμα την τιμή “Κώστας”.
sayHelloUser("Κώστας")Hello Κώστας !
Αντίστοιχα μπορούμε να δώσουμε διαφορετική τιμή στο όρισμα ακόμα και μέσω μίας μεταβλητής:
onoma="Χρήστος"
sayHelloUser(onoma)Hello Χρήστος !
Το παραπάνω μπορεί να γραφτεί και πιο ρητά κάτα πέρασμα του ορίσματος στην παράμετρο.
onoma="Ελένη"
sayHelloUser(name=onoma)Hello Ελένη !
Η χρησιμότητα του docstring που αναγράφουμε σε μια συνάρτηση φαίνεται αν καλέσουμε την βοήθεια της Python αναφορικά με την συγκεκριμένη συνάρτηση. Με αυτόν τον τρόπο λαμβάνουμε πληροφορίες για την λειτουργία της χωρίς να χρειαστεί να ανατρέξουμε στην σύνταξή της.
help(sayHelloUser)Help on function sayHelloUser in module __main__:
sayHelloUser(name)
Μια συνάρτηση που χαιρετά τον κάποιο.
Παράμετροι:
name(str): ένα όνομα
Επιστρέφει:
Τίποτα
Εναλλακτικά μπορούμε να χρησιμοποιήσουμε το __doc__ attribute της συνάρτησης.
print(sayHelloUser.__doc__)
Μια συνάρτηση που χαιρετά τον κάποιο.
Παράμετροι:
name(str): ένα όνομα
Επιστρέφει:
Τίποτα
Παρακάτω ορίζεται μια συνάρτηση με δύο παραμέτρους:
def add(num1, num2) :
"""Add two numbers"""
num3 = num1 + num2
print("Το άθροισμα των αριθμών " + str(num1) + " και " +str(num2) + " είναι " + str(num3))Την καλούμε με τα σχετικά ορίσματα:
add(10,7)
# αντί τιμών πέρασμα μεταβλητών ως ορίσματα στην συνάρτηση
a=2
b=5
add(a, b)
# ή μεικτός τρόπος
add(9, a)Το άθροισμα των αριθμών 10 και 7 είναι 17
Το άθροισμα των αριθμών 2 και 5 είναι 7
Το άθροισμα των αριθμών 9 και 2 είναι 11
Ορίσματα θέσης (Positional arguments)¶
Όταν συντάσσεται μια συνάρτηση με πολλές παραμέτρους κατά την κλήση της πρέπει να ορίσουμε και αντίστοιχα ορίσματα.
Το πέρασμα αυτών των ορισμάτων γίνεται είτε α) κατα θέση (positional arguments) είτε β) με βάση την λέξη κλειδί (keyword arguments).
Τα ορίσματα θέσης ορίζονται κατά σειρά με βάση τις αντίστοιχες παραμέτρους που έχουν οριστεί κατά την σύνταξη της συνάρτησης. Το παρακάτω παράδειγμα είναι πιο κατανοητό:
def car(style, color):
'''Information about a car'''
print("Ο τύπους του αυτοκινήτου είναι:", style)
print("και έχει χρώματα:", color)
car("Sedan", "μαύρο")Ο τύπους του αυτοκινήτου είναι: Sedan
και έχει χρώματα: μαύρο
Στην παραπάνω περίπτωση ορίσαμε μια συνάρτηση (function) που εκτυπώνει το style και το color ενός αυτοκινήτου. Κατά την κλήση της περνάμε τα ορίσματα κατά θέση. Δηλαδή στην πρώτη θέση κατά την σύνταξη έχουμε την παράμετρο style που παίρνει το όρισμα “Sedan” και στην δεύτερη θέση έχουμε την παράμετρο color που παίρνει το όρισμα “μαύρο”. Με τα ορίσματα θέσης πρέπει να είμαστε ακριβείς στις τιμές που περνάμε σε κάθε γιατί αλλιώς μπορεί να έχουμε απροσδιόριστα αποτελέσματα. Δείτε το παρακάτω παράδειγμα:
car("κόκκινo", "SUV")Ο τύπους του αυτοκινήτου είναι: κόκκινo
και έχει χρώματα: SUV
Ορίσματα με βάση την λέξη-κλειδί (keyword arguments)¶
Τα ορίσματα κλειδιά είναι πιο ευέλικτα καθότι περνάμε ένα ζεύγος κλειδιού-τιμής. Έτσι ορίζουμε ρητά και ονομαστικά σε κάθε παράμετρο τι τιμή θα λάβει. Σε αυτή την περίπτωση δεν παίζει ρόλο η σειρά που περνάμε τιμές αλλά η αντιστοιχία παραμέτρου με τιμή ορίσματος. Γι’ αυτόν τον λόγο χρειάζεται προσοχή κατά την αντιστοιχία να χρησιμοποοιούμε τα σωστά ονόματα παραμέτρων όπως διατυπώνονται στην σύνταξη της συνάρτησης. Ας δούμε το παραπάνω παράδειγμα με ορίσματα κλειδιά:
car(color="κόκκινo", style="SUV")
car(style="SUV",color="κόκκινo", )Ο τύπους του αυτοκινήτου είναι: SUV
και έχει χρώματα: κόκκινo
Ο τύπους του αυτοκινήτου είναι: SUV
και έχει χρώματα: κόκκινo
Προκαθορισμένη τιμή παραμέτρου¶
Μια παράμετρο μπορεί να έχει μια προκαθορισμένη τιμή κατά την σύνταξη της συνάρτησης. Αν κατά την κλήση της συνάρτησης δώσουμε τιμή σε αυτήν την παράμετρο τότε αγνοείται η προκαθορισμένη τιμή. Όμως αν δεν δώσουμε τιμή τότε η παράμετρος κρατάει την προκαθορισμένη τιμή. Έτσι σε αρκετές περιπτώσεις όταν καλούμε μια συνάρτηση μπορεί οι προκαθορισμένες τιμές να αρκούν και να μην χρειάζεται να ορίσουμε τιμές στην αντίστοιχη παράμετρο. Ας δούμε το παρακάτω παράδειγμα:
def car(style, color, wheels="τέσσερις"):
'''Information about a car'''
print("Ο τύπους του αυτοκινήτου είναι:", style)
print("Έχει χρώμα", color, "και έχει", wheels, "τροχούς")car(color="μπλέ", style="SUV")Ο τύπους του αυτοκινήτου είναι: SUV
Έχει χρώμα μπλέ και έχει τέσσερις τροχούς
Στο παραπάνω παράδειγμα δεν χρειάζεται να ορίσουμε τιμή για την παράμετρο wheels γιατί μας αρκεί η προκαθορισμένη, μιας και όλα σχεδόν τα επιβατικά έχουν τέσσερις τροχούς. Αντίστοιχα μπορεί να οριστούν και προκαθορισμένες τιμές και για τις άλλες παραμέτρους.
Βέβαια μπορούμε να αγνοήσουμε την προκαθορισμένη τιμή και να περάσουμε την αναγκαία κατά περίπτωση. π.χ. εδώ αγνοούμε την προκαθορισμένη τιμή για την παράμετρο wheels (τέσσερις) και ορίζουμε τιμή έξι.
car(color="μπλέ", wheels="έξι",style="SUV")Ο τύπους του αυτοκινήτου είναι: SUV
Έχει χρώμα μπλέ και έχει έξι τροχούς
Εναλλακτικά το προηγούμενο μπορεί να συνταχθεί με ορίσματα θέσης:
car("μπλέ", "SUV", "έξι")Ο τύπους του αυτοκινήτου είναι: μπλέ
Έχει χρώμα SUV και έχει έξι τροχούς
Επιστροφή τιμής από μία συνάρτηση¶
Στα προηγούμενα παραδείγματα περιγράφεται η σύνταξη συναρτήσεων χωρίς να επιστρέφονται τιμές από αυτές. Στην συνέχεια θα δούμε πως μια συνάρτηση μπορεί να επιστρέψει τιμές μέσω της λέξης-κλειδιού return. Ας επεκτείνουμε το προηγούμενο παράδειγμα με την συνάρτηση που προσθέτει δύο αριθμούς. Η συνάρτηση αυτή μέχρι τώρα απλά δημιουργεί μια νέα μεταβλητή με το άθροισμα και στην συνέχεια εκτυπώνει ένα μήνυμα. Δεν επιστρέφει τίποτα. Αν δοκιμάσουμε να δούμε τι τύπο δεδομένων επιστρέφει θα δούμε ότι είναι NoneType.
type(add(1, 2))Το άθροισμα των αριθμών 1 και 2 είναι 3
NoneTypeΑς τροποποιήσουμε την συνάρτηση ώστε να επιστρέφει μία τιμή. Θα δώσουμε νέο όνομα στην συνάρτηση, addV2
def addV2(num1, num2) :
"""Add two numbers"""
num3 = num1 + num2
print("Το άθροισμα των αριθμών " + str(num1) + " και " +str(num2) + " είναι " + str(num3))
return(num3)Πλέον η συνάρτηση επιστρέφει το άθροισμα των τιμών που είναι ακέραιος τύπος δεδομένων. Το αποτέλεσμα της συνάρτησης που επιστρέφει το return μπορούμε να το προσαρτήσουμε σε μια μεταβλητή.
result=addV2(5,3)Το άθροισμα των αριθμών 5 και 3 είναι 8
Η συνάρτηση συνεχίζει να εκτυπώνει το μήνυμα που έχει οριστεί κατά την σύνταξη αλλά πλέον επιστρέφει και τιμή:
result8Την οποία μπορούμε να χρησιμοποιήσουμε σε άλλες προτάσεις του κώδικα. πχ
print("Το αποτέλεσμα της πράξης είναι:" + str(result))Το αποτέλεσμα της πράξης είναι:8
ή μπορούμε να την καλέσουμε άμεσα:
print("Το αποτέλεσμα της πράξης είναι:" + str(addV2(9,9)))Το άθροισμα των αριθμών 9 και 9 είναι 18
Το αποτέλεσμα της πράξης είναι:18
Ο τύπος δεδομένων που επιστρέφει η συνάρτηση είναι ακέραιος (int):
type(addV2(1, 2))Το άθροισμα των αριθμών 1 και 2 είναι 3
intΠολλαπλές επιστρεφόμενες τιμές¶
Σε ορισμένες περιπτώσεις συναρτήσεων μπορεί να απαιτούμε να επιστρέφονται παραπάνω από μία τιμές. Τότε χρησιμοποιούμε μια μέθοδος που λέγεται tuple packing κατά την οποία δημιουργούμε μια πλειάδα με τις αναγκαίες τιμές. Κατά την κλήση της συνάρτησης μπορούμε να προσαρτήσουμε το αποτέλεσμα που επιστρέφει σε αντίστοιχο πλήθος μεταβλητών (tuple unpacking).
def addV3(num1, num2) :
"""Add two numbers"""
num3 = num1 + num2
return(num3, num3**2) #tuple packingsum, squareofsum = addV3(4, 1) # tuple unpacking
print("Sum:", sum, ", Square of sum:", squareofsum)Sum: 5 , Square of sum: 25
Μια συνάρτηση μπορεί να επιστρέφει και ένα λεξικό ή μία λίστα.
Εμβέλεια μεταβλητών¶
Οι μεταβλήτες στην Python διαχωρίζονται με βάση την εμβέλειά τους (δηλαδή από ποιό σημείο του κώδικα είναι “ορατές”), σε τοπικές (local) και καθολικές (global).
Καθολικές είναι οι μεταβλητές που ορίζονται στο κυρίως σώμα του κώδικα και δεν εντάσσονται μέσα σε κάποια συνάρτηση. Αυτές είναι προσπελάσιμες από κάθε σημείο του κώδικα ακόμα και μέσα από συναρτήσεις.
Τοπικές είναι οι μεταβλητές οι οποίες ορίζονται μέσα σε συναρτήσεις, είναι προσπελάσιμες μόνο μέσα σε αυτές και διαρκούν όσο διαρκεί η εκτέλεση μιας συνάρτησης. Κατά την πολλάπλή κλήση μιας συνάρτησης δημιουργούνται αντίστοιχες τοπικές μεταβλητές που περιγράφονται στην σύνταξή της. Οι παράμετροι μιας συνάρτησης αποτελούν και αυτές τοπικές μεταβλητές. Ας ορίσουμε μια τοπική μεταβλητή. Στην παρακάτω συνάρτηση ορίζεται η τοπική μεταβλητή text.
def PrintMyText():
text = "Athens"
print(text)
PrintMyText()Athens
Αν δοκιμάσουμε να προσπελάσουμε την μεταβλητή text εκτός συνάρτησης θα λάβουμε σχετικό σφάλμα:
print(text)---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[29], line 1
----> 1 print(text)
NameError: name 'text' is not definedΌπως προαναφέρθηκε και μια παράμετρος αποτελεί τοπική μεταβλητή:
def PrintMyText(p):
print(p)
PrintMyText("Βόλος")Βόλος
Αντιθέτως μια καθολική μεταβλητή είναι προσβάσιμη σε μία συνάρτηση.
city="Λάρισα"
def PrintMyText():
print("Η τιμή της μεταβλητής city ΕΝΤΟΣ της συνάρτησης", city) # η καθολική μεταβλητή είναι προσβάσιμη μέσα στην συνάρτηση
PrintMyText() # γι αύτό και εκτυπώνεται κατά την κλήση
print("Η τιμή της μεταβλητής city ΕΚΤΟΣ συνάρτησης", city) # και φυσικά είναι διαθέσιμη και εκτός συνάρτησης από οποιοδήποτε σημείο του κώδικαΗ τιμή της μεταβλητής city ΕΝΤΟΣ της συνάρτησης Λάρισα
Η τιμή της μεταβλητής city ΕΚΤΟΣ συνάρτησης Λάρισα
Τι συμβαίνει όμως όταν μια μεταβλητή ορίζεται με την ίδια ονομασία σαν καθολική και τοπική; Δείτε το παρακάτω παράδειγμα:
city="Λάρισα"
def PrintMyText():
city="Βόλος" # τοπική μεταβλητή, προτεραιότητα έναντι της καθολικής
print("Η τιμή της μεταβλητής city ΕΝΤΟΣ της συνάρτησης (τοπική)", city) # εδώ εκτυπώνεται η τοπική μεταβλητή
PrintMyText() # θα εκτυπώσει την τοπική
print("Η τιμή της μεταβλητής city ΕΚΤΟΣ συνάρτησης (καθολική)", city) # θα εκτυπώσει την καθολικήΗ τιμή της μεταβλητής city ΕΝΤΟΣ της συνάρτησης (τοπική) Βόλος
Η τιμή της μεταβλητής city ΕΚΤΟΣ συνάρτησης (καθολική) Λάρισα
Αν θέλουμε να αλλάξουμε την τιμή μιας καθολικής μέσα σε μια συνάρτηση χρησιμοποιούμε την λέξη κλειδί global για να αναφερθούμε σε αυτήν.
# Αυτή η συνάρτηση θα τροποποιήσει την καθολική μεταβλητή city
def printCity():
global city
city += ', πρωτεύουσα της Ελλάδας'
print(city)
city = "Βόλος"
print(city)
# Καθολική εμβέλεια
city= "Αθήνα"
printCity()
print(city)Αθήνα, πρωτεύουσα της Ελλάδας
Βόλος
Βόλος
Συναρτήσεις lambda¶
Οι συναρτήσεις lambda είναι μικρές ανώνυμες συναρτήσεις που μπορούν να έχουν πολλά ορίσματα αλλά μία έκφραση. Για παράδειγμα:
x = lambda a : a ** 2
x(5)25Σε αυτό το παράδειγμα ορίζεται μια συνάρτηση lambda που επιστρέφει το τετράγωνο ενός αριθμού. Στο παρακάτω παράδειγμα μια συνάρτηση lambda υπολογίζει το γινόμενο δύο αριθμών.
x = lambda a,b : a * b
x(2,3)6Άλλο παράδειγμα
onomateponymo = lambda onoma, epitheto, birth: f'Ονοματεπώνυμο: {onoma.title()} {epitheto.title()}, Έτος γέννησης: {birth}'
onomateponymo('αριστοτέλης', 'ωνάσης', 1906)'Ονοματεπώνυμο: Αριστοτέλης Ωνάσης, Έτος γέννησης: 1906'Πρακτική εφαρμογή της συνάρτησης lambda όπου χρησιμοποιείται για να φιλτραριστούν οι τιμές μιας λίστας με βάση ένα κριτήριο.
# Program to filter out only the even items from a list
nums = [1, 2, 9, 10, 18, 31, 53, 120]
nums_filtered = list(filter(lambda x: x >= 10 , nums))
print(nums_filtered)[10, 18, 31, 53, 120]
Στο παρακάτω παράδειγμα χρησιμοποιείται μια lambda συνάρτηση σε συνδυασμό με την συνάρτηση map που στόχο έχει πολλάπλασιάσει x2 τα στοιχεία μας λίστας.
# Program to double each item in a list using map()
nums = [1, 2, 9, 10, 18, 31, 53, 120]
nums_squared = list(map(lambda x: x * 2 , nums))
print(nums_squared)[2, 4, 18, 20, 36, 62, 106, 240]