Soll ich meinen Klassenmitgliedern folgende Standardwerte geben:
class Foo:
num = 1
oder so?
class Foo:
def __init__(self):
self.num = 1
In dieser Frage entdeckte ich, dass in beiden Fällen
bar = Foo()
bar.num += 1
ist eine genau definierte Operation.
Ich verstehe, dass die erste Methode mir eine Klassenvariable gibt, die zweite nicht. Wenn ich jedoch keine Klassenvariable benötige, sondern nur einen Standardwert für meine Instanzvariablen festlegen muss, sind beide Methoden gleich gut? Oder einer von ihnen "pythonischer" als der andere?
Eine Sache, die mir aufgefallen ist, ist, dass sie im Django-Tutorial die zweite Methode verwenden, um Modelle zu deklarieren. Persönlich denke ich, dass die zweite Methode eleganter ist, aber ich würde gerne wissen, was der "Standard" ist.
self.attr = attr or []
innerhalb der__init__
Methode. Es erzielt das gleiche Ergebnis (glaube ich) und ist immer noch klar und lesbar.Die beiden Schnipsel machen unterschiedliche Dinge, es ist also keine Frage des Geschmacks, sondern des richtigen Verhaltens in Ihrem Kontext. Die Python-Dokumentation erklärt den Unterschied, aber hier sind einige Beispiele:
Anlage A.
Dies bindet
num
an die Foo- Instanzen . Änderungen an diesem Feld werden nicht an andere Instanzen weitergegeben.So:
Anlage B.
Dies bindet
num
an die Bar- Klasse . Änderungen werden weitergegeben!Aktuelle Antwort
Der Code in Exponat B ist dafür eindeutig falsch: Warum sollten Sie ein Klassenattribut (Standardwert bei der Instanzerstellung) an die einzelne Instanz binden?
Der Code in Exponat A ist in Ordnung.
Wenn Sie in Ihrem Konstruktor Standardeinstellungen für beispielsweise Variablen angeben möchten, würde ich dies jedoch tun:
...oder auch:
... oder sogar: (vorzuziehen, aber genau dann, wenn es sich um unveränderliche Typen handelt!)
So können Sie vorgehen:
quelle
def __init__(self, num = None)
Die Verwendung von Klassenmitgliedern zur Angabe von Standardwerten funktioniert sehr gut, solange Sie darauf achten, dies nur mit unveränderlichen Werten zu tun. Wenn Sie versuchen, es mit einer Liste oder einem Diktat zu tun, wäre das ziemlich tödlich. Es funktioniert auch, wenn das Instanzattribut eine Referenz auf eine Klasse ist, solange der Standardwert None ist.
Ich habe gesehen, dass diese Technik sehr erfolgreich in Repoze verwendet wurde, einem Framework, das auf Zope ausgeführt wird. Der Vorteil hierbei ist nicht nur, dass beim Beibehalten Ihrer Klasse in der Datenbank nur die nicht standardmäßigen Attribute gespeichert werden müssen, sondern auch, wenn Sie dem Schema ein neues Feld hinzufügen müssen, dass alle vorhandenen Objekte das neue Feld mit seinem Standardfeld sehen Wert, ohne dass die gespeicherten Daten tatsächlich geändert werden müssen.
Ich finde, dass es auch in der allgemeineren Codierung gut funktioniert, aber es ist eine Stilsache. Verwenden Sie alles, womit Sie am glücklichsten sind.
quelle
Die Verwendung von Klassenmitgliedern für Standardwerte von Instanzvariablen ist keine gute Idee, und es ist das erste Mal, dass ich diese Idee überhaupt erwähnt habe. In Ihrem Beispiel funktioniert es, aber in vielen Fällen kann es fehlschlagen. Wenn der Wert beispielsweise veränderbar ist, wird durch Ändern in einer nicht geänderten Instanz der Standardwert geändert:
quelle
[]
dort geklont wurde;x.l
undy.l
sind sowohl böse Namen als auch verschiedene unmittelbare Werte, die mit demselben Referenten verbunden sind. (Sprachanwalt BegriffeSie können Klassenvariablen auch als Keine deklarieren, wodurch die Weitergabe verhindert wird. Dies ist nützlich, wenn Sie eine genau definierte Klasse benötigen und AttributeErrors verhindern möchten. Beispielsweise:
Auch wenn Sie Standardeinstellungen benötigen:
Befolgen Sie natürlich weiterhin die Informationen in den anderen Antworten zur Verwendung von veränderlichen und unveränderlichen Typen als Standard in
__init__
.quelle
Mit Datenklassen , einer in Python 3.7 hinzugefügten Funktion, gibt es jetzt eine weitere (recht bequeme) Möglichkeit, Standardwerte für Klasseninstanzen festzulegen. Der Dekorator
dataclass
generiert automatisch einige Methoden für Ihre Klasse, z. B. den Konstruktor. In der oben verlinkten Dokumentation heißt es: "Die in diesen generierten Methoden zu verwendenden Mitgliedsvariablen werden mithilfe von Anmerkungen vom Typ PEP 526 definiert ."In Anbetracht des Beispiels von OP könnten wir es folgendermaßen implementieren:
Beim Erstellen eines Objekts vom Typ dieser Klasse können wir den Wert optional überschreiben.
quelle