Python

ΕΝΟΤΗΤΑ 22 - Magic Methods

image description

Στο σημερινό δωρεάν μάθημα Python θα μάθουμε τι είναι οι magic methods και πως να τις χρησιμοποιούμε στα προγράμματα μας.

Ένας απλός ορισμός μπορούσε να είναι ο εξής: magic methods είναι σπέσιαλ μέθοδοι που προσθέτουν έξτρα δυνατότητες στις κλάσεις. Οι magic methods προσφέρονται από την Python οπότε δεν έχετε να κατεβάσετε κάποια έξτρα βιβλιοθήκη και πάντα το όνομα τους περιέχει δύο underscores πριν από το όνομα και δύο μετά το όνομα τους.

Στο προηγούμενο μάθημα είχαμε αναπτύξει ένα πρόγραμμα για να περιγράψουμε την έννοια του employee. Το ίδιο πρόγραμμα θα χρησιμοποιήσουμε και σε αυτή την ενότητα για να μιλήσουμε για τις magic methods. Ας θυμηθούμε τον κώδικα άλλη μια φορά:

App.py


class Employee():

    def __init__(self, name, id=0):
        self.name = name
        self.id = id
        self.salary = 0
        self.age = 30


    def paySalary(self):
        print(f'A check will be sent to {self.name}')

    def companyInformation():
        print('All employees are working for the company ABC')

    def vacationCalc(self, daysTotal, daysRequested):
        remainingDays = daysTotal - daysRequested
        print("You have requested", daysRequested, "days of vacation")
        print("You have", remainingDays, "of vacation left")

    def setSalary(self, salary):
        if salary>0 & salary<2000:
            self.salary = salary
        else:
            print("This salary amount is not acceptable")

    def getSalary(self):
        print(f'Your current salary is {self.salary}')

    def employeeBirthday(self):
        self.age +=1

    def getAge(self):
        print(f'your age is {self.age}')

mike = Employee("Michail", 100)
mike.employeeBirthday()
mike.getAge()
         

Output


your age is 31
 	 

Αν στο ίδιο πρόγραμμα καλούσαμε την dir μέθοδο στο mike αντικείμενο θα λαμβάναμε πίσω σαν αποτέλεσμα μια λίστα από μεθόδους.

App.py


class Employee():

    def __init__(self, name, id=0):
        self.name = name
        self.id = id
        self.salary = 0
        self.age = 30


    def paySalary(self):
        print(f'A check will be sent to {self.name}')

    def companyInformation():
        print('All employees are working for the company ABC')

    def vacationCalc(self, daysTotal, daysRequested):
        remainingDays = daysTotal - daysRequested
        print("You have requested", daysRequested, "days of vacation")
        print("You have", remainingDays, "of vacation left")

    def setSalary(self, salary):
        if salary>0 & salary<2000:
            self.salary = salary
        else:
            print("This salary amount is not acceptable")

    def getSalary(self):
        print(f'Your current salary is {self.salary}')

    def employeeBirthday(self):
        self.age +=1

    def getAge(self):
        print(f'your age is {self.age}')

mike = Employee("Michail", 100)
print(dir(mike))
         

Output


	['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
	'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__',
	'__init__', '__init_subclass__', '__le__', '__lt__', '__module__',
	'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
	'__setattr__', '__sizeof__', '__str__', '__subclasshook__',
	'__weakref__', 'age', 'companyInformation', 'employeeBirthday',
	'getAge', 'getSalary', 'id', 'name', 'paySalary', 'salary',
	'setSalary', 'vacationCalc']
 	 

