Objekt in Liste speichern und lesbar ausgeben

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.
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Hallo,

ich habe ein Programm, in dem Werte aus einer Textdatei gelesen werden und als Objekt gespeichert werden. Die Eigenschaften des Objektes sind: Name, Vorname, Zahlenliste1, Zahlenliste2. Das klappt soweit auch gut - jetzt möchte ich aber die Treffer (also die erzeugten Instanzen), die der User gefunden hat, in einer Liste speichern. Auch das scheint zu funktionieren - bloß an der Ausgabe hapert es. Das Programm gibt mir: [<__main__.Person object at 0x7fa191c69f98> aus. Kann ich irgendwie erreichen, dass mein Objekt in les-und verwendbarer Form ausgegeben wird?

Für Anfängerhilfe bin ich dankbar!

Beste Grüße
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cortez: Vorweg: Die Zeichenkettendarstellung von Listen ist nicht für Endbenutzer gedacht, sondern für den Programmierer um zum Beispiel Fehler zu suchen/zu finden.

In der Zeichenkettendarstellung von Listen wird von den einzelnen Elementen die `repr()`-Form abgefragt. Die kannst Du durch Implementieren der `__repr__()`-Methode beeinflussen. Konvention ist hier entweder etwas was man als Python-Code eingeben könnte um ein Objekt mit dem gleichen Wert zu erzeugen, oder etwas das mehr Informationen als die `object.__repr__()` liefert, die jetzt benutzt wird, und das mit '<' anfängt und '>' aufhört.

Ich persönlich mag das `attr`-Modul für Klassen sehr gerne, denn da muss man sich das nicht selber basteln, sondern bekommt schon eine schöne `__repr__()`-Implementierung frei Haus geliefert:

Code: Alles auswählen

#!/usr/bin/env python3
from attr import attrib, attrs

@attrs
class Person:
    name = attrib()
    vorname = attrib()
    werte_a = attrib()
    werte_b = attrib()


def main():
    person = Person('Musterman', 'Max', [42, 23], [1, 2, 3])
    print(person)


if __name__ == '__main__':
    main()
Ausgabe des Programms:

Code: Alles auswählen

Person(name='Musterman', vorname='Max', werte_a=[42, 23], werte_b=[1, 2, 3])
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
DeaD_EyE
User
Beiträge: 1021
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

EDIT: war zu langsam.

Ja, kannst du mit der Methode __repr__ in der Klasse.
https://docs.python.org/3/reference/dat ... ect.__repr__

Könnte so aussehen:

Code: Alles auswählen


class Person:
    def __init__(self, name):
       self.name = name
    def __repr__(self):
        return f'{self.__class__.__name__}(name={self.name})'

personen = [Person('Andre'), Person('Cortez')]
print(personen)
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wenn man es selbst umsetzt, würde ich dafür sorgen, dass die eingesetzten Werte ihrerseits wieder die `repr()`-Form verwenden, also in dem gezeigten Beispiel noch ein !r beim Platzhalter einfügen:

Code: Alles auswählen

        return f'{self.__class__.__name__}(name={self.name!r})'
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Vielen Dank erstmal für die Hilfe.

Also wenn ich euch jetzt richtig verstanden habe, gibt es die repr-Methode, die auf alle Eigenschaften, die im Konstruktor definiert sind, zugreift. Mich hat da jetzt nur in eurem Codebeispiel gewundert, dass ihr nur den namen gespeichert habt und nicht vornamen, werte a und werte b. Geht das auch? Und wie kann ich die gespeicherten Instanzen dann wieder verfügbar machen?
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cortez: Also ich habe in meinem Beispiel mehr als den Namen gespeichert und bei DeaD_EyE war es nur der Name weil er sich die ganze Tipparbeit sparen wollte, bei dem Beispiel. Hätte ich an der Stelle auch gemacht. Das Prinzip wird ja deutlich und kann auf beliebige Klassen angepasst werden.

Die letzte Frage verstehe ich nicht‽ Die Objekte sind ja in einer Liste gespeichert und da kann man dann halt auch über die üblichen Operationen drauf zugreifen. Zum Beispiel in einer Schleife über alle Elemente iterieren, oder per Index gezielt auf Objekte an dem Index zugreifen, oder per „unpacking“ bei einer Zuweisung an einzelne Namen binden. Wobei bei letzterem in der Regel Tupel statt Listen verwendet werden, wenn der einzelne Index in der Sequenz eine besondere Bedeutung hat.

Und vielleicht noch mal der Hinweis: Die Zeichenkettendarstellung von Python-Listen sind als Information für Programmierer gedacht. Die sind weder für Endbenutzer, noch um Daten zum Beispiel in Dateien zu speichern. Wenn Du die Personen-Infos einem Benutzer anzeigen möchtest oder in einer Datei speichern möchtest aus der sie später wieder geladen werden sollen, dann schreib dafür explizit Code der die Daten entsprechend aufbereitet und verwende ein bekanntes Dateiformat statt selbst etwas zu basteln.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Danke für deinen raschen Input. Ich denke, ich habs jetzt grob verstanden und mach mich jetzt mal ans Basteln :)

