Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισμός

...ασύγχρονα μαθήματα python

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισμός

Δημοσίευσηαπό malos » 09 Οκτ 2009, 22:56

9 Οκτωβρίου 2009 ώρα 22:53 !
Ξέρω από κλάσεις ! Yeaaaaaaah! :thumbup:

Ευχαριστώ σας !

(Βάλτε μου άσκηση να την ξευτιλίσω !!! :D )
Επεξεργαστής: AMD Ryzen 9 5900x
Μνήμη Gskill 16gb (2X8gb), 3200 mh, CL 14
Μητρική: Asrock X570 phantom gaming X
Τροφοδοτικό: Corsair 850 platinum
Δίσκος: SSD Corsair MP600 (1 TB)
Άβαταρ μέλους
malos
saintTUX
saintTUX
 
Δημοσιεύσεις: 1222
Εγγραφή: 02 Νοέμ 2008, 12:00
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό midkin » 24 Ιουν 2014, 22:06

Από το βιβλίο:

Κώδικας: Επιλογή όλων
class Person:
    def sayHi(self):
        print('Hello, how are you?')
           
p = Person()
p.sayHi()
   
# Αυτό το σύντομο παράδειγμα θα μπορούσε να γραφτεί και ως
Person().sayHi()

Καταλαβαίνω απόλυτα το:

Κώδικας: Επιλογή όλων
def sayHi():
    print('Hello, how are you?')
sayHi()


Ωστόσο, έχω μία δυσκολία να καταλάβω το πρώτο παράδειγμα...
Γιατί πρέπει να χρησιμοποιώ το 'self'; Λέει το 'self' στην python ότι μπορώ να χρησιμοποιώ την συνάρτηση μέσω της κλάσης; Με άλλα λόγια η 'self' δίνει τα δικαιώματα της συνάρτησης στην κλάση;

Γιατί π.χ. δεν λειτουργεί η ακόλουθη σύνταξη;

Κώδικας: Επιλογή όλων
class Person:
    def sayHi():
        print('Hello, how are you?')
           
p = Person()
p.sayHi()
   
# Αυτό το σύντομο παράδειγμα θα μπορούσε να γραφτεί και ως
Person().sayHi()
Γνώσεις ⇛ Linux: Χαμηλό ┃ Προγραμματισμός: Χαμηλό ┃ Αγγλικά: Πολύ Καλά
Λειτουργικό: Laptop Lenovo G505s με Windows 8.1 / Ubuntu 14.10 & Mac OS X 10.10 μέσω VirtualBox
Προδιαγραφές ⇛ AMD A8 τετραπύρηνος │ 8 GB RAM |
Άβαταρ μέλους
midkin
babeTUX
babeTUX
 
Δημοσιεύσεις: 44
Εγγραφή: 05 Σεπ 2009, 21:14
Τοποθεσία: Κομοτηνή
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό lucinos » 24 Ιουν 2014, 22:30

πρώτη σημαντική λεπτομέρεια. Η λέξη self δεν έχει συντακτικό νόημα στην Python (δεν είναι μία από τις 33 λέξεις κλειδιά). Μπορείς να χρησιμοποιήσεις όποια λέξη θες, αλλά συνηθίζεται να χρησιμοποιείται η self ώστε να είναι αναγνωρίσιμος ο σκοπός.

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

Spoiler: show
Γνώσεις → Linux: Μέτριος ┃ Προγραμματισμός: Μέτριος ┃ Αγγλικά: Μέτριος
Λειτουργικό → Ubuntu 11.04 natty 64-bit (el_GR.UTF-8)
Προδιαγραφές → CPU: 4x Intel Core i5 CPU 750 2.67GHz ‖ RAM 3953 MiB ‖ ASRock P55DE3
Κάρτες γραφικών: nVidia G92 [GeForce GTS 250] ⎨10de:0615⎬ (rev a2)
Δίκτυα: eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller ⎨10ec:8168⎬ (rev 03)
Άβαταρ μέλους
lucinos
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 828
Εγγραφή: 12 Δεκ 2010, 22:04
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό midkin » 24 Ιουν 2014, 22:53

