socialgekon.com
  • Κύριος
  • Άτομα Και Ομάδες
  • Πίσω Μέρος
  • Κυνήγι
  • Κατανεμημένες Ομάδες
Τεχνολογία

Χαρακτηριστικά κλάσης Python: Ένας υπερβολικά διεξοδικός οδηγός

Είχα ένα συνέντευξη προγραμματισμού πρόσφατα, μια οθόνη τηλεφώνου στην οποία χρησιμοποιήσαμε ένα συνεργατικός επεξεργαστής κειμένου .

Μου ζητήθηκε να εφαρμόσω ένα συγκεκριμένο API , και επέλεξαν να το κάνουν μέσα Πύθων . Αφαιρώντας τη δήλωση προβλήματος, ας πούμε ότι χρειαζόμουν μια τάξη της οποίας οι παρουσίες αποθηκεύτηκαν κάποια data και μερικά other_data.

Πήρα μια βαθιά ανάσα και άρχισα να πληκτρολογώ. Μετά από μερικές γραμμές, είχα κάτι τέτοιο:



class Service(object): data = [] def __init__(self, other_data): self.other_data = other_data ...

Ο ερευνητής μου με σταμάτησε:

  • Συνέντευξη: «Αυτή η γραμμή: data = []. Δεν νομίζω ότι είναι έγκυρο Python; '
  • Εγώ: «Είμαι πολύ σίγουρος. Απλώς ορίζει μια προεπιλεγμένη τιμή για το χαρακτηριστικό εμφάνισης. '
  • Συνέντευξη: 'Πότε εκτελείται αυτός ο κώδικας;'
  • Εγώ: «Δεν είμαι πραγματικά σίγουρος. Θα το φτιάξω για να αποφύγω τη σύγχυση. '

Για αναφορά, και για να σας δώσω μια ιδέα για το τι έψαχνα, δείτε πώς τροποποίησα τον κώδικα:

class Service(object): def __init__(self, other_data): self.data = [] self.other_data = other_data ...

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

Χαρακτηριστικά κλάσης Python έναντι χαρακτηριστικών παρουσίας Python

Σημείωση: εάν έχετε μια ειδική λαβή σε χαρακτηριστικά κλάσης, μπορείτε να προχωρήσετε περιπτώσεις χρήσης .

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

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

Και εγώ έκανα λάθος στο ότι δεν ορίζει μια 'προεπιλεγμένη τιμή' για το χαρακτηριστικό εμφάνισης. Αντ 'αυτού, ορίζει data σαν τάξη χαρακτηριστικό με τιμή [].

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

Μεταβλητή κλάσης Python έναντι μεταβλητής παρουσίας: Ποια είναι η διαφορά;

Ένα χαρακτηριστικό κλάσης Python είναι ένα χαρακτηριστικό της κλάσης (κυκλικό, ξέρω), παρά ένα χαρακτηριστικό ενός παράδειγμα μιας τάξης.

Ας χρησιμοποιήσουμε ένα παράδειγμα κλάσης Python για να δείξουμε τη διαφορά. Εδώ, class_var είναι ένα χαρακτηριστικό κλάσης και i_var είναι ένα χαρακτηριστικό παρουσίας:

class MyClass(object): class_var = 1 def __init__(self, i_var): self.i_var = i_var

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

foo = MyClass(2) bar = MyClass(3) foo.class_var, foo.i_var ## 1, 2 bar.class_var, bar.i_var ## 1, 3 MyClass.class_var ## <— This is key ## 1

Για προγραμματιστές Java ή C ++, το χαρακτηριστικό κλάσης είναι παρόμοιο - αλλά όχι πανομοιότυπο - με το στατικό μέλος. Θα δούμε πώς διαφέρουν αργότερα.

Όνομα ονομάτων τάξης έναντι παρουσίας

Για να καταλάβουμε τι συμβαίνει εδώ, ας μιλήσουμε εν συντομία Χώροι ονομάτων Python .

