Κλ

Κλάσεις σε Python

49 ασκήσεις

Σχετικά με την έννοια Κλάσεις

Οι Classes συνδυάζουν δεδομένα με συμπεριφορά. Οι κλάσεις χρησιμοποιούνται για να δημιουργούν αντίγραφα ή instances ομαδοποιημένων δεδομένων και συμπεριφοράς, γνωστά κοινώς ως objects. Τα αντικείμενα μπορούν να αναπαριστούν οντότητες του πραγματικού κόσμου (όπως αυτοκίνητα ή γάτες) ή πιο αφηρημένες έννοιες (όπως ακέραιους αριθμούς, οχήματα ή θηλαστικά). Οι κλάσεις είναι αναπόσπαστο μέρος μιας προσέγγισης αντικειμενοστρεφούς προγραμματισμού (OOP), η οποία ζητά από τον προγραμματιστή να σκεφτεί το πρόβλημα ως ένα ή περισσότερα αντικείμενα που αλληλεπιδρούν μεταξύ τους, διατηρούν κατάσταση και δρουν πάνω στα δεδομένα.

Κλάσεις

Οι κλάσεις είναι οι ορισμοί νέων τύπων αντικειμένων, από τους οποίους δημιουργούνται νέα instances αντικειμένων. Συχνά ομαδοποιούν δεδομένα (γνωστά ως fields, attributes, properties, data members ή variables) με κώδικα ή συναρτήσεις (γνωστές ως methods) που επεξεργάζονται αυτά τα δεδομένα. Υπό αυτή την έννοια, μια κλάση είναι ένα σχέδιο ή ένα σύνολο οδηγιών από το οποίο μπορούν να κατασκευαστούν και να χρησιμοποιηθούν πολλά αντικείμενα παρόμοιου τύπου. Ένα σύνθετο πρόγραμμα μπορεί να έχει πολλές κλάσεις, καθεμία από τις οποίες κατασκευάζει πολλές διαφορετικές εκδοχές αντικειμένων. Η διαδικασία κατασκευής και προσαρμογής ενός αντικειμένου από μια κλάση είναι γνωστή ως instantiation (ή δημιουργία στιγμιότυπου της κλάσης).

Ο ορισμός μιας κλάσης σε Python είναι απλός:

class MyClass:
    # Class body goes here

Χαρακτηριστικά κλάσης

Τα πεδία κλάσης (γνωστά και ως ιδιότητες, χαρακτηριστικά, μέλη δεδομένων ή μεταβλητές) μπορούν να προστεθούν στο σώμα της κλάσης.

class MyClass:
    number = 5
    string = "Hello!"

Ένα στιγμιότυπο (αντικείμενο) της MyClass μπορεί να δημιουργηθεί και να δεθεί με ένα όνομα:

>>> new_object = MyClass()

# Class is instantiated and resulting object is bound to the "new_object" name (variable).
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.MyClass at 0x15adc55b0>

Τα Class attributes είναι κοινά σε όλα τα αντικείμενα (ή στιγμιότυπα) που δημιουργούνται από μια κλάση και μπορούν να προσπελαστούν μέσω της dot notation, δηλαδή μιας . που τοποθετείται μετά το όνομα του αντικειμένου και πριν από το όνομα του χαρακτηριστικού:

>>> new_object = MyClass()

# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5

# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'

# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = MyClass()

>>> second_new_object
<__main__.MyClass at 0x15ad99970>

# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True

Τα χαρακτηριστικά κλάσης ορίζονται στο σώμα της ίδιας της κλάσης, πριν από οποιεσδήποτε άλλες μεθόδους. Ανήκουν στην κλάση, γεγονός που τους επιτρέπει να μοιράζονται σε όλα τα στιγμιότυπα. Επειδή αυτά τα χαρακτηριστικά μοιράζονται από όλα τα στιγμιότυπα της κλάσης, η τιμή τους μπορεί να προσπελαστεί και να τροποποιηθεί απευθείας από την κλάση. Η αλλαγή της τιμής των χαρακτηριστικών κλάσης αλλάζει την τιμή για όλα τα αντικείμενα που έχουν δημιουργηθεί από την κλάση:

>>> obj_one = MyClass()
>>> obj_two = MyClass()

# Accessing a class attribute from an object.
>>> obj_two.number
5

# Accessing the class attribute from the class itself.
>>> MyClass.number
5

# Modifying the value of the "number" class attribute.
>>> MyClass.number = 27

# Modifying the "number" class attribute changes the "number" attribute for all objects.
>>> obj_one.number
27

>>> obj_two.number
27

