Συναρτήσεις - ειδικότερα θέματα

Ορίσματα με προεπιλεγμένες τιμές (default parameter values)

Παράδειγμα. [Πηγή: Σημειώσεις Μ. Πλεξουσάκη.] Ας γράψουμε τώρα μια συνάρτηση η οποία επιστρέφει σε μια ακολουθία χαρακτήρων την ημερομηνία στη μορφή day-month-year ή, εναλλακτικά, στη μορφή month-day-year, όπως συνηθίζεται σε κάποιες χώρες του κόσμου. Είναι λογικό να θεωρήσουμε ότι η λίστα των τυπικών ορισμάτων θα περιλαμβάνει τα day, month, year, καθώς και ένα τέταρτο όρισμα, ας το πούμε america το οποίο ορίζει τον τρόπο σχηματισμού της ακολουθίας χαρακτήρων. Αν η συνάρτηση κληθεί με τιμή του ορίσματος america ίσο με True τότε θα σχηματίσει την ακολουθία χαρακτήρων month-day-year, διαφορετικά την day-month-year. (Στην Αμερική χρησιμοποιείται ο τρόπος γραφής ημερομηνίας month-day-year.)


def dateString(day, month, year, america):
    if america:
	return str(month) + '-' + str(day) + '-' + str(year)
    else:
        return str(day) + '-' + str(month) + '-' + str(year)

Η συνηθισμένη μορφή για την ημερομηνία (για εμάς) είναι η day-month-year. Η python μας δίνει τη δυνατότητα να απλοποιήσουμε την κλήση της συνάρτησης για αυτή την περίπτωση χρησιμοποιώντας προεπιλεγμένες τιμές για ένα ή περισσότερα ορίσματα (default parameter values).


def dateString(day, month, year, america=False):
    if america:
	return str(month) + '-' + str(day) + '-' + str(year)
    else:
        return str(day) + '-' + str(month) + '-' + str(year)

Η απουσία του ορίσματος america είναι ισοδύναμη με την κλήση της συνάρτησης με το όρισμα america=False. Έτσι, όλες οι παρακάτω κλήσεις της dateString είναι επιτρεπτές:


dateString(12, 10, 2016)
dateString(12, 10, 2016, True)
dateString(12, 10, 2016, america=True)

Η πρώτη θα επιστρέψει την ακολουθία χαρακτήρων '12-10-2016' ενώ οι επόμενες δύο την ακολουθία χαρακτήρων '10-12-2016'.

Παρατήρηση....

Keyword arguments (ορίσματα-δεσμευμένες λέξεις)

Εισαγωγή. [Πηγή: Σημειώσεις Μ. Πλεξουσάκη.] Σε όλα τα παραδείγματα συναρτήσεων τα οποία έχουμε δει, η αντιστοίχιση των τυπικών ορισμάτων κατά την κλήση της συνάρτησης γίνεται σύμφωνα με τη θέση τους (η μέθοδος αυτή αντιστοίχισης λέγεται θεσιακή). Η Python επιτρέπει και έναν δεύτερο τρόπο αντιστοίχισης τυπικών ορισμάτων και ορισμάτων χρησιμοποιώντας το όνομα του τυπικού ορίσματος. Θα μπορούσαμε να γράψουμε dateString(day=12, month=10, year=2016, america=True). Σε αυτή την περίπτωση μπορούμε να δώσουμε τιμές στα τυπικά ορίσματα με οποιαδήποτε σειρά θέλουμε


dateString(year=2016, month=10, day=12, america=True)
dateString(day=12, year=2016, month=10, america=True)
dateString(america=True, day=12, year=2016, month=10)

Δείτε όμως ότι η κλήση dateString(12, month=10, 2016, False) παράγει ένα μήνυμα σφάλματος:


>>> dateString(12, month=10, 2016, False)
SyntaxError: positional argument follows keyword argument

ενώ η κλήση dateString(12, 10, 2016, america=False) επιστρέφει την ημερομηνία χωρίς μήνυμα σφάλματος:


>>> dateString(12, 10, 2016, america=False)
'12-10-2016'

Παρατήρηση. Εφόσον δώσουμε τιμή σε όρισμα συνάρτησης χρησιμοποιώντας το όνομά του (keyword argument) δεν μπορούμε να δώσουμε τιμή σε επόμενο όρισμα με τη μέθοδο αντιστοίχισης κατά τη θέση του ορίσματος.

Παράδειγμα. Γράψτε μία συνάρτηση στην οποία θα δίνεται όνομα και επίθετο και θα μπορεί να το τυπώνει στη μορφή Όνομα Επίθετο είτε Επίθετο, Όνομα.