ΠΡΟΣ ΤΟ χώρος ονομάτων είναι μια αντιστοίχιση από ονόματα σε αντικείμενα, με την ιδιότητα να υπάρχει μηδενική σχέση μεταξύ ονομάτων σε διαφορετικούς χώρους ονομάτων. Συνήθως εφαρμόζονται ως λεξικά Python, αν και αφαιρείται.

Ανάλογα με το περιβάλλον, ίσως χρειαστεί να αποκτήσετε πρόσβαση σε ένα χώρο ονομάτων χρησιμοποιώντας σύνταξη κουκκίδων (π.χ. object.name_from_objects_namespace) ή ως τοπική μεταβλητή (π.χ. object_from_namespace). Ως συγκεκριμένο παράδειγμα:

class MyClass(object): ## No need for dot syntax class_var = 1 def __init__(self, i_var): self.i_var = i_var ## Need dot syntax as we've left scope of class namespace MyClass.class_var ## 1

Μαθήματα Python και παρουσίες τάξεων το καθένα έχει το δικό του ξεχωριστό χώρο ονομάτων που αντιπροσωπεύεται από προκαθορισμένα χαρακτηριστικά MyClass.__dict__ και instance_of_MyClass.__dict__, αντίστοιχα.

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

foo = MyClass(2) ## Finds i_var in foo's instance namespace foo.i_var ## 2 ## Doesn't find class_var in instance namespace… ## So look's in class namespace (MyClass.__dict__) foo.class_var ## 1

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

def instlookup(inst, name): ## simplified algorithm... if inst.__dict__.has_key(name): return inst.__dict__[name] else: return inst.__class__.__dict__[name]

Και, σε οπτική μορφή:

αναζήτηση χαρακτηριστικών σε οπτική μορφή

Τρόπος χειρισμού χαρακτηριστικών κατηγορίας

Έχοντας αυτό κατά νου, μπορούμε να κατανοήσουμε πώς τα χαρακτηριστικά κλάσης Python χειρίζονται την ανάθεση:

  • Εάν ένα χαρακτηριστικό κλάσης έχει οριστεί με την πρόσβαση στην τάξη, θα αντικαταστήσει την τιμή για όλα περιπτώσεις. Για παράδειγμα:

    foo = MyClass(2) foo.class_var ## 1 MyClass.class_var = 2 foo.class_var ## 2

    Στο επίπεδο ονομάτων… ρυθμίζουμε MyClass.__dict__['class_var'] = 2. (Σημείωση: αυτό δεν είναι ο ακριβής κωδικός (που θα ήταν setattr(MyClass, 'class_var', 2)) ως __dict__ επιστρέφει a υπαγόρευση , ένα αμετάβλητο περιτύλιγμα που αποτρέπει την άμεση ανάθεση, αλλά βοηθά για λόγους επίδειξης). Στη συνέχεια, όταν έχουμε πρόσβαση στο foo.class_var, class_var έχει μια νέα τιμή στο χώρο ονομάτων τάξης και έτσι επιστρέφεται το 2.

  • Εάν μια μεταβλητή κλάσης Paython έχει οριστεί με πρόσβαση σε μια παρουσία, θα παρακάμψει την τιμή μόνο για αυτήν την περίπτωση . Αυτό ουσιαστικά παρακάμπτει τη μεταβλητή κλάσης και τη μετατρέπει σε μια μεταβλητή παρουσίας, διαισθητικά, μόνο για αυτήν την περίπτωση . Για παράδειγμα:

    foo = MyClass(2) foo.class_var ## 1 foo.class_var = 2 foo.class_var ## 2 MyClass.class_var ## 1

    Στο επίπεδο ονομάτων… προσθέτουμε το class_var χαρακτηριστικό στο foo.__dict__, οπότε όταν αναζητάμε foo.class_var, επιστρέφουμε 2. Εν τω μεταξύ, άλλες εμφανίσεις του MyClass θα δεν έχουν class_var στους χώρους ονομάτων παρουσίας τους, έτσι συνεχίζουν να βρίσκουν class_var σε MyClass.__dict__ και έτσι επιστρέψτε 1.

Ευμετάβλητο