Εντυπωσιακό το βιντεάκι. Ωστόσο, οι κλάσεις υπάρχουν σαν μάθημα και θα ήθελα να τις κατανοήσω... Είμαι αρκετά αρχάριος για να καταλάβω αν και πότε θα μου χρησιμεύσουν (πολύ) αργότερα αλλά ακόμη δεν έχω καταλάβει το 'self' ή το ότι βάζω εκέι μέσα...
Γιατί δεν συντάσσεται όπως έγραψα εγώ στο παράδειγμα και χρειάζεται η μεταβλητή στις παρενθέσεις; Με ποια λογική λειτουργεί η 'self';
Γνώσεις ⇛ Linux: Χαμηλό ┃ Προγραμματισμός: Χαμηλό ┃ Αγγλικά: Πολύ Καλά
Λειτουργικό: Laptop Lenovo G505s με Windows 8.1 / Ubuntu 14.10 & Mac OS X 10.10 μέσω VirtualBox
Προδιαγραφές ⇛ AMD A8 τετραπύρηνος │ 8 GB RAM |
Άβαταρ μέλους
midkin
babeTUX
babeTUX
 
Δημοσιεύσεις: 44
Εγγραφή: 05 Σεπ 2009, 21:14
Τοποθεσία: Κομοτηνή
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό lucinos » 24 Ιουν 2014, 23:06

σού είπα, ως πρώτο όρισμα βάζουμε πάντα self (μπορούμε να χρησιμοποιήσουμε όποια λέξη θέλουμε αλλά χρησιμοποιούμε το self για να φαίνεται καλύτερα) και πάντα αυτό το όρισμα σημαίνει το ίδιο το αντικείμενο. Εδώ το "def" δεν ορίζει «συναρτήσεις» αλλά ορίζει «μεθόδους» (οι μέθοδοι δρουν πάνω σε αντικείμενα)

Στην πράξη κλάσεις χρησιμοποιείς αρκετά συχνά, αλλά ποτέ δεν θα χρειαστείς να φτιάξεις μία ή να δεις τον κώδικα μίας στην Python. Εκτός και αν θες να φτιάξεις κάποιο API, πράγμα μάλλον απίθανο (συνήθως αρκούν τα έτοιμα πράγματα δλδ λίστες, πλειάδες, λεξικά και σύνολα)
Spoiler: show
Γνώσεις → Linux: Μέτριος ┃ Προγραμματισμός: Μέτριος ┃ Αγγλικά: Μέτριος
Λειτουργικό → Ubuntu 11.04 natty 64-bit (el_GR.UTF-8)
Προδιαγραφές → CPU: 4x Intel Core i5 CPU 750 2.67GHz ‖ RAM 3953 MiB ‖ ASRock P55DE3
Κάρτες γραφικών: nVidia G92 [GeForce GTS 250] ⎨10de:0615⎬ (rev a2)
Δίκτυα: eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller ⎨10ec:8168⎬ (rev 03)
Άβαταρ μέλους
lucinos
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 828
Εγγραφή: 12 Δεκ 2010, 22:04
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό Ilias95 » 25 Ιουν 2014, 05:31

lucinos έγραψε:Η αλήθεια είναι ότι οι κλάσσεις δεν είναι το δυνατό σημείο τής Python.

Μπορείς να το εξηγήσεις αυτό;

lucinos έγραψε:Στην πράξη κλάσεις χρησιμοποιείς αρκετά συχνά, αλλά ποτέ δεν θα χρειαστείς να φτιάξεις μία ή να δεις τον κώδικα μίας στην Python.

Wut? :problem:
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό Ilias95 » 25 Ιουν 2014, 05:44

@midkin
Γι' αυτό σου είπα να αποφύγεις το βιβλίο του Swaroop, γιατί σε κεφάλαια τόσο σημαντικά όσο ο αντικειμενοστραφής προγραμματισμός δεν εξηγεί σχεδόν τίποτα. Θα σε προέτρεπα να ψάξεις να βρεις άλλες πηγές για να διαβάσεις για αντικειμενοστρεφή σε python.

Πολύ χοντρικά και επειδή δεν έχω όρεξη να επαναλαμβάνω πράγματα χιλιογραμμένα.
Όταν φτιάξεις μία κλάση μπορείς να δημιουργήσεις διάφορα instances αυτής. Δημιουργείς δηλαδή objects το καθένα μπορεί να έχει ξεχωριστά χαρακτηριστικά. Το self είναι ο τρόπος για να αναφερθείς στα χαρακτηριστικά του κάθε object.

