2010-04-26 14 views
95

Ich habe Python-Klassen, von denen ich zur Laufzeit nur eine Instanz benötige, daher wäre es ausreichend, die Attribute nur einmal pro Klasse und nicht pro Instanz zu haben. Wenn es mehr als eine Instanz geben würde (was nicht passieren wird), sollten alle Instanzen dieselbe Konfiguration haben. Ich frage mich, welche der folgenden Optionen besser oder "idiomatischer" Python wäre.Instanzvariablen vs. Klassenvariablen in Python

Klassenvariablen:

class MyController(Controller): 

    path = "something/" 
    children = [AController, BController] 

    def action(self, request): 
    pass 

Instanzvariablen:

class MyController(Controller): 

    def __init__(self): 
    self.path = "something/" 
    self.children = [AController, BController] 

    def action(self, request): 
    pass 
+4

Nachdem ich diese Frage gelesen und die Antwort gesehen hatte, war eine meiner ersten Fragen: "Wie greife ich auf Klassenvariablen zu?" Das liegt daran, dass ich bis zu diesem Zeitpunkt nur Instanzvariablen verwendet habe. Als Antwort auf meine eigene Frage machst du das über den Klassennamen selbst, obwohl du es technisch auch über eine Instanz machen kannst. Hier ist ein Link für jeden anderen mit der gleichen Frage zu lesen: http://stackoverflow.com/a/3434596/4561887 –

Antwort

138

Wenn Sie ohnehin nur eine Instanz haben, ist es am besten, alle Variablen pro Instanz zu machen, nur weil sie zugegriffen wird (a etwas) schneller (eine Ebene weniger "Nachschlagen" aufgrund der "Vererbung" von Klasse zu Instanz), und es gibt keine Nachteile, die gegen diesen kleinen Vorteil stehen.

+6

Noch nie von dem Borg-Muster gehört? Nur eine Instanz zu haben, war der falsche Weg, sie überhaupt zu haben. –

+378

@Devin, yep, ich habe von dem Borg-Muster gehört, da ich derjenige bin, der es eingeführt hat (im Jahr 2001, cfr http://code.activestate.com/recipes/66531-singleton-wee-dont-need) -no-stinktin-singleton-the-bo/;-). Aber es ist nichts falsch, in einfachen Fällen, mit einer einzigen Instanz ohne Durchsetzung. –

+0

Gibt es irgendwelche Benchmarks? – user1767754

18

Im Zweifelsfall möchten Sie wahrscheinlich ein Instanzattribut.

Klassenattribute sind am besten für Sonderfälle reserviert, in denen sie sinnvoll sind. Der einzige sehr häufige Anwendungsfall sind Methoden. Es ist nicht uncommon Klassenattribute für schreibgeschützte Konstanten zu verwenden, die Instanzen wissen müssen (obwohl der einzige Vorteil ist, wenn Sie auch Zugriff von außerhalb der Klasse wollen), aber Sie sollten vorsichtig beim Speichern sein jeder Staat in ihnen, was selten ist, was Sie wollen. Selbst wenn Sie nur eine Instanz haben, sollten Sie die Klasse wie jede andere schreiben, was normalerweise die Verwendung von Instanzattributen bedeutet.

+0

Die Klassenvariablen sind eine Art schreibgeschützter Konstanten. Wenn Python Konstanten definieren würde, hätte ich es als Konstanten geschrieben. – deamon

+1

@deamon, ich bin etwas wahrscheinlicher, meine Konstanten vollständig außerhalb einer Klassendefinitionen zu setzen und sie in Großbuchstaben zu benennen. Putting sie in der Klasse ist auch in Ordnung. Das Erstellen von Instanzattributen wird nichts schaden, könnte aber ein wenig merkwürdig sein. Ich glaube nicht, dass dies ein Problem ist, bei dem die Community zu sehr hinter eine der Optionen zurückfällt. –

+0

@MikeGraham FWIW, [Google Python Style Guide] (http://google-styleguide.googlecode.com/svn/trunk/pyguide.html?showone=Global_variables#Global_variables) schlägt vor, globale Variablen zugunsten von Klassenvariablen zu vermeiden. Es gibt jedoch Ausnahmen. – Dennis

36

weiter Echo Mikes und alex Rat und das Hinzufügen meiner eigenen Farbe ...

mit Instanz-Attribute sind die typischen, mehr idiomatische Python. Klassenattribute werden nicht oft verwendet - zumindest nicht in Produktionscode in meinen letzten 13+ aufeinanderfolgenden Jahren von Python. Das selbe gilt für statische und Klassenmethoden ... einfach nicht sehr häufig, es sei denn, es gibt einen speziellen Anwendungsfall oder einen anormalen Programmierer, der zeigen möchte, dass er irgendeine obskure Ecke der Python-Programmierung kennt.

alex erwähnt in seiner Antwort, dass der Zugriff (ein bisschen) schneller sein wird aufgrund einer weniger Ebene der Nachschau ... lassen Sie mich weiter für diejenigen, die nicht wissen, wie das funktioniert noch klären, es ist sehr ähnlich variablen Zugriff - ist nun mal die Suche in dieser Reihenfolge:

  1. Einheimische
  2. nonlocals
  3. Globals
  4. Einbauten

für Attribut Zugriff ist die Reihenfolge:

  1. Instanz
  2. Klasse
  3. Basisklassen als

in Ihrem Beispiel oben durch die MRO (Methode Auflösung Reihenfolge) bestimmt, die Sie sagen wir mal‘ Das Attribut path nachschlagen. Wenn es auf einen Verweis wie "self.path" stößt, sucht Python zuerst nach den Instanzattributen für eine Übereinstimmung. Wenn dies fehlschlägt, überprüft es die Klasse, von der das Objekt instanziiert wurde.Schließlich wird es die Basisklassen durchsuchen. wie alex gesagt hat, wenn dein attribut in der instanz gefunden wird, wird es nicht auf die klasse verzichten, daher hast du ein bisschen zeit gespart.

jedoch, wenn Sie auf Klassenattribute zu bestehen, müssen Sie diese klein wenig Leistung verzichten, oder, Ihre andere Alternative ist, über die Klasse auf das Objekt zu verweisen, statt der Instanz, zB MyController.path statt von self.path. Das ist eine direkte Suche, die die verzögerte Suche umgehen wird, aber wie alex unten erwähnt, ist das eine globale Variable, also verlierst du das Bit, von dem du dachtest, dass du es speichern würdest (es sei denn, du erstellst einen lokalen Verweis auf den [globalen] Klassennamen).

+0

@wescpy, aber 'MyController' wird in den Globals nachgeschlagen, so dass die Gesamtkosten höher als' self.path' sind, wobei 'path' eine Instanzvariable ist (da' self' _local_ zur Methode == super-schnell ist Sieh nach oben). –

+0

ach, stimmt. guter Fang. Ich denke, die einzige Problemumgehung ist, eine lokale Referenz zu erstellen ... an diesem Punkt ist es nicht wirklich wert. – wescpy

Verwandte Themen