def organizeName(firstName, lastName, reverse = False):

    if reverse == True:
        s = lastName + ', ' + firstName
    else:
        s = firstName + ' ' + lastName

    return s

# - - - Main program - - -

fName = input("Give your first name: ")
lName = input("Give your last name: ")

# call function with default argument
s = organizeName(fName,lName)
print(s)

# call using keyword arguments
s = organizeName(reverse=True, firstName='Nick', lastName='Papadakis')
print(s)

Χρησιμοποιήσατε ένα προεπιλεγμένο όρισμα (reverse). Καλέσαμε τη συνάρτηση αφήνοντας την προεπιλεγμένη τιμή στο προεπιλεγμένο όρισμα. Επίσης, καλέσαμε τη συνάρτηση χρησιμοποιώντας keyword arguments με τη σειρά προτίμησής μας (και όχι με τη σειρά που εμφανίζονται τα ορίσματα στον ορισμό της συνάρτησης).

Ερώτηση. Είναι αποδεκτή η κλήση της παραπάνω συνάρτησης ως s = organizeName(reverse=True,'Nick','Papadakis');

Αναδρομή

Παραγοντικό, Το παραγοντικό ακεραίου $n$ ορίζεται ως $n! = n\cdot (n-1) \cdot \ldots \cdot 1$.


def factorialIter(n):
    """Assumes n is int > 0
    returns n!"""
    nfact = 1
    while n > 1:
        nfact = n*nfact
        n -= 1
    return nfact

Είναι όμως συχνά πιο απλό να σκεφτούμε ότι το παραγοντικό $(n+1)!$ μπορεί να υπολογιστεί άμεσα αν είναι γνωστό το $n!$, αφού $(n+1)! = (n+1)\cdot n!$. Αυτό ορίζει μία αναδρομική περίπτωση (το $n!$ υπολογίζεται αν γνωρίζουμε το $(n-1)!$, κλπ) και μας επιτρέπει να αναπτύξουμε μία επαγωγική μέθοδο. Η διαδικασία τερματίζεται αν γνωρίζουμε ότι $1!=1$ (βασική περίπτωση).

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


def factorialRecur(n):
    if n == 1:
        return n
    else:
        return = n*factorialRecur(n-1)

Ακολουθία Fibonacci. Αν ο πληθυσμός (κάποιου βιολογικού είδους) παρασταθεί με $F_i$ σε κάθε χρονιά $i$, τότε έχει υποστηριχθεί ότι η αύξηση του πληθυσμού κάποιων ζώων μπορεί να παρασταθεί από την ακολουθία $F_i = F_{i-1} + F_{i-2}$, δηλαδή εξαρτάται από τον πληθυσμό τα δύο προηγούμενα χρόνια. Αυτή είναι μία αναδρομική σχέση. Για την εφαρμογή ενός υπολογισμού χρειαζόμαστε μία βασική περίπτωση: θα υποθέσουμε ότι αρχικά είχαμε μόνο ένα υποκείμενο του βιολογικού είδους, δηλαδή $F_0 = 1, F_1 = 1$.


def fib(n):
    if n == 0 or n == 1:
        return 1
    else:
        return = fib(n-1) + fib(n-2)

Παράδειγμα. Θα θέλαμε να μετρήσουμε πόσες κλήσεις γίνονται στη συνάρτηση fib μέσω της αναδρομικής κλήσης της.


def fib(n):
    global numFibCalls
    numFibCalls += 1
    if n == 0 or n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

def testFib(n):
    global numFibCalls
    numFibCalls = 0
    print("Fibonacci number for",n,' = ',fib(n))
    print("Function fib was called",numFibCalls,"times")

Γραφική επανάληψη

Program form
Σχήμα. Η γενική μορφή προγράμματος με συνάρτηση και κλήση της από το κύριο πρόγραμμα.

Μελέτη

Βιβλιογραφία

  1. Δημήτριος Καρολίδης, Μαθαίνετε εύκολα python (Εκδόσεις Καρολίδη, 2016).
  2. Κ. Μαγκούτης, Χ. Νικολάου, Εισαγωγή στον αντικειμενοστραφή προγραμματισμό με Python, (Αποθετήριο "Κάλλιπος", 2016) - Κεφάλαιο 4. Συναρτήσεις και εκτέλεση υπό συνθήκη.
  3. J.V. Guttag, Υπολογισμοί και προγραμματισμός με την python, Κεφάλαιο 4.