Παράδειγμα:
Κώδικας: Επιλογή όλων
class Person:
    def __init__(self, a_name, an_age):
        self.name = a_name
        self.age = an_age

    def sayHi(self):
        print("I am {0} and I am {1} years old.".format(self.name, self.age))

giannis = Person("Giannis", 12)
hristos = Person("Hristos", 39)

giannis.sayHi();
hristos.sayHi();


Έξοδος:
Κώδικας: Επιλογή όλων
I am Giannis and I am 12 years old.
I am Hristos and I am 39 years old.


Η μέθοδος __init__() είναι ο constructor της κλάσης. Καλείται αυτόματα κατά την δημιουργία του αντικειμένου και τα ορίσματα της είναι αυτά που θα ορίσουμε στην δημιουργία του αντικειμένου.

Αν δεν χρησιμοποιήσεις το self σε μια μέθοδο σημαίνει ότι η μέθοδος σχετίζεται μόνο με την κλάση σαν κλάση και όχι με κάθε instance ξεχωριστά. Τότε είναι καλό να την δηλώσεις σαν staticmethod. Αλλά άστο αυτό για αργότερα αφού ξεκαθαρίσεις τα βασικά.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό midkin » 25 Ιουν 2014, 11:15

Καταρχάς ευχαριστώ πολύ για τον χρόνο σας, τον κόπο σας και την υπομονή σας!! Πραγματικά είναι πολύ ενθαρρυντικό να εχεις άτομα που ενδιαφέρονται και απαντάνε...
Τις κλάσεις άρχισα μόλις να τις διαβάζω λιγάκι πιο απλουστευμένα και αναλυτικά από το "Python for kids".
Γενικά όσο μπορώ, προσπαθώ να αντλώ πληροφορίες από πολλές πηγες! :)
Γνώσεις ⇛ Linux: Χαμηλό ┃ Προγραμματισμός: Χαμηλό ┃ Αγγλικά: Πολύ Καλά
Λειτουργικό: Laptop Lenovo G505s με Windows 8.1 / Ubuntu 14.10 & Mac OS X 10.10 μέσω VirtualBox
Προδιαγραφές ⇛ AMD A8 τετραπύρηνος │ 8 GB RAM |
Άβαταρ μέλους
midkin
babeTUX
babeTUX
 
Δημοσιεύσεις: 44
Εγγραφή: 05 Σεπ 2009, 21:14
Τοποθεσία: Κομοτηνή
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό lucinos » 26 Ιουν 2014, 06:43

Ilias95 έγραψε:
lucinos έγραψε:Η αλήθεια είναι ότι οι κλάσσεις δεν είναι το δυνατό σημείο τής Python.

Μπορείς να το εξηγήσεις αυτό;

