Objekte abspeichern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

Hallo,

wenn ich Objekte erstelle, habe ich ja eine Speicheradresse aus dem Arbeitsspeicher, in dem das Objekt liegt. Was mache ich jetzt, wenn ich dieses Objekt richtig abspeichern möchte um es beispielsweise das nächste mal wiederzuverwenden? Zum Beispiel in eine json Datei. Eine Liste könnte ich ja ganz einfach abspeichern, aber wie sieht es aus, wenn ich nur diese Adresse habe? Der Arbeitsspeicher wird ja wieder gelehrt...
Benutzeravatar
pillmuncher
User
Beiträge: 1530
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Du hast keine Adresse eines Objekts im Arbeitsspeicher. Python ist nicht C.

Du könntest je eine Funktion definieren, die aus einem Objekt eine dict-Repräsentation erzeugt, und eine die aus einer entsprechenden dict-Repräsentation ein Objekt erzeugt, und diese Funktionen dann verwenden. Das Umwandeln eines dicts in einen JSON-String ist mittels des json-Moduls aus der Standardbibliothek trivial.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Loster_Paddel: Übrigens selbst wenn das wie C wäre und man tatsächlich die Speicheradressen von Objekten hätte, könnte man die Speicherinhalte nicht einfach so in eine Datei speichern, denn die Bestandteile eines Objektes sind liegen ja wieder als Speicheradressen und man kann wenn man das wieder laden will, nicht garantieren, dass diese Speicherbereiche dann nicht schon von anderen Objekten belegt sind.

Falls Du über das `pickle`-Modul stolpern solltest, eine kleine Warnung: Das sieht auf den ersten Blick superpraktisch aus, hat aber seine Tücken, weil die gespeicherten Daten von der Package-Struktur abhängig ist und auch Probleme bei Code-Änderungen machen können, denn es werden nur die Daten gespeichert und nicht der Code. Und die Datentypen zu den Daten werden als voll qualifizierte Namen gespeichert. Das Modul ist praktisch für die Datenübertragung oder kurzfristiges speichern von aktuellen Daten, beispielsweise in einem Cache, aber nicht für die langfristige Speicherung von Daten zu empfehlen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Loster_Paddel
User
Beiträge: 39
Registriert: Samstag 16. April 2022, 20:31

Okay und was ist dann das genau?:

__main__.Moebel object at 0x000002B4430F9FD0>

Wenn es nicht die Adresse fürn Speicher ist...
Und danke erstmal. Das stimmr pickle hab ich schon mal gesehen. Werde mich dann erstmal in die dict-Repräsentation einlesen müssen. Es ist auch noch nicht wtwas was ich bisher gebraucht habe, interessiert mich nur, weil es ja nur eine Frage der Zeit ist, bis man irgendwelche Spieler und damit Objekte abspeichern muss...
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

Grundsätzlich ist das ein Hinweis darauf, das die Klasse keine __str__ bzw __repr__ Funktion besitzt:

Code: Alles auswählen

class SampleClass():

    def __init__(self, name):
        self.name = name


class SampleClassWithRepr():

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return f"<{self.__class__}: {self.name}>"


def main():
    ham = SampleClass("Ham")
    print(ham)
    spam = SampleClassWithRepr("Spam")
    print(spam)


if __name__ == "__main__":
    main()
Ergibt hier auf dem System:

Code: Alles auswählen

<__main__.SampleClass object at 0x000001DBB25FAA00>
<<class '__main__.SampleClassWithRepr'>: Spam>
Und dass du eine Instanz dieser Klasse hast.
narpfel
User
Beiträge: 691
Registriert: Freitag 20. Oktober 2017, 16:10

@Loster_Paddel: Die lange Hexzahl im Rückgabewert von `object.__repr__` ist die `id` des Objektes, keine Speicheradresse. Zum Beispiel sieht das bei mir so aus:

Code: Alles auswählen

