Wie wandle ich in Python ein Klassenobjekt in ein Diktat um?

85

Nehmen wir an, ich habe eine einfache Klasse in Python

class Wharrgarbl(object):
    def __init__(self, a, b, c, sum, version='old'):
        self.a = a
        self.b = b
        self.c = c
        self.sum = 6
        self.version = version

    def __int__(self):
        return self.sum + 9000

    def __what_goes_here__(self):
        return {'a': self.a, 'b': self.b, 'c': self.c}

Ich kann es sehr leicht in eine ganze Zahl umwandeln

>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> int(w)
9006

Was toll ist! Aber jetzt möchte ich es auf ähnliche Weise zu einem Diktat machen

>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> dict(w)
{'a': 'one', 'c': 'three', 'b': 'two'}

Was muss ich definieren, damit dies funktioniert? Ich habe versucht , beide ersetzen __dict__und dictfür __what_goes_here__, sondern dict(w)in einer Folge TypeError: Wharrgarbl object is not iterablein beiden Fällen. Ich denke nicht, dass es das Problem lösen wird, wenn man die Klasse einfach iterierbar macht. Ich habe auch versucht, viele Brillen mit so vielen verschiedenen Formulierungen von "Python Cast Object to Dict" zu erstellen, wie ich mir vorstellen konnte, konnte aber nichts Relevantes finden: {

Ebenfalls! Beachten Sie, wie Aufruf w.__dict__nicht tun , was ich will , denn es geht zu enthalten w.versionund w.sum. Ich möchte die Besetzung auf dictdie gleiche Weise anpassen, wie ich die Besetzung intmithilfe von anpassen kann def int(self).

Ich weiß, dass ich so etwas einfach machen kann

>>> w.__what_goes_here__()
{'a': 'one', 'c': 'three', 'b': 'two'}

Aber ich gehe davon aus, dass es einen pythonischen Weg gibt, um dict(w)Arbeit zu machen , da es die gleiche Art von Dingen ist wie int(w)oder str(w). Wenn es keinen pythonischeren Weg gibt, ist das auch in Ordnung, dachte ich nur, ich würde fragen. Oh! Ich denke, da es wichtig ist, ist dies für Python 2.7, aber auch Super-Bonuspunkte für eine 2.4 alte und kaputte Lösung.

Es gibt noch eine andere Frage: Überladen von __dict __ () in der Python-Klasse, die dieser ähnlich ist, aber möglicherweise so unterschiedlich ist, dass dies kein Duplikat ist. Ich glaube, dass OP fragt, wie alle Daten in seinen Klassenobjekten als Wörterbücher umgewandelt werden sollen. Ich suche nach einem individuelleren Ansatz, indem ich nicht möchte, dass alles im __dict__Wörterbuch enthalten ist, das von zurückgegeben wird dict(). Etwas wie öffentliche oder private Variablen kann ausreichen, um zu erklären, wonach ich suche. Die Objekte speichern einige Werte, die in Berechnungen verwendet werden und die ich nicht in den resultierenden Wörterbüchern anzeigen muss / möchte.

UPDATE: Ich habe mich für die asdictvorgeschlagene Route entschieden, aber es war eine schwierige Entscheidung, die Antwort auf die Frage auszuwählen. Sowohl @RickTeachey als auch @ jpmc26 lieferten die Antwort, mit der ich rollen werde, aber der erstere hatte mehr Informationen und Optionen und landete ebenfalls auf dem gleichen Ergebnis und wurde mehr positiv bewertet, also ging ich mit. Überall Upvotes und danke für die Hilfe. Ich habe lange und hart am Stackoverflow gelauert und versuche, meine Zehen mehr ins Wasser zu bekommen.

Vorliebe
quelle
1
hast du das schon gesehen docs.python.org/3/reference/…
Garrett R
@ GarrettR Es ist hilfreich, aber es gibt nicht wirklich viel Einblick in dieses spezielle Problem.
Zizouz212
Mögliches Duplikat von Overloading __dict __ () in der Python-Klasse
Rick unterstützt Monica
@ RickTeachey es ist sicherlich ähnlich wie die Frage Überladen ..., obwohl ich nach einer anpassbareren Diktatdarstellung suche. Zum Beispiel kann das Objekt Dinge speichern, die ich im Diktat nicht sehen möchte.
Vorliebe
Ihre Frage ist irreführend formuliert. Sie möchten Ihr Objekt nicht konvertieren oder in eine diktierte Darstellung umwandeln (sodass Sie das Objekt vollständig wiederherstellen können, wenn Sie es zurückkonvertieren). Sie möchten nur eine Diktatdarstellungsansicht für (beispielsweise) öffentliche Instanzvariablen erstellen.
smci

Antworten:

117

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)  # cast to dict directly
{'a': 'one', 'b': 'two', 'c': 'three'}
>>> dict(**m)  # unpack as kwargs
{'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]  # note: InitVar will exclude this from the dict
    version: InitVar[str] = "old"

    def __post_init__(self, sum, version):
        self.sum = 6  # this looks like an OP mistake?
        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

Rick unterstützt Monica
quelle
1
Dies ist ein Weg, um den vom OP gewünschten Effekt zu erzielen, aber Sie sollten vielleicht klarstellen, dass er andere Effekte hat, z. B. for k, v in my_objectauch aktiviert wird.
zwol
@ RickTeachey Ich sehe, worauf du mit dem Asdict Point fährst. Ich brauche die Objekte sicher nicht, um iterierbar zu sein.
Vorliebe
Warum wir einfach die vars-Funktion verwenden können, wie in anderen Linkhttps erwähnt: //stackoverflow.com/questions/61517/python-dictionary-from-an-objects-fields. Vermisse ich etwas in dieser Frage?
Benutzer
@user Die Frage des OP wollte nur Mitglieder a, bund cin den dict. Die varsFunktion gibt ein Wörterbuch mit ALLEN Objektelementen zurück, einschließlich derjenigen, die nicht gewünscht wurden: sumund version. In einigen Fällen varswird es funktionieren, aber meiner Erfahrung nach ist es keine wirklich idiomatische Python. Normalerweise sind die Leute expliziter und sagen "Ich werfe jetzt mein Objekt in ein Wörterbuch", indem sie z obj.asdict(). Mit varsist es normalerweise eher so, obj_kwargs = vars(obj)gefolgt von MyObject(**obj_kwargs). Mit anderen Worten: varswird meistens zum Kopieren von Objekten verwendet.
Rick unterstützt Monica
Wie wäre es mit einer Methode, die zurückgibt self.__dict__?
user32882
17

Es gibt keine magische Methode, die macht, was Sie wollen. Die Antwort ist einfach, es angemessen zu benennen. asdictist eine vernünftige Wahl für eine einfache Umstellung auf dict, vor allem inspiriert von namedtuple. Ihre Methode enthält jedoch offensichtlich eine spezielle Logik, die aus diesem Namen möglicherweise nicht sofort ersichtlich ist. Sie geben nur eine Teilmenge des Klassenstatus zurück. Umso besser, wenn Sie einen etwas ausführlicheren Namen finden, der die Konzepte klar kommuniziert.

Andere Antworten schlagen die Verwendung vor __iter__, aber wenn Ihr Objekt nicht wirklich iterierbar ist (eine Reihe von Elementen darstellt), macht dies wirklich wenig Sinn und stellt einen unangenehmen Missbrauch der Methode dar. Die Tatsache, dass Sie einen Teil des Klassenzustands herausfiltern möchten, macht diesen Ansatz noch zweifelhafter.

jpmc26
quelle
Ja, ich versuche, eine Teilmenge des gesamten Zustands der Klasse, die relevanten Werte, zurückzugeben. Ich habe einige "versteckte" Werte gespeichert, die die Berechnung / Vergleiche usw. beschleunigen, aber sie sind nichts, was ein Mensch sehen oder damit spielen möchte, und sie repräsentieren auch nicht wirklich das Objekt selbst.
Vorliebe
@ tr3buchet In Ihrem Beispielcode werden diese Werte an den Initialisierer übergeben . Ist das in Ihrem echten Code so? Es scheint seltsam, dass zwischengespeicherte Berechnungen als Argumente übergeben werden.
jpmc26
Überhaupt nicht, ich habe es nur getan, um ein Beispiel zu liefern
Vorliebe für den
Ich möchte nur darauf hinweisen, dass die Dokumente die Verwendung zu dulden scheinen, __iter__wie andere Antworten vorgeschlagen haben: "Bei Zuordnungen sollte sie über die Schlüssel des Containers iterieren und auch als Methode iterkeys () verfügbar gemacht werden."
Dbenton
@dbenton Das ist nicht das, was das OP tut oder was die anderen Antworten empfehlen. Das OP-Objekt ist kein "Container", der in diesem Zusammenhang grundsätzlich als Synonym für Sammlung verwendet wird. Das OP-Objekt ist auch nicht das, was normalerweise mit Mapping gemeint ist. Ein Mapping hat eine beliebige Anzahl von Schlüsseln und Werten und sollte die MappingBasisklasse erweitern. Ein Objekt mit bestimmten benannten Attributen fällt nicht in diese Kategorie.
jpmc26
11

so etwas würde wahrscheinlich funktionieren

class MyClass:
    def __init__(self,x,y,z):
       self.x = x
       self.y = y
       self.z = z
    def __iter__(self): #overridding this to return tuples of (key,value)
       return iter([('x',self.x),('y',self.y),('z',self.z)])

dict(MyClass(5,6,7)) # because dict knows how to deal with tuples of (key,value)
Joran Beasley
quelle
Oh, interessant! Als Iterable der Tupel habe ich das nicht berücksichtigt. Ich werde einen kurzen Test machen
Vorliebe
Wenn Sie einen Iter einer Liste von Tupeln zurückgeben, werden alle Werte von x, y und z in die Liste aufgenommen, auf der der Iter basiert. In dem Fall, in dem die 3 Yield-Anweisungen vorliegen, ist es möglich (ein winziges Fenster, aber dennoch vorhanden), dass das Ausführen in einer Thread-Umgebung dazu führen kann, dass ein anderer Thread das y-Attribut oder das z-Attribut so ändert, dass das gemeldete x, y und z sind nicht konsistent.
PaulMcG
@PaulMcGuire: Garantiert CPython, dass alle auch mit Jorans Code konsistent sind? Ich hätte gedacht, dass ein anderer Thread geplant werden könnte, zum Beispiel nachdem das erste Tupel mit xerstellt wurde, aber vor dem zweiten Tupel mit y. Bin ich falsch und tatsächlich ist das Listenverständnis in Bezug auf die Thread-Planung atomar?
Steve Jessop
Jetzt, wo Sie fragen, ist mir klar, dass selbst das Listenverständnis nicht atomar garantiert ist, da Pythons Thread-Switcher dies auf Bytecode-Ebene und nicht auf Quellenebene tut. Ihre Belichtung gilt jedoch nur für die Dauer der Erstellung der Liste. Sobald die Liste erstellt wurde, spielen Aktualisierungen der Eigenschaften keine Rolle mehr (es sei denn, die Eigenschaftswerte sind veränderbare Objekte). Verwenden Sie das disModul am besten, um die tatsächlichen Bytecodes anzuzeigen.
PaulMcG
11

Ich denke, das wird für dich funktionieren.

class A(object):
    def __init__(self, a, b, c, sum, version='old'):
        self.a = a
        self.b = b
        self.c = c
        self.sum = 6
        self.version = version

    def __int__(self):
        return self.sum + 9000

    def __iter__(self):
        return self.__dict__.iteritems()

a = A(1,2,3,4,5)
print dict(a)

Ausgabe

{'a': 1, 'c': 3, 'b': 2, 'sum': 6, 'version': 5}

Garrett R.
quelle
Was ist mit Summe und Version passiert? Wie unterscheidet sich das vom einfachen Zugriff __dict__wie in der anderen vorgeschlagenen Antwort?
Joran Beasley
es ist kein Diktat. Der Aufruf von iteritems gibt einen Iterator zurück
Garrett R
1
Ich mag diese Antwort ... aber es braucht etwas mehr Arbeit, bevor sie die Anforderungen des OP erfüllt ...
Joran Beasley
Diese Antwort unterscheidet sich wirklich nicht von @JoranBeasley. Der Unterschied besteht darin, dass er selektiv ist, während Sie das Ganze erfassen, das self.__dict__Elemente enthält, die ich in der Wörterbuchversion des Objekts nicht haben möchte.
Vorliebe
6

Wie viele andere würde ich vorschlagen, eine to_dict () -Funktion zu implementieren, anstatt (oder zusätzlich) das Casting in ein Wörterbuch zuzulassen. Ich denke, es macht es offensichtlicher, dass die Klasse diese Art von Funktionalität unterstützt. Sie können eine solche Methode leicht wie folgt implementieren:

def to_dict(self):
    class_vars = vars(MyClass)  # get any "default" attrs defined at the class level
    inst_vars = vars(self)  # get any attrs defined on the instance (self)
    all_vars = dict(class_vars)
    all_vars.update(inst_vars)
    # filter out private attributes
    public_vars = {k: v for k, v in all_vars.items() if not k.startswith('_')}
    return public_vars
tvt173
quelle
1

Es ist schwer zu sagen, ohne den gesamten Kontext des Problems zu kennen, aber ich würde es nicht überschreiben __iter__.

Ich würde __what_goes_here__auf der Klasse implementieren .

as_dict(self:
    d = {...whatever you need...}
    return d
noisewaterphd
quelle
Nein, das ist, was die Variablen gespeichert sind.
Zizouz212
3
Ich habe ausdrücklich darauf hingewiesen, dass w.__dict__das nicht das tut, was ich brauche.
Vorliebe
Aber __dict__könnte überschrieben werden, nicht wahr?
Noisewaterphd
@noisewaterphd nein, es ist eine magische Methode (vielleicht könnten Sie sie überschreiben, aber die Auswirkungen sind, gelinde gesagt, beängstigend)
Joran Beasley
1
Warum nicht vom Diktat erben oder besser noch, erstellen Sie einfach eine Methode für die Klasse, um sie als Diktat zurückzugeben.
Noisewaterphd
0

Ich versuche eine Klasse zu schreiben, die "beides" ist list oder a ist dict. Ich möchte, dass der Programmierer in der Lage ist, dieses Objekt sowohl in ein list( Casting der Schlüssel) als auch in ein "Cast" zu verwandelndict (mit den Schlüsseln) .

Betrachten Sie die Art und Weise, wie Python derzeit die dict()Besetzung ausführt: Es ruft aufMapping.update() mit dem übergebenen Objekt auf. Dies ist der Code aus dem Python-Repo :

def update(self, other=(), /, **kwds):
    ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
        If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
        If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
        In either case, this is followed by: for k, v in F.items(): D[k] = v
    '''
    if isinstance(other, Mapping):
        for key in other:
            self[key] = other[key]
    elif hasattr(other, "keys"):
        for key in other.keys():
            self[key] = other[key]
    else:
        for key, value in other:
            self[key] = value
    for key, value in kwds.items():
        self[key] = value

Der letzte Unterfall der if-Anweisung, über otherden sie iteriert, ist der, an den die meisten Menschen denken. Wie Sie sehen können, ist es jedoch auch möglich, eine zu habenkeys() Eigenschaft . In Kombination mit a __getitem__()sollte es einfach sein, eine Unterklasse ordnungsgemäß in ein Wörterbuch umzuwandeln:

class Wharrgarbl(object):
    def __init__(self, a, b, c, sum, version='old'):
        self.a = a
        self.b = b
        self.c = c
        self.sum = 6
        self.version = version

    def __int__(self):
        return self.sum + 9000

    def __keys__(self):
        return ["a", "b", "c"]

    def __getitem__(self, key):
        # have obj["a"] -> obj.a
        return self.__getattribute__(key)

Dann wird das funktionieren:

>>> w = Wharrgarbl('one', 'two', 'three', 6)
>>> dict(w)
{'a': 'one', 'c': 'three', 'b': 'two'}
Jérémie
quelle
Sie haben das Mapping-Protokoll implementiert. Siehe Option 3 in meiner Antwort oben. Wenn Sie auch listdie Schlüssel __iter__löschen möchten , können Sie eine Methode hinzufügen , die die Werte durchläuft, und das Casting dictan funktioniert weiterhin. Beachten Sie, dass bei Wörterbüchern, die Sie in eine Liste umwandeln, normalerweise die SCHLÜSSEL zurückgegeben werden und nicht die gewünschten Werte. Dies könnte für andere Personen, die Ihren Code verwenden, überraschend sein, es sei denn, es ist offensichtlich, warum dies passieren würde.
Rick unterstützt Monica