Ερώτηση κουίζ: Τι γίνεται αν το χαρακτηριστικό της τάξης σας έχει ένα μεταβλητός τύπος ; Μπορείτε να χειριστείτε (να ακρωτηριάσετε;) το χαρακτηριστικό κλάσης, αποκτώντας πρόσβαση σε αυτό μέσω μιας συγκεκριμένης παρουσίας και, με τη σειρά του, να καταλήξετε χειρισμός του αντικειμένου αναφοράς στο οποίο έχουν πρόσβαση όλες οι παρουσίες (όπως επεσήμανε ο Τίμοθι Βίσμαν ).

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

class Service(object): data = [] def __init__(self, other_data): self.other_data = other_data ...

Ο στόχος μου ήταν να έχω την κενή λίστα ([]) ως την προεπιλεγμένη τιμή για data και για κάθε εμφάνιση Service να έχω τα δικά του δεδομένα αυτό θα άλλαζε με την πάροδο του χρόνου με βάση την περίσταση. Σε αυτήν την περίπτωση, έχουμε την ακόλουθη συμπεριφορά (θυμηθείτε ότι Service παίρνει κάποιο επιχείρημα other_data, το οποίο είναι αυθαίρετο σε αυτό το παράδειγμα):

s1 = Service(['a', 'b']) s2 = Service(['c', 'd']) s1.data.append(1) s1.data ## [1] s2.data ## [1] s2.data.append(2) s1.data ## [1, 2] s2.data ## [1, 2]

Αυτό δεν είναι καλό - η αλλαγή της μεταβλητής τάξης μέσω μιας παρουσίας την αλλάζει για όλες τις άλλες!

Στο επίπεδο ονομάτων… όλες οι εμφανίσεις του Service έχουν πρόσβαση και τροποποιούν την ίδια λίστα στο Service.__dict__ χωρίς να φτιάξουν το δικό τους data χαρακτηριστικά στους χώρους ονομάτων παρουσίας τους.

Θα μπορούσαμε να το αντιμετωπίσουμε χρησιμοποιώντας την ανάθεση. δηλαδή, αντί να εκμεταλλευόμαστε τη μεταβλητότητα της λίστας, θα μπορούσαμε να αντιστοιχίσουμε το Service αντικείμενα για να έχουν τις δικές τους λίστες, ως εξής:

s1 = Service(['a', 'b']) s2 = Service(['c', 'd']) s1.data = [1] s2.data = [2] s1.data ## [1] s2.data ## [2]

Σε αυτήν την περίπτωση, προσθέτουμε s1.__dict__['data'] = [1], οπότε το πρωτότυπο Service.__dict__['data'] παραμένει αναλλοίωτο.

Δυστυχώς, αυτό απαιτεί ότι Service οι χρήστες έχουν οικεία γνώση των μεταβλητών του και είναι σίγουρα επιρρεπείς σε λάθη. Κατά μία έννοια, αντιμετωπίζουμε τα συμπτώματα και όχι την αιτία. Θα προτιμούσαμε κάτι που ήταν σωστό από την κατασκευή.

Η προσωπική μου λύση: αν χρησιμοποιείτε απλώς μια μεταβλητή τάξης για να εκχωρήσετε μια προεπιλεγμένη τιμή σε μια πιθανή μεταβλητή παρουσίας Python, μην χρησιμοποιείτε μεταβλητές τιμές . Σε αυτήν την περίπτωση, κάθε περίπτωση Service επρόκειτο να παρακάμψει Service.data με το δικό του χαρακτηριστικό παρουσίας τελικά, οπότε η χρήση μιας κενής λίστας ως προεπιλογή οδήγησε σε ένα μικρό σφάλμα που παραβλέφθηκε εύκολα. Αντί για τα παραπάνω, θα μπορούσαμε είτε:

  1. Κολλημένο σε χαρακτηριστικά παραδείγματα εντελώς, όπως αποδεικνύεται στην εισαγωγή.
  2. Αποφύγετε τη χρήση της κενής λίστας (μια μεταβλητή τιμή) ως «προεπιλογή»:

    class Service(object): data = None def __init__(self, other_data): self.other_data = other_data ...

    Φυσικά, πρέπει να χειριστούμε το None κατάλληλη υπόθεση, αλλά αυτό είναι ένα μικρό τίμημα.

