Es gibt mindestens fünf sechs Möglichkeiten. Der bevorzugte Weg hängt von Ihrem Anwendungsfall ab.
Option 1: Fügen Sie einfach eine asdict()Methode hinzu.
Basierend auf der Problembeschreibung würde ich sehr über die asdictArt und Weise nachdenken, wie andere Antworten vorgeschlagen werden. Dies liegt daran, dass Ihr Objekt anscheinend nicht wirklich eine Sammlung ist:
class Wharrgarbl(object):
...
def asdict(self):
return {'a': self.a, 'b': self.b, 'c': self.c}
Die Verwendung der anderen unten aufgeführten Optionen kann für andere verwirrend sein, es sei denn, es ist sehr offensichtlich, welche Objektelemente als Schlüssel-Wert-Paare iteriert oder nicht iteriert oder angegeben werden.
Option 1a: Erben Sie Ihre Klasse von 'typing.NamedTuple'(oder die meist gleichwertige 'collections.namedtuple') und verwenden Sie die für Sie bereitgestellte _asdictMethode .
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
Die Verwendung eines benannten Tupels ist eine sehr bequeme Möglichkeit, Ihrer Klasse mit minimalem Aufwand viele Funktionen hinzuzufügen, einschließlich einer _asdictMethode . Eine Einschränkung besteht jedoch darin, dass der NT, wie oben gezeigt, alle Mitglieder in seinen NT einbezieht _asdict.
Wenn es Mitglieder gibt, die Sie nicht in Ihr Wörterbuch aufnehmen möchten, müssen Sie das _asdictErgebnis ändern :
from typing import NamedTuple
class Wharrgarbl(NamedTuple):
a: str
b: str
c: str
sum: int = 6
version: str = 'old'
def _asdict(self):
d = super()._asdict()
del d['sum']
del d['version']
return d
Eine weitere Einschränkung besteht darin, dass NT schreibgeschützt ist. Dies kann wünschenswert sein oder nicht.
Option 2: Implementieren __iter__.
So zum Beispiel:
def __iter__(self):
yield 'a', self.a
yield 'b', self.b
yield 'c', self.c
Jetzt können Sie einfach tun:
dict(my_object)
Dies funktioniert, weil der dict()Konstruktor eine Iterable von (key, value)Paaren akzeptiert , um ein Wörterbuch zu erstellen . Bevor Sie dies tun, stellen Sie sich die Frage, ob das Iterieren des Objekts als eine Reihe von Schlüssel-Wert-Paaren auf diese Weise - obwohl dies für die Erstellung eines geeignet ist dict- in anderen Kontexten tatsächlich überraschend sein kann. Stellen Sie sich beispielsweise die Frage "Wie soll list(my_object)sich ... verhalten ?"
Beachten Sie außerdem, dass der direkte Zugriff auf Werte mithilfe der obj["a"]Syntax get item nicht funktioniert und das Entpacken von Schlüsselwortargumenten nicht funktioniert. Für diese müssten Sie das Mapping-Protokoll implementieren.
Option 3: Implementieren Sie das Zuordnungsprotokoll . Dies ermöglicht das Zugriffsverhalten nach Schlüssel, das dictohne Verwendung in a umgewandelt wird __iter__, und bietet auch das Entpackverhalten ( {**my_obj}) und das Entpackverhalten von Schlüsselwörtern, wenn alle Schlüssel Zeichenfolgen ( dict(**my_obj)) sind.
Das Zuordnungsprotokoll erfordert, dass Sie (mindestens) zwei Methoden zusammen bereitstellen: keys()und __getitem__.
class MyKwargUnpackable:
def keys(self):
return list("abc")
def __getitem__(self, key):
return dict(zip("abc", "one two three".split()))[key]
Jetzt können Sie Dinge tun wie:
>>> m=MyKwargUnpackable()
>>> m["a"]
'one'
>>> dict(m)
{'a': 'one', 'b': 'two', 'c': 'three'}
>>> dict(**m)
{'a': 'one', 'b': 'two', 'c': 'three'}
Wie oben erwähnt, können Sie, wenn Sie eine ausreichend neue Python-Version verwenden, Ihr Mapping-Protokoll-Objekt auch in ein Wörterbuch-Verständnis wie dieses entpacken (und in diesem Fall ist es nicht erforderlich, dass Ihre Schlüssel Zeichenfolgen sind):
>>> {**m}
{'a': 'one', 'b': 'two', 'c': 'three'}
Beachten Sie, dass das Zuordnungsprotokoll Vorrang vor der __iter__Methode hat, wenn ein Objekt dictdirekt in ein Objekt umgewandelt wird (ohne kwarg-Entpacken zu verwenden, dh dict(m)). Es ist also möglich - und manchmal auch bequem -, das Objekt anders verhalten zu lassen, wenn es als iterable (z. B. list(m)) verwendet wird, als wenn es in a dict( dict(m)) umgewandelt wird.
HERVORZUHEBEN : Nur weil Sie das MappingProtokoll verwenden können, bedeutet nicht , dass Sie sollten dies tun . Ist es tatsächlich sinnvoll, Ihr Objekt als Satz von Schlüssel-Wert-Paaren oder als Schlüsselwortargumente und -werte weiterzugeben? Ist der Zugriff per Schlüssel - genau wie bei einem Wörterbuch - wirklich sinnvoll?
Wenn die Antwort auf diese Fragen Ja lautet , ist es wahrscheinlich eine gute Idee, die nächste Option in Betracht zu ziehen.
Option 4: Sehen Sie sich die Verwendung des 'collections.abcModuls an .
Das Erben Ihrer Klasse von 'collections.abc.Mappingoder das 'collections.abc.MutableMappingSignal an andere Benutzer, dass Ihre Klasse in jeder Hinsicht eine Zuordnung * ist und sich voraussichtlich so verhält.
Sie können Ihr Objekt immer noch dictso bearbeiten, wie Sie es benötigen, aber es gibt wahrscheinlich wenig Grund, dies zu tun. Aufgrund der Typisierung von Entendict wäre es die meiste Zeit nur ein zusätzlicher unnötiger Schritt , sich die Mühe zu machen, Ihr Mapping-Objekt in ein zu verwandeln.
Diese Antwort könnte auch hilfreich sein.
Wie in den Kommentaren unten erwähnt: Es ist erwähnenswert, dass dies auf abc-Weise Ihre Objektklasse im Wesentlichen in eine dictähnliche Klasse verwandelt (vorausgesetzt, Sie verwenden MutableMappingund nicht die schreibgeschützte MappingBasisklasse). Alles, was Sie tun dictkönnten, könnten Sie mit Ihrem eigenen Klassenobjekt tun. Dies kann wünschenswert sein oder auch nicht.
Beachten Sie auch die numerischen Abcs im numbersModul:
https://docs.python.org/3/library/numbers.html
Da Sie Ihr Objekt auch auf ein Objekt übertragen, intist es möglicherweise sinnvoller, Ihre Klasse in eine vollwertige Klasse zu verwandeln, intsodass das Casting nicht erforderlich ist.
Option 5: Sehen Sie sich die Verwendung des dataclassesModuls an (nur Python 3.7), das eine praktische asdict()Dienstprogrammmethode enthält.
from dataclasses import dataclass, asdict, field, InitVar
@dataclass
class Wharrgarbl(object):
a: int
b: int
c: int
sum: InitVar[int]
version: InitVar[str] = "old"
def __post_init__(self, sum, version):
self.sum = 6
self.version = str(version)
Jetzt können Sie dies tun:
>>> asdict(Wharrgarbl(1,2,3,4,"X"))
{'a': 1, 'b': 2, 'c': 3}
Option 6: Verwenden Sie typing.TypedDictdiese Option , die in Python 3.8 hinzugefügt wurde .
HINWEIS: Option 6 ist wahrscheinlich NICHT das, wonach das OP oder andere Leser, die auf dem Titel dieser Frage basieren, suchen. Siehe zusätzliche Kommentare unten.
class Wharrgarbl(TypedDict):
a: str
b: str
c: str
Bei Verwendung dieser Option ist das resultierende Objekt adict (Hervorhebung: es ist kein a Wharrgarbl). Es gibt überhaupt keinen Grund, es auf ein Diktat zu "übertragen" (es sei denn, Sie machen eine Kopie).
Und da das Objekt a istdict , ist die Initialisierungssignatur mit der von identisch dictund akzeptiert als solche nur Schlüsselwortargumente oder ein anderes Wörterbuch.
>>> w = Wharrgarbl(a=1,b=2,b=3)
>>> w
{'a': 1, 'b': 2, 'c': 3}
>>> type(w)
<class 'dict'>
Hervorgehoben : Die obige "Klasse" Wharrgarblist eigentlich überhaupt keine neue Klasse. Es ist einfach syntaktischer Zucker zum Erstellen typisierter dictObjekte mit Feldern unterschiedlicher Typen für die Typprüfung.
Daher kann diese Option sehr praktisch sein, um Lesern Ihres Codes (und auch einem Typprüfer wie mypy) zu signalisieren, dass von einem solchen dictObjekt bestimmte Schlüssel mit bestimmten Werttypen erwartet werden.
Dies bedeutet jedoch, dass Sie beispielsweise keine anderen Methoden hinzufügen können, obwohl Sie Folgendes versuchen können:
class MyDict(TypedDict):
def my_fancy_method(self):
return "world changing result"
... aber es wird nicht funktionieren:
>>> MyDict().my_fancy_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'my_fancy_method'
* "Mapping" ist zum Standard "Namen" des dictEntentyps geworden