Το να έχεις ένα σωρό αντικείμενα με συγχρονισμένα δεδομένα όλη την ώρα δεν είναι ιδιαίτερα χρήσιμο. Ευτυχώς, τα αντικείμενα που δημιουργούνται από μια κλάση μπορούν να προσαρμοστούν με τα δικά τους instance attributes (ή ιδιότητες, μεταβλητές ή πεδία στιγμιότυπου). Όπως υποδηλώνει το όνομά τους, τα χαρακτηριστικά στιγμιότυπου είναι μοναδικά για κάθε αντικείμενο και μπορούν να τροποποιηθούν ανεξάρτητα.

Προσαρμογή της δημιουργίας αντικειμένων με __init__()

Η ειδική "dunder method" (συντομογραφία του "double underscore method") __init__() χρησιμοποιείται για την προσαρμογή στιγμιότυπων κλάσης και μπορεί να χρησιμοποιηθεί για την αρχικοποίηση χαρακτηριστικών ή ιδιοτήτων στιγμιότυπου για αντικείμενα. Λόγω του ρόλου του στην αρχικοποίηση χαρακτηριστικών στιγμιότυπου, το __init__() αναφέρεται επίσης ως class constructor ή initializer. Το __init__() δέχεται μία υποχρεωτική παράμετρο που ονομάζεται self, η οποία αναφέρεται στο νεοδημιουργημένο αντικείμενο. Δεδομένα για χαρακτηριστικά ή ιδιότητες στιγμιότυπου μπορούν στη συνέχεια να περαστούν ως ορίσματα του __init__(), μετά την παράμετρο self.

Παρακάτω, η MyClass έχει τώρα χαρακτηριστικά στιγμιότυπου που ονομάζονται location_x και location_y. Όπως βλέπεις, τα δύο χαρακτηριστικά έχουν ανατεθεί στην πρώτη και δεύτερη θέση του ορίσματος location (μια πλειάδα) που έχει περαστεί στο __init__(). Τα χαρακτηριστικά location_x και location_y για ένα στιγμιότυπο κλάσης θα αρχικοποιούνται τώρα όταν δημιουργείς το στιγμιότυπο της κλάσης και παράγεται ένα αντικείμενο:

class MyClass:
    # These are class attributes, variables, or fields.
    number = 5
    string = "Hello!"

    # This is the class "constructor", with a "location" parameter that is a tuple.
    def __init__(self, location):

        # This is an instance or object property, attribute, or variable.
        # Note that we are unpacking the tuple argument into two separate instance variables.
        self.location_x = location[0]
        self.location_y = location[1]

# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = MyClass((1, 2))

# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = MyClass((-8, -9))

# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1

>>> new_object_two.location_x
-8

Σημείωσε ότι χρειάζεται να περάσεις μόνο ένα όρισμα κατά την αρχικοποίηση της MyClass παραπάνω: η Python αναλαμβάνει να περάσει το self όταν καλείται η κλάση.

Advanced

Ένας άλλος τρόπος για να δημιουργήσεις μια μεταβλητή στιγμιότυπου είναι απλώς να προσπελάσεις μια μεταβλητή κλάσης μέσω ενός αντικειμένου και να την αλλάξεις σε κάτι άλλο:

>>> obj_one = MyClass()
>>> obj_two = MyClass()
>>> MyClass.string
'Hello!'

>>> obj_two.string = "Hi!"
>>> obj_two.string
'Hi!'

>>> obj_one.string
'Hello!'

Τώρα, δες τι συμβαίνει όταν αλλάζει η μεταβλητή κλάσης:

>>> MyClass.string = "World!"
>>> obj_two.string

# obj_two.string has not changed
'Hi!'

>>> obj_one.string

# obj_one.string changed
'World!'

Το χαρακτηριστικό string είναι τώρα μια μεταβλητή στιγμιότυπου στην περίπτωση του obj_two, αλλά παραμένει μια μεταβλητή κλάσης στο obj_one.

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

class Demo:
    new_var = 3

    def add_two(self):
        self.new_var += 2

Τη στιγμή που καλείται το <object>.add_two() και διαβάζεται το self.new_var += 2, το new_var αλλάζει από μεταβλητή κλάσης σε μεταβλητή στιγμιότυπου με το ίδιο όνομα.

Αυτό μπορεί να φανεί χρήσιμο κατά την αρχικοποίηση όταν όλα τα στιγμιότυπα μιας κλάσης χρειάζεται να ξεκινούν με την ίδια τιμή για κάποιο ή κάποια χαρακτηριστικά. Ωστόσο, η μεταβλητή στιγμιότυπου τότε επισκιάζει τη μεταβλητή κλάσης, καθιστώντας τη μεταβλητή κλάσης μη προσβάσιμη από το στιγμιότυπο όπου επισκιάζεται. Δεδομένης αυτής της κατάστασης, μπορεί να είναι ασφαλέστερο και σαφέστερο να ορίζεις τα χαρακτηριστικά στιγμιότυπου από τη μέθοδο __init__() ως self.<attribute>.