Λοιπόν, πότε πρέπει να χρησιμοποιήσετε τα χαρακτηριστικά κλάσης Python;

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

  1. Αποθήκευση σταθερών . Καθώς τα χαρακτηριστικά κατηγορίας είναι προσβάσιμα ως χαρακτηριστικά της ίδιας της τάξης, είναι συχνά ωραίο να τα χρησιμοποιείτε για την αποθήκευση σταθερών σε όλη την κατηγορία και συγκεκριμένων κατηγοριών. Για παράδειγμα:

    class Circle(object): pi = 3.14159 def __init__(self, radius): self.radius = radius def area(self): return Circle.pi * self.radius * self.radius Circle.pi ## 3.14159 c = Circle(10) c.pi ## 3.14159 c.area() ## 314.159
  2. Καθορισμός προεπιλεγμένων τιμών . Ως ασήμαντο παράδειγμα, ενδέχεται να δημιουργήσουμε μια οριοθετημένη λίστα (δηλαδή, μια λίστα που μπορεί να περιέχει μόνο έναν συγκεκριμένο αριθμό στοιχείων ή λιγότερα) και να επιλέξει να έχει ένα προεπιλεγμένο όριο 10 στοιχείων:

    class MyClass(object): limit = 10 def __init__(self): self.data = [] def item(self, i): return self.data[i] def add(self, e): if len(self.data) >= self.limit: raise Exception('Too many elements') self.data.append(e) MyClass.limit ## 10

    Θα μπορούσαμε, στη συνέχεια, να δημιουργήσουμε παρουσίες με τα δικά τους ειδικά όρια, εκχωρώντας επίσης την παρουσία limit Χαρακτηριστικό.

    foo = MyClass() foo.limit = 50 ## foo can now hold 50 elements—other instances can hold 10

    Αυτό έχει νόημα μόνο αν θέλετε την τυπική παρουσία σας MyClass για να κρατήσετε μόνο 10 στοιχεία ή λιγότερα — εάν δίνετε σε όλες τις περιπτώσεις σας διαφορετικά όρια, τότε limit θα πρέπει να είναι μια μεταβλητή παρουσίας. (Θυμηθείτε, ωστόσο: προσέξτε όταν χρησιμοποιείτε μεταβλητές τιμές ως προεπιλογές σας.)

  3. Παρακολούθηση όλων των δεδομένων σε όλες τις εμφανίσεις μιας συγκεκριμένης κλάσης . Αυτό είναι ένα είδος συγκεκριμένου, αλλά θα μπορούσα να δω ένα σενάριο στο οποίο μπορεί να θέλετε να αποκτήσετε πρόσβαση σε ένα κομμάτι δεδομένων που σχετίζεται με κάθε υπάρχουσα παρουσία μιας δεδομένης κλάσης.

    Για να κάνουμε το σενάριο πιο συγκεκριμένο, ας υποθέσουμε ότι έχουμε ένα Person τάξη και κάθε άτομο έχει name. Θέλουμε να παρακολουθούμε όλα τα ονόματα που έχουν χρησιμοποιηθεί. Μια προσέγγιση μπορεί να είναι επαναλάβετε τη λίστα αντικειμένων του συλλέκτη απορριμμάτων , αλλά είναι πιο απλό να χρησιμοποιείτε μεταβλητές τάξης.

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

    class Person(object): all_names = [] def __init__(self, name): self.name = name Person.all_names.append(name) joe = Person('Joe') bob = Person('Bob') print Person.all_names ## ['Joe', 'Bob']

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

    class Person(object): all_people = [] def __init__(self, name): self.name = name Person.all_people.append(self) joe = Person('Joe') bob = Person('Bob') print Person.all_people ## [, ]
  4. Εκτέλεση (είδος… δείτε παρακάτω).

