Gibt es eine Möglichkeit, eine C-ähnliche Struktur in Python bequem zu definieren? Ich bin es leid Dinge zu schreiben wie:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
MyStruct = namedtuple("MyStruct", "field1 field2 field3")
pandas.Series(a=42).a
sollte es tun, wenn Sie ein Datenwissenschaftler sind ...Antworten:
Verwenden Sie ein benanntes Tupel , das dem Sammlungsmodul in der Standardbibliothek in Python 2.6 hinzugefügt wurde . Es ist auch möglich, das benannte Tupelrezept von Raymond Hettinger zu verwenden, wenn Sie Python 2.4 unterstützen müssen.
Es ist gut für Ihr grundlegendes Beispiel, deckt aber auch eine Reihe von Randfällen ab, auf die Sie später möglicherweise stoßen. Ihr Fragment oben würde geschrieben werden als:
Der neu erstellte Typ kann folgendermaßen verwendet werden:
Sie können auch benannte Argumente verwenden:
quelle
Update : Datenklassen
Mit der Einführung von Datenklassen in Python 3.7 kommen wir uns sehr nahe.
Das folgende Beispiel ähnelt dem folgenden NamedTuple- Beispiel, das resultierende Objekt ist jedoch veränderbar und lässt Standardwerte zu.
Dies funktioniert gut mit dem neuen Typisierungsmodul, falls Sie spezifischere Typanmerkungen verwenden möchten.
Ich habe verzweifelt darauf gewartet! Wenn Sie mich fragen, Datenklassen und die neue NamedTuple Erklärung, mit der kombinierten Eingabe - Modul sind ein Geschenk des Himmels!
Verbesserte NamedTuple-Deklaration
Seit Python 3.6 ist es ziemlich einfach und schön geworden (IMHO), solange man mit Unveränderlichkeit leben kann .
Eine neue Art und Weise NamedTuples deklarieren wurde eingeführt, die für ermöglicht Typenannotationen auch:
quelle
dataclass
Modul ist neu in Python 3.7, aber Sie könnenpip install dataclasses
. Es ist der Backport auf Python 3.6. pypi.org/project/dataclasses/#description@dataclass
Die Details sind hier: pypi.org/project/dataclasses/#descriptionSie können ein Tupel für viele Dinge verwenden, bei denen Sie eine Struktur in C verwenden würden (z. B. x-, y-Koordinaten oder RGB-Farben).
Für alles andere können Sie ein Wörterbuch oder eine Dienstprogrammklasse wie diese verwenden :
Ich denke, die "endgültige" Diskussion ist hier in der veröffentlichten Version des Python-Kochbuchs.
quelle
TypeError: this constructor takes no arguments
Vielleicht suchen Sie nach Strukturen ohne Konstruktoren:
quelle
class Sample:
tun nichts sofort; Sie setzen Klassenattribute. Auf diese kann immer zugegriffen werden als zSample.name
.s1
unds2
zur Laufzeit. Sofern nicht anders verboten, können Sie dasname
Attribut jederzeit für jede Instanz einer Klasse hinzufügen oder ändern , unabhängig davon, ob die Klasse über einname
Attribut verfügt oder nicht . Das wahrscheinlich größte funktionale Problem dabei ist, dass sich verschiedene Instanzen derselben Klasse unterschiedlich verhalten, je nachdem, ob Sie festgelegt habenname
. Wenn Sie aktualisierenSample.name
, geben alle Objekte ohne explizit festgelegtename
Eigenschaft die neue zurückname
.self
Schlüsselwörter und eine Konstruktorzeile zu sparen, wenn Sie mich fragen. Ich würde mich freuen, wenn Jose seine Antwort bearbeiten könnte, um eine Warnmeldung über das Risiko des versehentlichen Teilens von Werten über Instanzen hinweg hinzuzufügen.Wie wäre es mit einem Wörterbuch?
Etwas wie das:
Dann können Sie dies verwenden, um Werte zu manipulieren:
Und die Werte müssen keine Zeichenfolgen sein. Sie können so ziemlich jedes andere Objekt sein.
quelle
pt3.w = 1 print pt3.w
In einer Sprache mit Diktaten ist es besser, sie zu verwenden, insbesondere für Objekte, die serialisiert werden, da Sie import json automatisch verwenden können, um sie und andere Serialisierungsbibliotheken zu speichern, solange Sie keine Seltsamkeiten haben Zeug in deinem Diktat. Dicts sind die Lösung, um Daten und Logik getrennt zu halten. Sie sind besser als Strukturen für Personen, die keine benutzerdefinierten Serialisierungs- und Unserialisierungsfunktionen schreiben und keine nicht tragbaren Serialisierer wie pickle verwenden möchten.Sie können mit einem Wörterbuch auf die Felder einer Klasse zugreifen, da die Felder einer Klasse, ihre Methoden und alle ihre Eigenschaften intern mithilfe von Dicts gespeichert werden (zumindest in CPython).
... was uns zu Ihrem zweiten Kommentar führt. Zu glauben, dass Python-Diktate "schwer" sind, ist ein äußerst nicht-pythonistisches Konzept. Und das Lesen solcher Kommentare tötet meinen Python Zen. Das ist nicht gut.
Sie sehen, wenn Sie eine Klasse deklarieren, erstellen Sie tatsächlich einen ziemlich komplexen Wrapper um ein Wörterbuch. Wenn überhaupt, fügen Sie also mehr Overhead hinzu als mit einem einfachen Wörterbuch. Ein Overhead, der übrigens ohnehin bedeutungslos ist. Wenn Sie an leistungskritischen Anwendungen arbeiten, verwenden Sie C oder etwas anderes.
quelle
self['member']
ist 3 Zeichen länger alsself.member
und diese Zeichen sind alle relativ unhandgelenkfreundlich.Sie können die C-Struktur, die in der Standardbibliothek verfügbar ist, in Unterklassen unterteilen. Das Modul ctypes stellt eine Strukturklasse bereit . Das Beispiel aus den Dokumenten:
quelle
Ich möchte auch eine Lösung hinzufügen, die Slots verwendet :
Überprüfen Sie auf jeden Fall die Dokumentation auf Slots, aber eine kurze Erklärung der Slots ist, dass Python sagt: "Wenn Sie diese Attribute und nur diese Attribute in der Klasse sperren können, verpflichten Sie sich, dass Sie nach der Klasse keine neuen Attribute hinzufügen." wird instanziiert (ja, Sie können einer Klasseninstanz neue Attribute hinzufügen, siehe Beispiel unten), dann werde ich die große Speicherzuordnung beseitigen, die das Hinzufügen neuer Attribute zu einer Klasseninstanz ermöglicht, und genau das verwenden, was ich für diese Slots benötige Attribute . "
Beispiel für das Hinzufügen von Attributen zur Klasseninstanz (daher werden keine Slots verwendet):
Ausgabe: 8
Beispiel für den Versuch, Attribute zu Klasseninstanzen hinzuzufügen, in denen Slots verwendet wurden:
Ausgabe: AttributeError: Das Objekt 'Point' hat kein Attribut 'z'.
Dies kann effektiv als Struktur funktionieren und benötigt weniger Speicher als eine Klasse (wie eine Struktur, obwohl ich nicht genau untersucht habe, wie viel). Es wird empfohlen, Slots zu verwenden, wenn Sie eine große Anzahl von Instanzen des Objekts erstellen und keine Attribute hinzufügen müssen. Ein Punktobjekt ist ein gutes Beispiel dafür, da es wahrscheinlich ist, dass man viele Punkte instanziieren kann, um einen Datensatz zu beschreiben.
quelle
Sie können die Init-Parameter auch nach Position an die Instanzvariablen übergeben
quelle
Point3dStruct
Deklaration ändern ,Point3dStruct(5, 6)
funktioniert dies nicht wie erwartet. Es ist seltsam, dass dies in allen 6 Jahren niemand geschrieben hat.print
>print()
undattrs[n]
>next(attrs)
(Filter ist jetzt ein eigenes iterierbares Objekt und erfordertnext
).Immer wenn ich ein " Sofortdatenobjekt brauche, das sich auch wie ein Wörterbuch verhält" (ich denke nicht an C-Strukturen!), Denke ich an diesen niedlichen Hack:
Jetzt können Sie einfach sagen:
Perfekt für Zeiten, in denen Sie eine "Datentasche benötigen, die KEINE Klasse ist" und in der Namedtuples unverständlich sind ...
quelle
Sie greifen auf folgende Weise auf die C-Style-Struktur in Python zu.
Wenn Sie nur das Objekt cstruct verwenden möchten
Wenn Sie ein Array von Objekten von cstruct erstellen möchten
Hinweis: Verwenden Sie anstelle des Namens 'cstruct' Ihren Strukturnamen anstelle von var_i, var_f, var_str. Definieren Sie die Mitgliedsvariable Ihrer Struktur.
quelle
Einige der Antworten hier sind sehr ausführlich. Die einfachste Option, die ich gefunden habe, ist (von: http://norvig.com/python-iaq.html ):
Initialisierung:
Hinzufügen von mehr:
edit: Dieses Beispiel wurde leider noch nicht weiter unten angezeigt.
quelle
Dies mag etwas spät sein, aber ich habe eine Lösung mit Python Meta-Classes (Dekorator-Version unten auch) erstellt.
Wann
__init__
es zur Laufzeit aufgerufen wird, erfasst es jedes der Argumente und ihren Wert und weist sie Ihrer Klasse als Instanzvariablen zu. Auf diese Weise können Sie eine strukturähnliche Klasse erstellen, ohne jeden Wert manuell zuweisen zu müssen.In meinem Beispiel gibt es keine Fehlerprüfung, daher ist es einfacher zu folgen.
Hier ist es in Aktion.
Ich habe es auf reddit gepostet und / u / matchu hat eine Dekorationsversion gepostet, die sauberer ist. Ich würde Sie ermutigen, es zu verwenden, es sei denn, Sie möchten die Metaklassenversion erweitern.
quelle
Ich habe einen Dekorator geschrieben, den Sie für jede Methode verwenden können, damit alle übergebenen Argumente oder Standardeinstellungen der Instanz zugewiesen werden.
Eine kurze Demonstration. Beachten Sie, dass ich ein Positionsargument
a
, den Standardwert fürb
und ein benanntes Argument verwendec
. Ich drucke dann alle 3 Verweise ausself
, um zu zeigen, dass sie ordnungsgemäß zugewiesen wurden, bevor die Methode eingegeben wird.Beachten Sie, dass mein Dekorateur mit jeder Methode arbeiten sollte, nicht nur
__init__
.quelle
Ich sehe diese Antwort hier nicht, also werde ich sie wohl hinzufügen, da ich gerade Python lehne und sie gerade entdeckt habe. Das Python-Tutorial (in diesem Fall Python 2) enthält das folgende einfache und effektive Beispiel:
Das heißt, ein leeres Klassenobjekt wird erstellt, dann instanziiert und die Felder werden dynamisch hinzugefügt.
Das Beste daran ist, dass es wirklich einfach ist. Der Nachteil ist, dass es nicht besonders selbstdokumentierend ist (die beabsichtigten Mitglieder sind an keiner Stelle in der Klassendefinition aufgeführt), und nicht gesetzte Felder können beim Zugriff Probleme verursachen. Diese beiden Probleme können gelöst werden durch:
Jetzt können Sie auf einen Blick sehen, welche Felder das Programm erwartet.
Beide sind anfällig für Tippfehler,
john.slarly = 1000
werden erfolgreich sein. Trotzdem funktioniert es.quelle
Hier ist eine Lösung, die eine Klasse (nie instanziiert) verwendet, um Daten zu speichern. Ich mag es, dass dieser Weg sehr wenig Eingabe erfordert und keine zusätzlichen Pakete usw. erfordert .
Sie können später nach Bedarf weitere Felder hinzufügen:
Um die Werte zu erhalten, wird wie gewohnt auf die Felder zugegriffen:
quelle
Ich persönlich mag diese Variante auch. Es erweitert die Antwort von @ dF .
Es werden zwei Initialisierungsmodi unterstützt (die gemischt werden können):
Außerdem druckt es schöner:
quelle
Die folgende Lösung für eine Struktur ist von der Implementierung von namedtuple und einigen der vorherigen Antworten inspiriert. Im Gegensatz zum namedtuple ist es jedoch in seinen Werten veränderbar, aber wie die Struktur im c-Stil, die in den Namen / Attributen unveränderlich ist, was eine normale Klasse oder ein Diktat nicht ist.
Verwendungszweck:
quelle
Genau für diesen Zweck gibt es ein Python-Paket. siehe cstruct2py
cstruct2py
ist eine reine Python-Bibliothek zum Generieren von Python-Klassen aus C-Code und zum Packen und Entpacken von Daten. Die Bibliothek kann C-Headres (Strukturen, Vereinigungen, Aufzählungen und Arrays-Deklarationen) analysieren und in Python emulieren. Die generierten Python-Klassen können die Daten analysieren und packen.Zum Beispiel:
Zuerst müssen wir die pythonischen Strukturen erzeugen:
Jetzt können wir alle Namen aus dem C-Code importieren:
Das können wir auch direkt machen:
Verwenden von Typen und Definitionen aus dem C-Code
Die Ausgabe wird sein:
Für den Klonlauf
cstruct2py
:quelle
Ich denke, Python-Strukturwörterbuch ist für diese Anforderung geeignet.
quelle
https://stackoverflow.com/a/32448434/159695 funktioniert in Python3 nicht.
https://stackoverflow.com/a/35993/159695 funktioniert in Python3.
Und ich erweitere es, um Standardwerte hinzuzufügen.
quelle
Wenn Sie keine 3.7 für @dataclass haben und Veränderbarkeit benötigen, funktioniert der folgende Code möglicherweise für Sie. Es ist ziemlich selbstdokumentierend und IDE-freundlich (automatisch vervollständigen), verhindert das zweimalige Schreiben von Dingen, ist leicht erweiterbar und es ist sehr einfach zu testen, ob alle Instanzvariablen vollständig initialisiert sind:
quelle
Hier ist ein schneller und schmutziger Trick:
Wie funktioniert es? Es verwendet einfach die eingebaute Klasse
Warning
(abgeleitet vonException
) und verwendet sie so, wie Sie es selbst definiert haben.Die guten Punkte sind, dass Sie nichts importieren oder definieren müssen, dass "Warnung" ein Kurzname ist und dass es auch klar macht, dass Sie etwas schmutziges tun, das nicht anderswo als in einem kleinen Skript von Ihnen verwendet werden sollte.
Übrigens habe ich versucht, etwas noch einfacheres zu finden
ms = object()
, konnte es aber nicht (dieses letzte Beispiel funktioniert nicht). Wenn Sie eine haben, bin ich interessiert.quelle
Der beste Weg, dies zu tun, war die Verwendung einer benutzerdefinierten Wörterbuchklasse, wie in diesem Beitrag erläutert: https://stackoverflow.com/a/14620633/8484485
Wenn Unterstützung für die automatische Vervollständigung von iPython benötigt wird, definieren Sie einfach die Funktion dir () wie folgt :
Sie definieren dann Ihre Pseudostruktur wie folgt: (Diese ist verschachtelt)
Sie können dann wie folgt auf die Werte in my_struct zugreifen:
print(my_struct.com1.inst)
=>
[5]
quelle
NamedTuple ist komfortabel. aber dort teilt niemand die Leistung und Speicherung.
Wenn Sie
__dict__
nicht verwenden, wählen Sie bitte zwischen__slots__
(höhere Leistung und Speicherplatz) undNamedTuple
(zum Lesen und Verwenden freigegeben).Sie können diesen Link ( Verwendung von Slots ) überprüfen , um weitere
__slots__
Informationen zu erhalten.quelle