Ich sehe Muster wie
def __init__(self, x, y, z):
...
self.x = x
self.y = y
self.z = z
...
ziemlich häufig, oft mit viel mehr Parametern. Gibt es eine gute Möglichkeit, diese Art von langwieriger Wiederholung zu vermeiden? Sollte die Klasse namedtuple
stattdessen erben ?
__slots__
für diesen Zweck verwenden ; Es ist leicht unpythonisch (ausführlicher, um Speichereinsparungen zu erzielen), aber ich mag es weitgehend, um das Risiko einer automatischen Belebung eines ganz neuen Attributs zu vermeiden, wenn ich den Namen tippe.ini <shortcut> x, y, z): <shortcut>
und Sie sind fertig.Antworten:
Bearbeiten: Wenn Sie Python 3.7+ haben, verwenden Sie einfach Datenklassen
Eine Dekorationslösung, die die Signatur behält:
quelle
signature
Haftungsausschluss: Es scheint, dass mehrere Personen besorgt sind, diese Lösung vorzustellen, daher werde ich einen sehr klaren Haftungsausschluss geben. Sie sollten diese Lösung nicht verwenden. Ich gebe es nur als Information, damit Sie wissen, dass die Sprache dazu in der Lage ist. Der Rest der Antwort zeigt nur die Sprachfähigkeiten und unterstützt sie nicht auf diese Weise.
Es ist eigentlich nichts Falsches daran, Parameter explizit in Attribute zu kopieren. Wenn Sie zu viele Parameter im ctor haben, wird dies manchmal als Codegeruch angesehen, und Sie sollten diese Parameter möglicherweise in weniger Objekte gruppieren. In anderen Fällen ist es notwendig und es ist nichts falsch daran. Auf jeden Fall ist es der richtige Weg, dies explizit zu tun.
Da Sie jedoch fragen, wie dies getan werden kann (und nicht, ob es getan werden soll), lautet eine Lösung:
quelle
self.__dict__.update(kwargs)
etwas pythonischer sein könnteA.__init__
aufgezeichnet wird, welche Argumente tatsächlich erwartet werden, und keine Fehlerprüfung auf falsch eingegebene Argumentnamen erfolgt.kwargs
Sie offen für das Äquivalent eines SQL-Injection-Angriffs. Wenn Ihr Objekt eine Methode mit dem Namen hatmy_method
und Sie ein Argument mit dem Namenmy_method
an den Konstruktor undupdate()
das Wörterbuch übergeben, haben Sie die Methode einfach überschrieben.Wie andere bereits erwähnt haben, ist die Wiederholung nicht schlecht, aber in einigen Fällen kann ein benanntes Tupel gut zu dieser Art von Problem passen. Dies vermeidet die Verwendung von Einheimischen () oder Kwargs, was normalerweise eine schlechte Idee ist.
Ich habe eine begrenzte Verwendung dafür gefunden, aber Sie können ein benanntes Tupel wie bei jedem anderen Objekt erben (Beispiel wird fortgesetzt):
quelle
properties
Methode als gerecht geschrieben werden. Diesreturn tuple(self)
ist besser zu warten, wenn in Zukunft mehr Felder zur Definition des benannten Tupels hinzugefügt werden.XYZ = namedtuple("XYZ", "x y z")
funktioniert genauso gut.namedtuple
s oft genau für diesen Zweck, insbesondere in mathematischem Code, in dem eine Funktion möglicherweise stark parametrisiert ist und eine Reihe von Koeffizienten aufweist, die nur zusammen Sinn ergeben.namedtuple
ist, dass sie schreibgeschützt sind. Sie können nichtabc.x += 1
oder so etwas tun .explizit ist besser als implizit ... so sicher, dass Sie es prägnanter gestalten können:
Die bessere Frage ist, sollten Sie?
... das heißt, wenn Sie ein benanntes Tupel möchten, würde ich die Verwendung eines benannten Tupels empfehlen (denken Sie daran, dass an Tupel bestimmte Bedingungen geknüpft sind) ... vielleicht möchten Sie ein geordnetes Diktat oder sogar nur ein Diktat ...
quelle
if k != "self":
könnte einif v is not self:
billiger Identitätstest anstelle eines Zeichenfolgenvergleichs verwendet werden. Ich nehme an, technisch__init__
könnte ein zweites Mal nach dem Bau aufgerufen undself
als nachfolgendes Argument übergeben werden, aber ich möchte wirklich nicht darüber nachdenken, welche Art von Monster das tun würde. :-)locals
: annimmtset_fields_from_locals(locals())
. Dann ist es nicht länger als die magischeren Dekorationslösungen.Um die
gruszczy
Antwort zu erweitern , habe ich ein Muster wie das folgende verwendet:Ich mag diese Methode, weil es:
super().__init(...)
)X.__init__
Vor Python 3.6 gibt dies keine Kontrolle über die Reihenfolge, in der die Attribute festgelegt werden. Dies kann ein Problem sein, wenn einige Attribute Eigenschaften mit Setzern sind, die auf andere Attribute zugreifen.
Es könnte wahrscheinlich ein bisschen verbessert werden, aber ich bin der einzige Benutzer meines eigenen Codes, sodass ich mir keine Sorgen über irgendeine Form der Eingabesanierung mache. Vielleicht
AttributeError
wäre ein passender.quelle
Sie könnten auch tun:
Natürlich müssten Sie das
inspect
Modul importieren .quelle
Dies ist eine Lösung ohne zusätzliche Importe.
Hilfsfunktion
Eine kleine Hilfsfunktion macht es bequemer und wiederverwendbarer:
Anwendung
Sie müssen es aufrufen mit
locals()
:Prüfung
Ausgabe:
Ohne Veränderung
locals()
Wenn Sie nicht ändern möchten,
locals()
verwenden Sie diese Version:quelle
locals()
sollte nicht geändert werden (dies kann sich auf den Interpreter auswirken, in Ihrem Fallself
aus dem Bereich der aufrufenden Funktion entfernen )self
ist noch verfügbar in__init__
.Eine interessante Bibliothek, die dies handhabt (und viele andere Boilerplates vermeidet), ist attrs . Ihr Beispiel könnte zum Beispiel darauf reduziert werden (vorausgesetzt, die Klasse heißt
MyClass
):Sie brauchen nicht einmal
__init__
mehr eine Methode, es sei denn, sie erledigt auch andere Dinge. Hier ist eine schöne Einführung von Glyph Lefkowitz .quelle
attr
überflüssig gemachtdataclasses
?Meine 0,02 $. Es ist sehr nah an Joran Beasleys Antwort, aber eleganter:
Zusätzlich kann die Antwort von Mike Müller (die beste nach meinem Geschmack) mit dieser Technik reduziert werden:
Und der gerade Anruf
auto_init(locals())
von Ihrem__init__
quelle
locals()
sollte nicht geändert werden (undefiniertes Verhalten)Es ist eine natürliche Art, Dinge in Python zu tun. Versuchen Sie nicht, etwas Klügeres zu erfinden, da dies zu übermäßig cleverem Code führt, den niemand in Ihrem Team verstehen wird. Wenn du ein Teamplayer sein willst und es dann so weiter schreibst.
quelle
Ab Python 3.7
In Python 3.7 können Sie (ab) den
dataclass
Dekorator verwenden, der imdataclasses
Modul verfügbar ist . Aus der Dokumentation:Wenn Ihre Klasse groß und komplex ist, kann es unangemessen sein, a zu verwenden
dataclass
. Ich schreibe dies am Tag der Veröffentlichung von Python 3.7.0, daher sind die Verwendungsmuster noch nicht gut etabliert.quelle