Σχετίζεται με: Βέλτιστες πρακτικές και συμβουλές της Python από τους ApeeScape Developers

Κάτω από την κουκούλα

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

Θυμηθείτε ότι ο χώρος ονομάτων μιας τάξης έχει δημιουργηθεί και συμπληρωθεί τη στιγμή του ορισμού της τάξης. Αυτό σημαίνει ότι κάνουμε μόνο μία ανάθεση— πάντα —Για μια δεδομένη μεταβλητή κλάσης, ενώ οι μεταβλητές παρουσίας πρέπει να εκχωρούνται κάθε φορά που δημιουργείται μια νέα παρουσία. Ας πάρουμε ένα παράδειγμα.

def called_class(): print 'Class assignment' return 2 class Bar(object): y = called_class() def __init__(self, x): self.x = x ## 'Class assignment' def called_instance(): print 'Instance assignment' return 2 class Foo(object): def __init__(self, x): self.y = called_instance() self.x = x Bar(1) Bar(2) Foo(1) ## 'Instance assignment' Foo(2) ## 'Instance assignment'

Αναθέτουμε στο Bar.y μόνο μία φορά, αλλά instance_of_Foo.y σε κάθε κλήση προς __init__.

Ως περαιτέρω αποδείξεις, ας χρησιμοποιήσουμε το Αποσυναρμολογητής Python :

import dis class Bar(object): y = 2 def __init__(self, x): self.x = x class Foo(object): def __init__(self, x): self.y = 2 self.x = x dis.dis(Bar) ## Disassembly of __init__: ## 7 0 LOAD_FAST 1 (x) ## 3 LOAD_FAST 0 (self) ## 6 STORE_ATTR 0 (x) ## 9 LOAD_CONST 0 (None) ## 12 RETURN_VALUE dis.dis(Foo) ## Disassembly of __init__: ## 11 0 LOAD_CONST 1 (2) ## 3 LOAD_FAST 0 (self) ## 6 STORE_ATTR 0 (y) ## 12 9 LOAD_FAST 1 (x) ## 12 LOAD_FAST 0 (self) ## 15 STORE_ATTR 1 (x) ## 18 LOAD_CONST 0 (None) ## 21 RETURN_VALUE

Όταν εξετάζουμε τον κώδικα byte, είναι και πάλι προφανές ότι Foo.__init__ πρέπει να κάνει δύο εργασίες, ενώ Bar.__init__ κάνει μόνο ένα.

Στην πράξη, πώς φαίνεται αυτό το κέρδος; Θα είμαι ο πρώτος που θα παραδεχτώ ότι οι δοκιμές χρονισμού εξαρτώνται σε μεγάλο βαθμό από συχνά ανεξέλεγκτους παράγοντες και οι διαφορές μεταξύ τους είναι συχνά δύσκολο να εξηγηθούν με ακρίβεια.

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

Σημείωση: Είμαι σε MacBook Pro με OS X 10.8.5 και Python 2.7.2.

Αρχικοποίηση

10000000 calls to `Bar(2)`: 4.940s 10000000 calls to `Foo(2)`: 6.043s

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

Γιατί λοιπόν συμβαίνει αυτό; Ενας κερδοσκοπικός εξήγηση: κάνουμε δύο εργασίες στο Foo.__init__, αλλά μόνο μία στο Bar.__init__.

ΑΝΑΘΕΣΗ ΕΡΓΑΣΙΑΣ

10000000 calls to `Bar(2).y = 15`: 6.232s 10000000 calls to `Foo(2).y = 15`: 6.855s 10000000 `Bar` assignments: 6.232s - 4.940s = 1.292s 10000000 `Foo` assignments: 6.855s - 6.043s = 0.812s

Σημείωση: Δεν υπάρχει τρόπος να εκτελέσετε ξανά τον κωδικό εγκατάστασης σε κάθε δοκιμή χρονικά , οπότε πρέπει να επανεκκινήσουμε τη μεταβλητή μας στη δοκιμή μας. Η δεύτερη γραμμή χρόνων αντιπροσωπεύει τους παραπάνω χρόνους με τους προηγούμενους υπολογισμένους χρόνους αρχικοποίησης.