Ach ja, danke für die Dokumentation - gibts sowas vielleicht auch irgendwo auf Deutsch?
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cortez: Die Referenzdokumentation eher nicht. Beim Programmieren muss man sich sowieso auf Englisch einstellen, da macht sich keiner mehr die Mühe Dokumentation auf Deutsch zu übersetzen. Da muss der Markt schon sehr gross sein, dass sich das lohnt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

So, habe mir das Ganze mal angesehen und mal folgendes Testprogramm geschrieben: Eine Klasse Person wird angelegt und im Hauptprogramm wird eine Instanz dieser Klasse erzeugt. Mit der repr-Funktion soll zunächst mal nur alles ausprinten, aber anstatt der Instanz erhalten ich folgende Ausgabe: Person({self.name},{self.vorname},{self.wertea},{self.werteb})

Hier mal der Beispielcode:

Code: Alles auswählen

class Person:
    def __init__(self, name, vorname, wertea, werteb):
        self.name = name
        self.vorname = vorname
        self.wertea = wertea
        self.werteb = werteb
    
    def __repr__(self):
        return "Person({self.name},{self.vorname},{self.wertea},{self.werteb})"
    
    
    
Name = input ("Nachname")
Vorname = input ("Vorname")
Werte1 = [1,2,3]
Werte2 = [4,5,6]

Instanz = Person(Name, Vorname, Werte1, Werte2)
print (Instanz.name)
print (repr(Instanz))
Was müsste ich noch ändern? Danke weiterhin für eure Geduld
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cortez: Das Beispiel von DeaD_EyE unterscheidet sich zwar nur um ein Zeichen, das ist aber wichtig! Python ersetzt nicht einfach so auf magische Weise Platzhalter in Zeichenketten.

Namen schreibt man in Python übrigens klein_mit_unterstrichen. Ausgenommen Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Und zwischen Funktionen/Methoden und öffnender Klammer der Argumentliste kommt kein Leerzeichen. Das machst Du irgendwie auch inkonsistent.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ok, danke - jetzt funktionierts.

Aber rein zum Verständnis würde mich schon interessieren, was es mit diesem f auf sich hat ...
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Einfach googeln und dann z.B. hier lesen
https://realpython.com/python-f-strings/
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Alternativ kann man auch direkt in der Python-Dokumentation nachlesen. Über den Index kommt man leicht an die entsprechende Stelle in der Dokumentation: https://docs.python.org/3/reference/lex ... g-literals
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Wollte mich nochmal für die Hilfe bedanken - auch in meinem anderen Thread.
Ein letztes Problem hätte ich noch: Wie kann ich auf die einzelnen Elemente eines in einer Liste gespeicherten Objektes zugreifen, wenn Indexing nicht unterstützt wird?
Oder muss man das irgendwie anders lösen?
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Mit Listen arbeitet man, indem man über sie iteriert. Was ist denn das Problem, das Du lösen möchtest?
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ich möchte im Prinzip die einzelnen Datensätze erstmal auslesen, um dann mit Ihnen zu arbeiten (Werte zusammenzählen/ändern usw.)
Normalerweise geht das doch so: print (Treffer[0][1]). Da greift er auf das zweite Element des ersten Datensatzes zu.
Aber wenn das ganze als Objekt in der Liste gespeichert ist, funktioniert das nicht. Ich kann zwar die Objekte anwählen, aber nicht die einzelnen Eigenschaften (in meinem obigen Beispiel also die [1].
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

liste[index].eigenschaft

Aber wie Sirius3 schon sagte - Indexzugriff klingt erstmal falsch. Iterieren über die Liste ist der bessere Ansatz.
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Cortez: Was ist denn ”das zweite Element des ersten Datensatzes”? Wenn die Datensätze zum Beispiel `Person`-Exemplare sind, dann gibt es da ja kein „zweites Element“ weil das ja keine Sequenz ist sondern ein Objekt mit Attributen. Genau deswegen macht man das ja, damit man nicht so was unverständliches wie ``treffer[0][1]`` im Programm stehen hat, wo man wissen muss was diese magische 1 wohl bedeuten mag, sondern ``treffer[0].vorname`` wo man sofort beim lesen weiss der Wert für eine Bedeutung hat.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Cortez
User
Beiträge: 115
Registriert: Montag 31. Dezember 2018, 15:28

Ah - sowas wie das treffer[0].vorname habe ich gesucht. Aber ich hab das testweise mal ausgeben lassen - bringt bei mir keine Ausgabe...

Edit: Kommando zurück - habe meinen Fehler gefunden.

Kann man auf die Indizes eigentlich auch variabel zugreifen. Also wenn der Benutzer aus mehreren Treffern z.B. einen auswählen möchte. Mit normalen Variablen gehts ja glaub ich nicht, weil der Index immer ein integer sein muss...
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Natürlich geht das Variabel. Hast du das mal probiert?
Antworten