Η Python σχεδιάστηκε αρχικά δίχως κλάσσεις. Αυτό ακόμα και αν δεν ξέρεις ιστορία είναι οφθαλμοφανές στην Python2. πχ
Κώδικας: Επιλογή όλων
Python 2.7.7 (default, Jun  3 2014, 01:46:20)
[GCC 4.9.0 20140521 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> type(2)
<type 'int'>
>>>


Η Python3 έχει απλοποιηθεί συντακτικά:
Κώδικας: Επιλογή όλων
Python 3.4.1 (default, May 19 2014, 17:23:49)
[GCC 4.9.0 20140507 (prerelease)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> type(2)
<class 'int'>
>>>


Όμως (και κατά την γνώμη μου άριστα) η Python δεν άλλαξε χαρακτήρα. Η Python παραμένει Python και οι κλάσσεις δεν είναι το ισχυρό χαρακτηριστικό. Το ισχυρό χαρακτηριστικό τής γλώσσας είναι οι συναρτήσεις.

lucinos έγραψε:Στην πράξη κλάσεις χρησιμοποιείς αρκετά συχνά, αλλά ποτέ δεν θα χρειαστείς να φτιάξεις μία ή να δεις τον κώδικα μίας στην Python.

Wut? :problem:

Όταν κάποιος χρησιμοποιεί ένα οποιοδήποτε άρθρωμα, κατά πάσα πιθανότητα χρησιμοποιεί κλάσσεις. Αλλά αυτό δεν ενδιαφέρει τον προγραμματιστή-χρήστη. Γιατί τότε απλά θα κοιτάξει πώς χρησιμοποιούνται τα συγκεκριμένα αντικείμενα. Δηλαδή τις κλάσσεις στην Python τις βλέπω κυρίως σαν εργαλεία που φτιάχνουν προγραμματιστές για άλλους προγραμματιστές (ως τέτοια εργαλεία είναι εξαιρετικά χρήσιμες). Ένας προγραμματιστής ποτέ δεν χρειάζεται να φτιάξει μια κλάσση για τον εαυτό του (μιλώ για την Python πάντα). Υπάρχει πάντα κάτι έτοιμο που είναι αρκετό.

Ο μόνος λόγος που προσωπικά θα έφτιαχνα κλάσση είναι για να υπερφορτώσω τελεστές. Και στην πραγματικότητα το έχω κάνει αυτό! Έχω φτιάξει κλάσση για "quaternion"! Το "quaternion" (τετραδικούς τούς ήξερα, τώρα βλέπω στην βικιπαίδεια τον όρο «τετραδόνια» είναι κατά κάποιον τρόπο επέκταση τών μιγαδικών. Περισσότερα μπορείτε να δείτε στο άρθρο τής βικιπαίδειας: Quaternion και Τετραδόνιο

Μάλιστα πάρτε και τον κώδικά μου να τον έχετε:
Κώδικας: Επιλογή όλων
import math

class Quaternion(object):
    def __init__(self, w=0.0, x=0.0, y=0.0, z=0.0):
        self.w = float(w)
        self.x = float(x)
        self.y = float(y)
        self.z = float(z)

    def __repr__(self):
        return quat_repr(self)

    def __add__(self, other):
        return quat_add(self, other)
   
    def __radd__(self, other):
        return quat_add(other, self)

    def __neg__(self):
        return Quaternion(-self.w, -self.x, -self.y, -self.z)

    def __sub__(self, other):
        return quat_add(self, - other)
   
    def __rsub__(self, other):
        return quat_add(other, - self)


    def __mul__(self, other):
        return quat_mul(self, other)
   
    def __rmul__(self, other):
        return quat_mul(other, self)

    def __truediv__(self, other):
        return quat_div(self, other)
   
    def __rtruediv__(self, other):
        return quat_div(other, self)

    def __abs__(self):
        return math.sqrt(
                    self.w * self.w
                  + self.x * self.x
                  + self.y * self.y
                  + self.z * self.z
        )

    def __invert__(q):
        """Conjugate of Quaternion.

        >>> q = Quaternion((2, 2, 2, 2))
        >>> print(q)
        (2 + 2i + 2j + 2k)
        >>> print(~q)
        (2 - 2i - 2j - 2k)
        >>> print(~~q)
        (2 + 2i + 2j + 2k)

        """
        return Quaternion(q.w, -q.x, -q.y, -q.z)

    def as_tuple(self):
        return (self.w, self.x, self.y, self.z)


    def normalize(q):
        """Convert Quaternion to Unit Quaternion.

        Unit Quaternion is Quaternion who's length is equal to 1.

        >>> q = Quaternion((1, 3, 3, 3))
        >>> q.normalize()
        >>> print(q) # doctest: +ELLIPSIS
        (0.1889822... + 0.5669467...i + 0.5669467...j + 0.5669467...k)

        """
        norm = abs(q)
        q.w = q.w / norm
        q.x = q.x / norm
        q.y = q.y / norm
        q.z = q.z / norm

def signed_repr(x):
    if x < 0:
       return repr(x)
    else:
        return '+' + repr(x)
   
def quat_repr(q):
   return '{0} {1}i {2}j {3}k'.format(
                           signed_repr(q.w),
                           signed_repr(q.x),
                           signed_repr(q.y),
                           signed_repr(q.z),
   )

def quat_get(q):
    try:
        w = float(q)
        x = 0.0
        y = 0.0
        z = 0.0
        return Quaternion(w, x, y, z)
    except TypeError:
        return q

def quat_add(q1, q2):
    q1 = quat_get(q1)
    q2 = quat_get(q2)
    return Quaternion(
                q1.w + q2.w,
                q1.x + q2.x,
                q1.y + q2.y,
                q1.z + q2.z,
    )

def quat_mul(q1, q2):
    q1 = quat_get(q1)
    q2 = quat_get(q2)
    return Quaternion(
                q1.w*q2.w - q1.x*q2.x - q1.y*q2.y - q1.z*q2.z,
                q1.w*q2.x + q1.x*q2.w + q1.y*q2.z - q1.z*q2.y,
                q1.w*q2.y - q1.x*q2.z + q1.y*q2.w + q1.z*q2.x,
                q1.w*q2.z + q1.x*q2.y - q1.y*q2.x + q1.z*q2.w,
    )

def quat_div(q1, q2):
    q1 = quat_get(q1)
    q2 = quat_get(q2)
    s = float(q2.w*q2.w + q2.x*q2.x + q2.y*q2.y + q2.z*q2.z)
    return Quaternion(
            (  q1.w*q2.w + q1.x*q2.x + q1.y*q2.y + q1.z*q2.z) / s,
            (- q1.w*q2.x + q1.x*q2.w + q1.y*q2.z - q1.z*q2.y) / s,
            (- q1.w*q2.y - q1.x*q2.z + q1.y*q2.w + q1.z*q2.x) / s,
            (- q1.w*q2.z + q1.x*q2.y - q1.y*q2.x + q1.z*q2.w) / s,
    )



Ο κώδικας αυτός είναι δικός μου, πλην τών μεθόδων __invert__ και normalize (φαίνεται!). Εδώ φαίνεται και ένας προσωπικός μου κανόνας για τις κλάσσεις. Είναι πιστεύω λάθος να βάζουμε μη τετριμμένο κώδικα στις κλάσσεις. Αυτός που κοιτάει μια κλάσση θέλει να δει τι μεθόδους περιέχει. Ο όποιος κώδικας «κάνει δουλειά» πρέπει πάντα να βρίσκεται σε συναρτήσεις έξω από τις κλάσσεις. (διαφορετικά συσκοτίζει την κλάσση)

Δίνω παράδειγμα χρήσης σε ipython
Κώδικας: Επιλογή όλων
In [1]: import my_quaternion as quat

In [2]: q = quat.Quaternion(2,2,2,2)

In [3]: q
Out[3]: +2.0 +2.0i +2.0j +2.0k

In [4]: print(q)
+2.0 +2.0i +2.0j +2.0k

In [5]: 3-q
Out[5]: +1.0 -2.0i -2.0j -2.0k

In [6]: ~q
Out[6]: +2.0 -2.0i -2.0j -2.0k

In [7]: q*2
Out[7]: +4.0 +4.0i +4.0j +4.0k

In [8]: q*q
Out[8]: -8.0 +8.0i +8.0j +8.0k

In [9]: abs(q)
Out[9]: 4.0

In [10]: 3/q
Out[10]: +0.375 -0.375i -0.375j -0.375k

In [11]:

Spoiler: show
Γνώσεις → Linux: Μέτριος ┃ Προγραμματισμός: Μέτριος ┃ Αγγλικά: Μέτριος
Λειτουργικό → Ubuntu 11.04 natty 64-bit (el_GR.UTF-8)
Προδιαγραφές → CPU: 4x Intel Core i5 CPU 750 2.67GHz ‖ RAM 3953 MiB ‖ ASRock P55DE3
Κάρτες γραφικών: nVidia G92 [GeForce GTS 250] ⎨10de:0615⎬ (rev a2)
Δίκτυα: eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller ⎨10ec:8168⎬ (rev 03)
Άβαταρ μέλους
lucinos
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 828
Εγγραφή: 12 Δεκ 2010, 22:04
Εκτύπωση

Re: Μάθημα 5 - Μελέτη κώδικα Αντικειμενοστρεφής προγραμματισ

Δημοσίευσηαπό midkin » 26 Ιουν 2014, 14:43

Πόσα χρόνια θα μου πάρει για να μπορώ να καταλάβω το παραπάνω ποστ του @lucinos; :D
Γνώσεις ⇛ Linux: Χαμηλό ┃ Προγραμματισμός: Χαμηλό ┃ Αγγλικά: Πολύ Καλά
Λειτουργικό: Laptop Lenovo G505s με Windows 8.1 / Ubuntu 14.10 & Mac OS X 10.10 μέσω VirtualBox
Προδιαγραφές ⇛ AMD A8 τετραπύρηνος │ 8 GB RAM |
Άβαταρ μέλους
midkin
babeTUX
babeTUX
 
Δημοσιεύσεις: 44
Εγγραφή: 05 Σεπ 2009, 21:14
Τοποθεσία: Κομοτηνή
Εκτύπωση

ΠροηγούμενηΕπόμενο

Επιστροφή στο Μαθήματα python