Από τα παραπάνω, μοιάζει με Foo διαρκεί μόνο περίπου 60% εφόσον Bar για να χειριστείτε εργασίες.

Γιατί συμβαίνει αυτό; Ενας κερδοσκοπικός εξήγηση: όταν αντιστοιχίζουμε στο Bar(2).y, κοιτάζουμε πρώτα στο χώρο ονομάτων παρουσίας (Bar(2).__dict__[y]), αποτυγχάνουμε να βρούμε y και μετά κοιτάζουμε στο χώρο ονομάτων τάξης (Bar.__dict__[y]) , στη συνέχεια κάνοντας την κατάλληλη ανάθεση. Όταν αντιστοιχίζουμε στο Foo(2).y, κάνουμε τις μισές αναζητήσεις, όπως αντιστοιχίζουμε αμέσως στο χώρο ονομάτων παρουσίας (Foo(2).__dict__[y]).

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

Συμπερασματικά

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

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

παράρτημα : Ιδιωτικές μεταβλητές παρουσίας

Ένα πράγμα που ήθελα να συμπεριλάβω αλλά δεν είχα ένα φυσικό σημείο εισόδου…

Η Python δεν έχει ιδιωτικός μεταβλητές έτσι ώστε να μιλούν, αλλά μια άλλη ενδιαφέρουσα σχέση μεταξύ της ονομασίας τάξης και παρουσίας έρχεται με το όνομα mangling.

Στον οδηγό στυλ Python, αναφέρεται ότι οι ψευδο-ιδιωτικές μεταβλητές θα πρέπει να προθεματοποιούνται με μια διπλή υπογράμμιση: «__». Αυτό δεν είναι μόνο ένα σημάδι για άλλους ότι η μεταβλητή σας προορίζεται να αντιμετωπιστεί ιδιωτικά, αλλά και ένας τρόπος να αποφευχθεί η πρόσβαση σε αυτήν, των ειδών. Να τι εννοώ:

class Bar(object): def __init__(self): self.__zap = 1 a = Bar() a.__zap ## Traceback (most recent call last): ## File '', line 1, in ## AttributeError: 'Bar' object has no attribute '__baz' ## Hmm. So what's in the namespace? a.__dict__ {'_Bar__zap': 1} a._Bar__zap ## 1

Κοιτάξτε αυτό: το χαρακτηριστικό εμφάνισης __zap προτίθεται αυτόματα με το όνομα της τάξης για απόδοση _Bar__zap.

Ενώ εξακολουθείτε να διευθετείτε και να λαμβάνετε χρησιμοποιώντας a._Bar__zap, αυτό το όνομα mangling είναι ένα μέσο δημιουργίας μιας «ιδιωτικής» μεταβλητής καθώς σας αποτρέπει και άλλοι από την πρόσβαση σε αυτό κατά λάθος ή από άγνοια.

Επεξεργασία: όπως επεσήμανε ο Pedro Werneck, αυτή η συμπεριφορά προορίζεται σε μεγάλο βαθμό να βοηθήσει στην υποκατηγορία. Στο Οδηγός στυλ PEP 8 , το θεωρούν ότι εξυπηρετεί δύο σκοπούς: (1) αποτροπή πρόσβασης σε υποκατηγορίες από συγκεκριμένα χαρακτηριστικά και (2) αποτροπή διένεξης χώρου ονομάτων σε αυτές τις υποκατηγορίες. Παρόλο που είναι χρήσιμο, το μεταβλητό mangling δεν πρέπει να θεωρείται πρόσκληση για σύνταξη κώδικα με υποτιθέμενη διάκριση δημόσιου-ιδιωτικού τομέα, όπως υπάρχει στην Java.

Σχετίζεται με: Γίνετε πιο προχωρημένοι: Αποφύγετε τα 10 πιο συνηθισμένα λάθη που κάνουν οι προγραμματιστές της Python

Κατανόηση των βασικών

