# Ορισμός Συναρτήσεων

# Δημιουργόντας Συναρτήσεις

Αρχίζω αυτό το κεφάλαιο δίνοντας ένα παράδειγμα με το τι θα μπορούσατε να κάνετε αλλά που δεν θα 'πρεπε (οπότε μην πληκτρολογήσετε το παράδειγμα):

    a = 23
    b = -23

    if a < 0:
        a = -a

    if b < 0:
        b = -b

    if a == b:
        print "The absolute values of", a,"and",b,"are equal"
    else:
        print "The absolute values of a and b are different"

και το αποτέλεσμα:

The absolute values of 23 and 23 are equal

Φαίνεται πως το πρόγραμμα επαναλαμβάνεται. Ένα πράγμα που οι προγραμματιστές απεχθάνονται είναι η επανάληψη (για αυτό άλλωστε δεν είναι οι υπολογιστές;). Ευτυχώς η Python μας επιτρέπει να δημιουργήσουμε συναρτήσεις με τις οποίες θα αποφεύγουμε τις επαναλήψεις. Να ένα παράδειγμα του πως θα μπορούσε να είχε γραφτεί το παραπάνω πρόγραμμα:

    a = 23
    b = -23

    def my_abs(num):
        if num < 0:
            num = -num
        return num

    if my_abs(a) == my_abs(b):
        print "The absolute values of", a,"and",b,"are equal"
    else:
        print "The absolute values of a and b are different"

με αποτέλεσμα:

The absolute values of 23 and -23 are equal