Μέθοδοι

Μια method είναι μια function που είναι δεσμευμένη είτε στην ίδια την κλάση (γνωστή ως μέθοδος κλάσης, η οποία θα συζητηθεί σε βάθος σε επόμενη άσκηση) είτε σε ένα στιγμιότυπο της κλάσης (αντικείμενο). Οι μέθοδοι που λειτουργούν πάνω σε ένα αντικείμενο ή στιγμιότυπο πρέπει να ορίζονται με το self ως πρώτη παράμετρο. Στη συνέχεια μπορείς να ορίσεις τις υπόλοιπες παραμέτρους όπως θα έκανες για μια "κανονική" ή μη δεσμευμένη συνάρτηση. Οι μέθοδοι που λειτουργούν πάνω σε μια κλάση πρέπει να ορίζονται με τον διακοσμητή @classmethod και (κατά σύμβαση) με το cls ως πρώτη παράμετρο. Οι μέθοδοι κλάσης καλούνται απευθείας πάνω σε μια κλάση χωρίς να δημιουργήσεις πρώτα αντικείμενο από την κλάση.

class MyClass:
    number = 5
    string = "Hello!"

    # Class constructor.
    def __init__(self, location):

        # Instance properties
        self.location_x = location[0]
        self.location_y = location[1]

    # Class method. Uses the @classmethod decorator, and cls as the first parameter.
    # Can be called without first making an instance of the class.
    @classmethod
    def change_string(cls, new_string):
        #Class attributes are referred to with cls.
        cls.string = new_string
        return cls.string

    # Instance method.  Note "self" as first parameter.
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

Όπως και η πρόσβαση σε χαρακτηριστικά, η κλήση μιας μεθόδου είναι τόσο απλή όσο το να βάλεις μια . μετά το όνομα του αντικειμένου και πριν από το όνομα της μεθόδου. Η μέθοδος που καλείται δε χρειάζεται αντίγραφο του αντικειμένου ως πρώτη παράμετρο: η Python συμπληρώνει το self αυτόματα:

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

# Make a new test_object with location (3,7)
>>> test_object = MyClass((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)

# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)

Τα χαρακτηριστικά κλάσης μπορούν να προσπελαστούν μέσα από μεθόδους στιγμιότυπου με τον ίδιο τρόπο που προσπελαύνονται και έξω από την κλάση:

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    # Alter instance variable location_x and location_y
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return self.location_x, self.location_y

    # Alter class variable number for all instances from within an instance.
    def increment_number(self):
        # Increment the 'number' class variable by 1.
        MyClass.number += 1


>>> test_object_one = MyClass((0,0))
>>> test_object_one.number
5

>>> test_object_two = MyClass((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6

Προσωρινή υλοποίηση ή σκελετός με pass

Σε προηγούμενες ασκήσεις εννοιών και σε σκελετούς ασκήσεων εξάσκησης, θα έχεις δει τη λέξη-κλειδί pass να χρησιμοποιείται μέσα στο σώμα συναρτήσεων στη θέση πραγματικού κώδικα.

Η λέξη-κλειδί pass είναι ένα συντακτικά έγκυρο σύμβολο θέσης, καθώς εμποδίζει την Python να πετάξει συντακτικό σφάλμα για έναν κενό ορισμό συνάρτησης ή κλάσης. Ουσιαστικά, είναι ένας τρόπος να πεις στον διερμηνευτή της Python: "Μην ανησυχείς! Θα βάλω κώδικα εδώ κάποια στιγμή, απλώς δεν το έχω κάνει ακόμα."

class MyClass:
    number = 5
    string = "Hello!"

    def __init__(self, location):
        self.location_x = location[0]
        self.location_y = location[1]

    # Alter instance variable location_x and location_y.
    def change_location(self, amount):
        self.location_x += amount
        self.location_y += amount
        return  self.location_x, self.location_y

    # Alter class variable number for all instances.
    def increment_number(self):
        # Increment the 'number' class variable by 1.
        MyClass.number += 1

    # This will compile and run without error, but has no current functionality.
    def pending_functionality(self):
       # Stubbing or place-holding the body of this method.
       pass
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα

Μάθε την έννοια Κλάσεις

Η εξάσκηση είναι κλειδωμένη

Ξεκλείδωσε 6 ακόμη ασκήσεις για να εξασκηθείς στην έννοια Κλάσεις