Τι είναι ο χώρος ονομάτων Python;

Όπως υποδηλώνει το όνομα, ένας χώρος ονομάτων Python είναι μια αντιστοίχιση από ονόματα σε αντικείμενα, με την ιδιότητα να υπάρχει μηδενική σχέση μεταξύ ονομάτων σε διαφορετικούς χώρους ονομάτων. Τα Namespaces συνήθως εφαρμόζονται ως λεξικά Python, αν και αυτό αφαιρείται.

Μέθοδος κλάσης Python έναντι μεθόδου εμφάνισης: Ποια είναι η διαφορά;

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

Τι θα συμβεί εάν οριστεί τόσο το χαρακτηριστικό εμφάνισης όσο και το χαρακτηριστικό κλάσης;

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

Πρέπει να επανεξετάσουμε τη χρήση του EBITDA;

Κερδοφορία & Αποδοτικότητα

Πρέπει να επανεξετάσουμε τη χρήση του EBITDA;
Σχεδιασμός για Ανθρώπινη Συμπεριφορά: Ορισμός του Άυλου

Σχεδιασμός για Ανθρώπινη Συμπεριφορά: Ορισμός του Άυλου

Σχεδιασμός Ux

Δημοφιλείς Αναρτήσεις
Ανώτερος Μηχανικός Back-end, Ομάδα Εξόρυξης Χρεώσεων
Ανώτερος Μηχανικός Back-end, Ομάδα Εξόρυξης Χρεώσεων
Η ApeeScape συνεργάζεται με Global Guide για να προσφέρει κατ 'απαίτηση πρόσβαση στο Elite Network of Freelancers
Η ApeeScape συνεργάζεται με Global Guide για να προσφέρει κατ 'απαίτηση πρόσβαση στο Elite Network of Freelancers
Παραγωγικότητα στο δρόμο: Εργασία με πλήρη απασχόληση, ταξίδια σόλο, διασκέδαση
Παραγωγικότητα στο δρόμο: Εργασία με πλήρη απασχόληση, ταξίδια σόλο, διασκέδαση
Πώς λειτουργεί το Shazam; Αλγόριθμοι αναγνώρισης μουσικής, δακτυλικά αποτυπώματα και επεξεργασία
Πώς λειτουργεί το Shazam; Αλγόριθμοι αναγνώρισης μουσικής, δακτυλικά αποτυπώματα και επεξεργασία
Απλοποίηση της χρήσης RESTful API και ανθεκτικότητας δεδομένων σε iOS με το Mantle και το Realm
Απλοποίηση της χρήσης RESTful API και ανθεκτικότητας δεδομένων σε iOS με το Mantle και το Realm
 
Εκμάθηση κειμένου SVG: Σχολιασμός κειμένου στον Ιστό
Εκμάθηση κειμένου SVG: Σχολιασμός κειμένου στον Ιστό
Εισαγωγή στο Deep Learning Trading σε Hedge Funds
Εισαγωγή στο Deep Learning Trading σε Hedge Funds
Magento 2 Tutorial: Πώς να φτιάξετε μια πλήρη ενότητα
Magento 2 Tutorial: Πώς να φτιάξετε μια πλήρη ενότητα
Προοπτικές εμπειρογνωμόνων για την κατάσταση της εκπαίδευσης σχεδιασμού
Προοπτικές εμπειρογνωμόνων για την κατάσταση της εκπαίδευσης σχεδιασμού
Πώς να χρησιμοποιήσετε το TikTok για επιχειρήσεις ως εντελώς αρχάριος
Πώς να χρησιμοποιήσετε το TikTok για επιχειρήσεις ως εντελώς αρχάριος
Κατηγορίες
ΚινητόΤροποσ ΖωησΚύκλος Ζωής ΠροϊόντοςΠίσω ΜέροςΆτομα Και ΟμάδεςΑνάρτησηΜηχανική ΔιοίκησηΤάσειςΔιεπαφή ΙστούKpi Και Analytics

© 2023 | Ολα Τα Δικαιώματα Διατηρούνται

socialgekon.com