Η νέα βασική έννοια που θα γνωρίσουμε εδώ είναι η δήλωση def .Η def (συντόμευση του define (όρισε)) ξεκινάει την δήλωση μιας συνάρτησης. Η def ακολουθείται από το όνομα της συνάρτησης (στο παράδειγμά μας my_abs. Μετά ακολουθεί η παράμετρος num (η num περνάει από το πρόγραμμα στην συνάρτηση όταν αυτή καλείται). Οι δηλώσεις μετά τις: εκτελούνται όποτε εκτελείται η συνάρτηση. Οι εκτέλεση των συναρτήσεων συνεχίζεται μέχρι οι εντολές στην εσοχή να τελειώσουν ή όταν συναντήσουν το return. Η δήλωση return επιστρέφει μια τιμή στο σημείο που βρίσκονταν μόλις κλήθηκε η συνάρτηση.

Παρατηρήστε πως οι τιμές a και b δεν αλλάζουν. Συναρτήσεις βέβαια χρησιμοποιούμε για να επαναλάβουμε εργασίες οι οποίες δεν επιστρέφουν τιμές. Παρακάτω ακολουθούν μερικά παραδείγματα:

    def hello():
        print "Hello"

    def area(width,height):
        return width*height

    def print_welcome(name):
        print "Welcome",name

    hello()
    hello()

    print_welcome("Fred")
    w = 4
    h = 5
    print "width =",w,"height =",h,"area =",area(w,h)

και το αποτέλεσμα:

    Hello
    Hello
    Welcome Fred
    width = 4 height = 5 area = 20

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

# Μεταβλητές Συναρτήσεων

Πολύ συχνά, όταν περιορίζουμε τον επαναλαμβανόμενο κώδικα, έχουμε μεταβλητές μέσα σ' αυτόν. Αυτές τις μεταβλητές τις μεταχειρίζεται η Python με έναν ιδιαίτερο τρόπο. Μέχρι τώρα οι μεταβλητές που συναντήσαμε ήταν γενικού τύπου. Οι συναρτήσεις έχουν έναν ειδικό τύπο μεταβλητής που λέγονται τοπικές μεταβλητές. Αυτές υφίστανται μόνο όσο τρέχει η συνάρτηση. Αν μια τοπική μεταβλητή έχει το ίδιο όνομα με μια γενικ'η τότε ή τοπική ``κρύβει'' την γενική. Ακούγεται μπερδεμένο; Ελπίζω το επόμενο (απλοποιημένο) παράδειγμα να διαλευκάνει τα πράγματα.

    a_var = 10
    b_var = 15
    e_var = 25

    def a_func(a_var):
        print "in a_func a_var = ",a_var
        b_var = 100 + a_var
        d_var = 2*a_var
        print "in a_func b_var = ",b_var
        print "in a_func d_var = ",d_var
        print "in a_func e_var = ",e_var
        return b_var + 10

    c_var = a_func(b_var)

    print "a_var = ",a_var
    print "b_var = ",b_var
    print "c_var = ",c_var
    print "d_var = ",d_var

Και το αποτέλεσμα είναι:

    in a_func a_var =  15
    in a_func b_var =  115
    in a_func d_var =  30
    in a_func e_var =  25
    a_var =  10
    b_var =  15
    c_var =  125
    d_var =
    Traceback (innermost last):
      File "separate.py", line 20, in ?
        print "d_var = ",d_var
    NameError: d_var

Στο παραπάνω παράδειγμα οι μεταβλητές a_var, b_var, και d_var ΄γινονται τοπικές μόλις χρησιμοποιηθούν μέσα στην στνάρτηση a_func. Αφού τρέξει η δήλωση return b_var + 10 παύουν να υφίστανται. Η μεταβλητή a_var είναι αυτόματα τοπική μεταβλητή αφού είναι όνομα παραμέτρου. Οι μεταβλητές b_var και d_var είναι όλες τοπικές μεταβλητές αφού εμφανίζονται στα αριστερά του συμβόλου της ισότητας ``='' μέσα στην συνάρτηση στις δηλώσεις `b_var = 100 + a_var` και `d_var = 2*a_var`.

Όπως μπορείτε να δείτε, μόλις πάψει να τρέχει η συνάρτηση οι τοπικές μεταβλητές a_var και b_var οι οποίες είχαν ``κρύψει'' τις γενικές μεταβλητές με το ίδιο όνομα έχουν εξαφανιστεί. Έπιετα η δήλωση `print "a_var = ",a_var` εμφανίζει την τιμή 10 παρά την τιμή 15 αφού η τοπική μεταβλητή που έκρυβε την γενική έχει εξαφανιστεί.

Κάτι άλλο που πρέπει να προσέξουμε είναι το σφάλμα NameError που σημειώνεται στο τέλος. Το σφάλμα εμφανίζεται επειδή η μεταβλητή d_var δεν υφίσταται πλέον (καθώς η συνάρτηση a_func έχει τελειώσει). Όλες οι τοπικές μεταβλητές διαγράφονται μόλις η συνάρτηση πάψει να τρέχει. Αν θέλετε να πάρετε μια τιμή από μια συνάρτηση πρέπει να χρησιμοποιήσετε την δήλωση return.

Το τελευταίο πράγμα που πρέπει να προσέξουμε είναι ότι η τιμή της μεταβλητής e_var δεν αλλάζει μέσα στην συνάρτηση a_func αφού δεν είναι παράμετρος της συνάρτησης και δεν εμφανίζεται στα αριστερά των ``='' μέσα στην συνάρτηση a_func. Γενικά όταν μια γενική μεταβλητή είναι προσβάσιμη μέσα στην συνάρτηση τότε είναι η γενική μεταβλητή έξω από την συνάρτηση.

Οι συναρτήσεις επιτρέπουν τοπικές μεταβλητές που υφίστανται μόνο μέσα στην συνάρτηση και μπορούν να ``κρύψου'' άλλες μεταβλητές έξω από την συνάρτηση.

# Περιήγηση Συναρτήσεων

TODO Move this section to a new chapter, Advanced Functions.

Θα κάνουμε τώρα μια μικρή περιήγηση στον κώδικα του παρακάτω προγράμματος:

    def mult(a,b):
        if b == 0:
            return 0
        rest = mult(a,b - 1)
        value = a + rest
        return value
    print "3*2 = ",mult(3,2)

Το πρόγραμμα δημιουργεί μια συνάρτηση multiplication ενός θετικού ακεραίου (που είναι βέβαια πολύ πιο αργή από την αντίστοιχη που υπάρχει εγγενής μέσα στην Python) και δείχνει την χρήση τηςnd then demonstrates this function with a use of the function.

Ερώτηση: Ποιο είναι το πρώτο πράγμα που κάνει το πρόγραμμα;

Απάντηση: Αρχικά ορίζει την συνάρτηση mult με τις γραμμές:

    def mult(a,b):
        if b == 0:
            return 0
        rest = mult(a,b - 1)
        value = a + rest
        return value

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

Ερώτηση: Τ γίνεται μετά;

Απάντηση: Τρέχει επόμενη γραμμή μετά την συνάρτηση που είναι: `print "3*2 = ",mult(3,2)`.

Ερώτηση: Και τί κάνει;

Απάντηση: Εμφανίζει `3*2 =` και τιν τιμή που επιστρέφεται απο την `mult(3,2)`

Ερώτηση: Και τι επιστρέφει η `mult(3,2)`;

Απάντηση: Πρέπει να κάνουμε μια περιήγηση στην συνάρτηση mult για να το μάθουμε.

Ερώτηση: Και τι συμβαίνει μετά;

Απάντηση: Η μεταβλητή a παίρνει την τιμή 3 και η μεταβλητή b παίρνει την τιμή 2.

Ερώτηση: Και έπειτα;

Απάντηση: Τρέχει η γραμμή`if b == 0:` . εφ' όσον το b έχει τιμή 2 είναι ψευδές και έτσι η γραμμή return 0 υπερσκελίζεται.

Ερώτηση: Και μετά;

Απάντηση: Τρέχει η γραμμή `rest = mult(a,b - 1)`. Η γραμμή αυτή ορίζει στην τοπική μεταβλητή rest την τιμή της `mult(a,b - 1)`. Η τιμή του a είναι 3 και η τιμή του b είναι 3 οπότε η κλήση της συνάρτησης είναι `mult(3,1)`

Ερώτηση: Ποια είναι λοιπόν η τιμή του `mult(3,1)` ?

Απάντηση: Θα πρέπει να τρέξουμε την συνάρτηση mult με τις παραμέτρους 3 και 1.

Ερώτηση: Τι συμβαίνει μετά;

Απάντηση: Οι τοπικές μεταβλητές στην νέα εκτέλεση της συνάρτησης ορίζονται έτσι ώστε το a να έχει τιμή 3 και το b τιμή 1. Εφ' όσον είναι τοπικές μεταβλητές δεν επηρεάζουν τις προηγούμενες τιμές των a και b.

Ερώτηση: Και ύστερα;

Απάντηση: Αφού το b έχει τιμή 1 η δήλωση if είναι ψευδής οπότε η επόμενη γραμμή που τρέχει είναι η `rest = mult(a,b - 1)`.

Ερώτηση: Τι κάνει αυτή η γραμμή;

Απάντηση: Αυτή η γραμμή θα δώσει την τιμή του mult(3,0) στο rest.

Ερώτηση: Τι είναι λοιπόν αυτή η τιμή;

Απάντηση: Θα πρέπει να τρέξουμε άλλη μια φορά την συνάρτηση για να μάθουμε. Αυτήν την φορά το a έχει τιμή 3 και το b έχει τιμή 0.

Ερώτηση: Και τι συμβαίνει μετά;

Απάντηση: Η πρώτη γραμμή που τρέχει μέσα στην συνάρτηση είναι η `if b == 0:`. Το b έχει τιμή 0 οπότε η επόμενη γραμμή που θα τρέξει είναι `return 0`

Ερώτηση: Και τι κάνει η γραμμή`return 0` ;

Απάντηση: Επιστρέφει την τιμή 0 από την συνάρτηση

Ερώτηση: Και λοιπόν;

Απάντηση: Τώρα λοιπόν ξέρουμε ότι η mult(3,0) έχει τιμή 0. Καταλαβαίνουμε τι ήταν αυτό που έκανε η γραμμή `rest = mult(a,b - 1)` όταν τρέχαμε την συνάρτηση mult με παραμέτρους 3 και 0. Τελειώσαμε με την εκτέλεση της mult(3,0) και τώρα είμαστε πίσω στην mult(3,1). Η μεταβλητή rest παίρνει την τιμή 0.

Ερώτηση: Ποιά γραμμή εκτελείται ύστερα;

Απάντηση: Εκτελείται η γραμμή `value = a + rest`. Αυτήν την φορά είναι `a=3` και `rest=0` άρα `value=3`.

Ερώτηση: Τι γίνεται μετά;

Απάντηση: Τρέχει η γραμμή`return value`. επιστρέφει 3 από την συνάρτηση. Επίσης τερματίζει την εκτέλεση της συνάρτησης mult(3,1). Αφού κληθεί η return πάμε πίσω για να τρέξουμε την mult(3,2).

Ερώτηση: Που είχαμε μείνει με την mult(3,2);

Απάντηση: Είχαμε τις μεταβλητές `a=3` και `b=2` και εξετάζαμε την γραμμή`rest = mult(a,b - 1)`.

Ερώτηση: Και τώρα τι γίνεται;

Απάντηση: Η μεταβλητή rest παίρνει τιμή 3. Η επόμενη γραμμή `value = a + rest` ορίζει την value σε 3+3 ή 6.

Ερώτηση: Και μετά;

Απάντηση: Η επόμενη γραμμή εκτελείται και επιστρέφει 6 από την συνάρτηση. Είμαστε πίσω στον ατρέξουμε την γραμμή `print "3*2 = ",mult(3,2)` που θα εμφανίζει τώρα 6.

Ερώτηση: Τι συμβαίνει γενικά;

Απάντηση: Χρησιμοποιήσαμε δύο αξιώματα για να υπολογίσουμε το multipule των δύο αριθμών. Το πρώτο είναι ότι κάθε αριθμός επί 0 είναι 0 (x * 0 = 0). Το δεύτερο είναι ότι το γινόμενο δύο αριθμών είναι ίσο με το άθροισμα του ενός συν το γινόμενο του ενός επί τον άλλο μικρότερο κατά 1 (x * y = x + x * (y - 1)). Αυτό λοιπόν που συνέβη είναι ότι το 3*2 αρχικά μετατράπηκε σε 3 + 3*1. Μετά το 3*1 σε 3 + 3*0. Τέλος, ξέρουμε ότι αριθμός επί μηδέν ισούται με μηδέν άρα 3*0 is 0. Έπειτα υπολογίζουμε ότι 3 + 3*0 δηλαδή 3 + 0 ή 3. Τώρα που ξέρουμε τι είναι το 3*1 iυπολογίσουμε 3 + 3*1 ίσον 3 + 3 ίσον 6.

Σχηματικά είναι ως εξής:

    3*2
    3 + 3*1
    3 + 3 + 3*0
    3 + 3 + 0
    3 + 3
    6

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

# Παραδείγματα

factorial.py

    #defines a function that calculates the factorial

    def factorial(n):
        if n <= 1:
            return 1
        return n*factorial(n-1)

    print "2! = ",factorial(2)
    print "3! = ",factorial(3)
    print "4! = ",factorial(4)
    print "5! = ",factorial(5)

Αποτέλεσμα:

    2! =  2
    3! =  6
    4! =  24
    5! =  120

temperature2.py

    #converts temperature to fahrenheit or celsius

    def print_options():
        print "Options:"
        print " 'p' print options"
        print " 'c' convert from celsius"
        print " 'f' convert from fahrenheit"
        print " 'q' quit the program"

    def celsius_to_fahrenheit(c_temp):
        return 9.0/5.0*c_temp+32

    def fahrenheit_to_celsius(f_temp):
        return (f_temp - 32.0)*5.0/9.0

    choice = "p"
    while choice != "q":
        if choice == "c":
            temp = input("Celsius temperature:")
            print "Fahrenheit:",celsius_to_fahrenheit(temp)
        elif choice == "f":
            temp = input("Fahrenheit temperature:")
            print "Celsius:",fahrenheit_to_celsius(temp)
        elif choice != "q":
            print_options()
        choice = raw_input("option:")

Δοκιμή:

    > python temperature2.py
    Options:
     'p' print options
     'c' convert from celsius
     'f' convert from fahrenheit
     'q' quit the program
    option:c
    Celsius temperature:30
    Fahrenheit: 86.0
    option:f
    Fahrenheit temperature:60
    Celsius: 15.5555555556
    option:q

area2.py

    #By Amos Satterlee
    print
    def hello():
        print 'Hello!'

    def area(width,height):
        return width*height

    def print_welcome(name):
        print 'Welcome,',name

    name = raw_input('Your Name: ')
    hello(),
    print_welcome(name)
    print
    print 'To find the area of a rectangle,'
    print 'Enter the width and height below.'
    print
    w = input('Width:  ')
    while w <= 0:
        print 'Must be a positive number'
        w = input('Width:  ')
    h = input('Height: ')
    while h <= 0:
        print 'Must be a positive number'
        h = input('Height: ')
    print 'Width =',w,' Height =',h,' so Area =',area(w,h)

Δοκιμή:

    Your Name: Josh
    Hello!
    Welcome, Josh

    To find the area of a rectangle,
    Enter the width and height below.

    Width:  -4
    Must be a positive number
    Width:  4
    Height: 3
    Width = 4  Height = 3  so Area = 12

# Ασκήσεις

Ξαναγράψτε το πρόγραμμα area.py που είδαμε στο 3.2 με ξεχωριστές συναρτήσεις για τετράγωνο, ορθογώνιο παραλληλόγραμμο και κύκλο. (3.14 * ακτίνα**2). Το πρόγραμμα θα πρέπει να έχει περιβάλλον διασύνδεση με μενού.