Αυτές οι magic methods ονομάζονται Dunder methods και τις κληρονομεί κάθε αντικείμενο που δημιουργούμε στην Python. Κάθε μια από αυτές τις magic methods έχει την δική του ιδιότητα και χαρακτηριστικά. Αν και δεν το είχατε καταλάβει, μέχρι τώρα έχετε ήδη χρησιμοποιήσει μια από τις magic methods – την init. Αν θέλετε να διαβάσετε περισσότερες πληροφορίες για τις magic methods μπορείτε να τις βρείτε στο επίσημο documentation της Python(https://docs.python.org/3/reference/datamodel.html?highlight=special%20methods)

Δωρεάν Μαθήματα και Σεμινάρια PYTHON

Το ερώτημα, και στην ουσία αυτό που μας ενδιαφέρει, είναι πως μπορούμε να χρησιμοποιήσουμε αυτές τις dunder methods? Βασικά σκεφτείτε λίγο πως χρησιμοποιήσατε την init για την δημιουργία αντικειμένων. Χωρίς την init μπορούσαμε να δημιουργήσουμε αντικείμενα αλλά χωρίς να ζητάμε από τον χρήστη κάποιες πληροφορίες. Όταν γράψαμε κώδικα για την init αλλάξαμε αυτή τη συμπεριφορά και αναγκάσαμε τον χρήστη να μας δίνει κάποιες αρχικές πληροφορίες πριν δημιουργήσουμε το αντικείμενο. Και με τις υπόλοιπες magic methods κάνουμε ακριβώς το ίδιο πράγμα. Δηλαδή, αν τις χρησιμοποιήσουμε όπως ακριβώς μας δίνονται ίσως να μην μας φαίνονται τόσο χρήσιμες. Όταν όμως γράψουμε κάποιο δικό μας κώδικα, κάνοντας στην ουσία override την λειτουργία της μεθόδου, τότε μπορούμε να δούμε την χρησιμότητα τους. Ίσως όλη αυτή η θεωρία να σας έχει μπερδέψει λίγο, αλλά μέσα από ένα παράδειγμα θα δείτε πόσο εύκολο είναι να χρησιμοποιήσουμε αυτές τις special methods και μάλιστα κάποιες από αυτές θα τις χρησιμοποιήσετε πολύ συχνά.

Στο πρόγραμμα μας, θέλουμε να εκτυπώσουμε πληροφορίες για το αντικείμενο, δηλαδή να δούμε μια γρήγορη περιγραφή των τιμών που έχουν ήδη ανατεθεί στο αντικείμενο κατά την δημιουργία του. Αν κοιτάξουμε το documentation της Python, και πιο συγκεκριμένα τις special methods, θα δούμε πως υπάρχει μια μέθοδο με το όνομα __str__ η οποία μας επιστρέφει σε string format το αντικείμενο. Αλλάζουμε λοιπόν τον κώδικα μας, και εκτελούμε την εντολή:

print(mike)

Εκτελώντας την εντολή print( ) σε κάποιο αντικείμενο, είναι ακριβώς η ίδια συμπεριφορά σαν να γράφουμε τον εξής κώδικα:

print(mike.__str__())

Στο παρακάτω παράδειγμα, χρησιμοποιούμε και τις δύο print( ) εντολές για να δείξουμε ότι παίρνουμε ακριβώς το ίδιο αποτέλεσμα. Επίσης, είμαστε περίεργοι να δούμε τι ακριβώς θα πάρουμε σαν αποτέλεσμα όταν το documentation αναφέρει ότι θα λάβουμε πίσω το string representation του αντικειμένου.

Δωρεάν Μαθήματα και Σεμινάρια PYTHON

App.py


class Employee():

    def __init__(self, name, id=0):
        self.name = name
        self.id = id
        self.salary = 0
        self.age = 30


    def paySalary(self):
        print(f'A check will be sent to {self.name}')

    def companyInformation():
        print('All employees are working for the company ABC')

    def vacationCalc(self, daysTotal, daysRequested):
        remainingDays = daysTotal - daysRequested
        print("You have requested", daysRequested, "days of vacation")
        print("You have", remainingDays, "of vacation left")

    def setSalary(self, salary):
        if salary>0 & salary<2000:
            self.salary = salary
        else:
            print("This salary amount is not acceptable")

    def getSalary(self):
        print(f'Your current salary is {self.salary}')

    def employeeBirthday(self):
        self.age +=1

    def getAge(self):
        print(f'your age is {self.age}')

mike = Employee("Michail", 100)
print(mike)
print(mike.__str__())

         

Output


<__main__.Employee object at 0x0000021FEAF18190>
<__main__.Employee object at 0x0000021FEAF18190>
 	 

Το αποτέλεσμα είναι να λάβουμε πίσω την διεύθυνση της μνήμης στην οποία έχει δημιουργηθεί το αντικείμενο. Πολύ σπάνια έως και καθόλου ίσως χρειαστείτε αυτή την πληροφορία. Τις περισσότερες φορές όμως δεν θα σας είναι καθόλου χρήσιμη. Για να πάρουμε λοιπόν ακριβώς αυτό που θέλουμε σαν αποτέλεσμα, μπορούμε να γράψουμε εμείς τον κώδικα που θέλουμε – όπως ακριβώς κάναμε και στην init. Αν αναρωτηθείτε γιατί χρειαζόμαστε την __str__ εάν μπορούμε να γράψουμε μια δική μας μέθοδο που κάνει ακριβώς αυτό που θέλουμε, σκεφτείτε πάλι την ευκολία που σας παράχει η __init__. Η __init__ έχει την δυνατότητα να δημιουργεί αντικείμενα κάτι που εμείς δεν γράφουμε κώδικα για αυτό. Εμείς απλά γράφουμε στην init τι απαιτούμε από τον χρήστη για να δημιουργηθεί το αντικείμενο. Κάτι αντίστοιχο είναι και με την __str__. Όταν κάνετε print( ) ένα αντικείμενο, αμέσως καλείτε η __str__. Το τι πληροφορίες θέλει να σας δείξει η __str__ αυτό πρέπει να το γράψετε εσείς, γιατί πολύ απλά δεν γνωρίζει εξ αρχής ούτε τι κλάσεις θα δημιουργήσετε αλλά ούτε και τι αντικείμενα. Οπότε, ας ορίσουμε έναν καινούργιο κώδικα για την __str__ που θα μας είναι πιο χρήσιμος.

App.py


class Employee():

    def __init__(self, name, id=0):
        self.name = name
        self.id = id
        self.salary = 0
        self.age = 30


    def paySalary(self):
        print(f'A check will be sent to {self.name}')

    def companyInformation():
        print('All employees are working for the company ABC')

    def vacationCalc(self, daysTotal, daysRequested):
        remainingDays = daysTotal - daysRequested
        print("You have requested", daysRequested, "days of vacation")
        print("You have", remainingDays, "of vacation left")

    def setSalary(self, salary):
        if salary>0 & salary<2000:
            self.salary = salary
        else:
            print("This salary amount is not acceptable")

    def getSalary(self):
        print(f'Your current salary is {self.salary}')

    def employeeBirthday(self):
        self.age +=1

    def getAge(self):
        print(f'your age is {self.age}')

    def __str__(self):
        return f'name={self.name}, age={self.age}, salary={self.salary}'

mike = Employee("Michail", 100)
print(mike)
print(mike.__str__())

         

Output


name=Michail, age=30, salary=0
name=Michail, age=30, salary=0
 	 

Αν και η __str__ καλείτε κάθε φορά που κάνουμε print( ) ένα αντικείμενο, το τι πληροφορία θα μας δείξει σαν αποτέλεσμα έχει καθοριστεί αποκλειστικά από εμάς. Με την ίδια ακριβώς λογική μπορείτε να πειραματιστείτε με τις υπόλοιπες μεθόδους αν και η __str__ είναι η πιο χρήσιμη από όλες.

ΕΙΣΗΓΗΤΗΣ

Merry Jhonson

Μιχάλης Κασάπογλου

Ο Μιχάλης Κασάπογλου, είναι ένας από τους πιο έμπειρους τεχνικούς εκπαιδευτές στον χώρο του προγραμματισμού με πάνω από 20 χρόνια εμπειρία. Έχει εργαστεί σαν IT Operations Manager, Senior Programmer, και Training Team Leader ενώ κατέχει και αρκετές πιστοποιήσεις που καλύπτουν ένα μεγάλο φάσμα τεχνολογιών στο προγραμματισμό, σε βάσεις δεδομένων και cloud. Στον ελεύθερο του χρόνο διατηρεί ένα τεχνολογικό blog στο οποίο θα βρείτε αρκετά δωρεάν μαθήματα προγραμματισμού για αρχάριους.

loader