>>>> object.__repr__(42)
'<int object at 0x00000000000002a1>'
>>>> id(42)
673
>>>> hex(id(42))
'0x2a1'
Da wird sehr schnell klar, dass das nicht die Speicheradresse sein kann, weil 673 erstens nicht durch 8 teilbar ist und zweitens die Adresse 673 gar nicht dem Prozess gehört, in dem ich das ausgeführt habe:

Code: Alles auswählen

$ cat /proc/16334/maps
55d8ba394000-55d8ba395000 r--p 00000000 00:18 27294921                   /opt/pypy3/bin/pypy3
[... viele Speicherbereiche, nach Adresse sortiert ...]
7ffc9f40a000-7ffc9f42c000 rw-p 00000000 00:00 0                          [stack]
7ffc9f4ec000-7ffc9f4f0000 r--p 00000000 00:00 0                          [vvar]
7ffc9f4f0000-7ffc9f4f2000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
0x55d8ba394000 ist die kleinste Adresse, die der Prozess benutzen darf.

Die Eigenschaften der `id` sind:
Dokumentation zu `id` hat geschrieben: Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
Nicht mehr, nicht weniger. Insbesondere steht da nichts von „Speicheradresse“.
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich habe es mal etwas angepasst, so dass es rückwärtskompatibel zu Python 2.7 ist und man es mit Jython ausführen kann:

Code: Alles auswählen

#!/usr/bin/env python3


class SampleClass(object):
    def __init__(self, name):
        self.name = name


class SampleClassWithRepr(object):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return "<{0.__class__.__name__}: {0.name}>".format(self)


def main():
    ham = SampleClass("Ham")
    print(ham)
    spam = SampleClassWithRepr("Spam")
    print(spam)


if __name__ == "__main__":
    main()
Testlauf mit CPython:

Code: Alles auswählen

<__main__.SampleClass object at 0x7fe50658cd50>
<SampleClassWithRepr: Spam>
Testlauf mit PyPy

Code: Alles auswählen

<__main__.SampleClass object at 0x00007fa8e2cfdda8>
<SampleClassWithRepr: Spam>
Testlauf mit Jython:

Code: Alles auswählen

<__main__.SampleClass object at 0x2>
<SampleClassWithRepr: Spam>
Bei Jython sieht man deutlich, dass man sich nicht darauf verlassen kann, dass in dem Text etwas steht das eine Speicheradresse ist oder sein könnte, denn wenn man ein weiteres Objekt nach `ham` angelegt hätte, stünde bei dem dort 0x3. Und Objekte sind ganz sicher nicht 1 Byte gross. Es ist nicht einmal sicher, dass dort überhaupt eine Nummer steht, oder das die Hexadezimal angegeben ist, oder eben auch nicht ob das eine Speicheradresse ist oder nicht. Die Darstellung ist Implementierungsdetail. Das einzige was die Dokumentation wirklich ”garantiert”, ist das es entweder eine Zeichenkette ist, mit der man (wahrscheinlich) das Objekt in einem Quelltext schreiben könnte, oder das es in ”spitze Klammern” eingefasst ist und das Objekt in einer Form darstellt, die bei der Fehlersuche nützlich sein kann.

Die Grundimplementierung von `object` in CPython hat den Typnamen und die `id()` als Hex-Zahl in spitzen Klammern. Und die `id()` ist irgendeine Zahl die das Objekt zu einem gegebenen Zeitpunkt eindeutig identifiziert. Das *kann* eine Speicheradresse sein. Aber auch eine künstliche ID wie bei Jython. Was auch immer es ist, man sollte sich nicht auf mehr verlassen, als das der Wert eindeutig ist.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
narpfel
User
Beiträge: 691
Registriert: Freitag 20. Oktober 2017, 16:10

__blackjack__ hat geschrieben: Sonntag 5. Juni 2022, 18:25 Was auch immer es ist, man sollte sich nicht auf mehr verlassen, als das der Wert eindeutig ist.
Nicht mal das: Man darf sich nur auf Eindeutigkeit verlassen, wenn die Objekte, deren IDs man vergleicht, paarweise überlappende Lebenszeiten haben.
Antworten