Objekte in Liste speichern?

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
dplusg
User
Beiträge: 2
Registriert: Samstag 2. Februar 2013, 20:35

Hallo Python Forum!

Ich bin momentan dabei ein Programm zu schreiben zum Verwalten eines Inventursystems.
Ich möchte eine Liste als meine kleine "Datenbank" dabei benutzen und am Ende diese Liste als eine csv Datei speichern.
Vorher wird eine csv Datei mit bereits vorhandenen Daten geöffnet.

Code: Alles auswählen

#neuer Artikel
class Artikel():
    def __init__(self, Artikelnummer, Menge, Artikelbezeichnung, Preis):
        self.Artikelnummer=Artikelnummer
        self.Menge=Menge
        self.Arikelbezeichnung=Artikelbezeichnung
        self.Preis=Preis

Bestandsliste=[]

def neues_objekt_anlegen():
        global Bestandsliste
        neuer_Artikel=Artikel(raw_input("Artikelnummer: "), raw_input("Menge: "), raw_input("Artikelbezeichnung: "), raw_input("Preis: "))
        Bestandsliste.append(neuer_Artikel)
neues_objekt_anlegen()

print(Bestandsliste)
wenn ich jetzt mir die Liste "Bestandsliste" anzeigen möchte bekomme ich irgendwelche Daten ausgespuckt, die nicht nach meinen Eingaben aussehen.

Entweder kann ich ein Objekt nicht in einer Liste speichern oder ich mach etwas mit print falsch :K



Ich hoffe jetzt einfach mal, dass mir meine Studienkollegen nicht meinen Python Code klauen ^^
BlackJack

@dplusg: Python kann nicht auf magische Weise erraten wie Du gerne Deine Objekte ausgegeben bekommen möchtest. Das musst *Du* schon selber definieren. Wenn man Objekte in eine Zeichenkette umwandelt, explizit mit `str()` oder in dem man es bei ``print`` angibt, dann wird die `__str__()`-Methode auf diesem Objekt aufgerufen. Bei Listen wird bei dieser Methode für jedes Element `repr()` aufgerufen, was wiederum die `__repr__()`-Methode auf den Elementen aufruft.

Entweder implemetierst Du diese Methode auf Deinem `Artikel`-Datentyp, dann aber bitte den Konventionen folgend entweder in Eine Zeichenkettenform die man im Quelltext schreiben könnte um wieder ein Objekt von dem Typ zu bekommen, oder Informationen die zur Fehlersuche geeignet sind in „spitzen Klammern”, wobei der Name des Datentyps als erstes kommen sollte, und danach genug Informationen um verschiedene Exemplare dieses Typs auseinander halten zu können.

Oder Du implementierst die `__str__()`-Methode — die ist für eine Zeichenkettendarstellung gedacht die Benutzer zu sehen bekommen können. Dann musst Du die Liste durchgehen und die Artikel einzeln ausgeben.

Alternativ könntest Du auch eine Funktion schreiben, die die Liste durchgeht und dann aus jedem Artikel eine Zeichenkette erstellt, die der Benutzer zu sehen bekommen soll.

Wegen der Namensschreibweisen und der Formatierung des Quelltextes (Leerzeichen) solltest Du mal einen Blick in den Style Guide for Python Code werfen.

Das Schlüsselwort ``global`` vergisst Du bitte ganz schnell wieder. Hier wird das überhaupt nicht gebraucht. Und wenn es gebraucht wird, hat man in 99% der Fälle unsauberen Code geschrieben. Im Grunde ist der vorliegende auch ohne das unnötige ``global`` nicht so toll, weil einfach das (modul)globale `Bestandsliste`-Objekt verändert wird. Werte sollten Funktionen als Argumente betreten. Ausnahme sind Konstanten.

In Python 2.x sollte man explizit von `object` erben, wenn man sonst keine Basisklasse hat, damit man eine „new style”-Klasse bekommt. Sonst funktionieren nicht alle Spracheigenschaften mit den Objekten, die Python bietet.

``print`` ist keine Funktion sondern eine Anweisung. Darum sollte man es auch nicht schreiben als wäre es eine.
dplusg
User
Beiträge: 2
Registriert: Samstag 2. Februar 2013, 20:35

danke für deine ausführliche Antwort, jedoch verwirrt mich diese als Leie mehr als sie mir eigentlich weiter hilft.

Könnte jemand nochmal eine vereinfachte Version verfassen oder mir ein Beispiel geben bitte?!
lunar

@dplusg BlackJack sagt Dir letztlich, dass Python nicht wissen kann, wie "Artikel" richtig angezeigt werden soll, und Du daher in einer Schleife über alle Artikel jeden Artikel manuell ausgeben muss. Wie das geht, musst Du jetzt selbst wissen, das ist Grundlagenwissen in Python, was Dir bereits im offiziellen Tutorial beigebracht wird.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hier das Gesagte mal in einem Beispiel:

Code: Alles auswählen

class Item(object):
    def __init__(self, id, title, quantum, price, currency):
        self.id = id
        self.title = title
        self.quantum = quantum
        self.price = float(price)
        self.currency = currency

    def __str__(self):
        return ('{quantum:5} x {id:5} {title:30} '
                '{price:8.2f} {currency}'.format(**self.__dict__))

class Stock(object):
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def list(self, order=None):
        if order:
            key = lambda i: getattr(i, order)
        else:
            key = None
        for item in sorted(self.items, key=key):
            print item

Code: Alles auswählen

>>> stock = inventory.Stock()
>>> stock.add(inventory.Item(id=1, title='aaa', quantum=9, price=10, currency='EUR'))
>>> stock.add(inventory.Item(id=2, title='bbb', quantum=8, price=20, currency='USD'))
>>> stock.add(inventory.Item(id=0, title='ccc', quantum=7, price=5, currency='AUD'))
>>> stock.list()
    9 x     1 aaa                               10.00 EUR
    8 x     2 bbb                               20.00 USD
    7 x     0 ccc                                5.00 AUD
>>> stock.list(order='currency')
    7 x     0 ccc                                5.00 AUD
    9 x     1 aaa                               10.00 EUR
    8 x     2 bbb                               20.00 USD
>>> stock.list(order='id')
    7 x     0 ccc                                5.00 AUD
    9 x     1 aaa                               10.00 EUR
    8 x     2 bbb                               20.00 USD
Ich stelle mein Beispiel hiermit unter die WTFPL License. Somit können Deine Studienkollegen das mit gutem Gewissen verwenden... :P

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

EDIT: Bevor ich jetzt wieder Klopfe bekomme: Das, was in der 'Stock.list()'-Methode geschieht, gehört eigentlich nicht in die 'Stock()'-Klasse, weil dadurch die Datenverwaltung und -ausgabe miteinander vermischt werden. Und das macht dann schon sehr bald Probleme, wenn es z. B. darum geht, die Artikelliste nicht auf dem Bildschirm, sondern auf einem Drucker auszugeben.
Besser wäre es also so:

Code: Alles auswählen

class Stock(object):
    ...
    ...
    def list(self, order=None):
        if order:
            ...
        return sorted(self.items, key=key)
Damit holst Du Dir dann die gewünschten Items ab und kannst diese wie auch immer weiterverarbeiten...

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

Verbesserungsvorschlag für die `list()`-Methode mit `operator.attrgetter()`:

Code: Alles auswählen

    def list(self, order=None):
        key = attrgetter(order) if order else None
        for item in sorted(self.items, key=key):
            print item
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@mutella:

Die Methode zur Ausgabe des `Stock`-Inhalts lässt sich IMHO auch unkomplizierter schreiben:

Code: Alles auswählen

from __future__ import print_function
from operator import attrgetter

class Item(object):
    def __init__(self, id, title, quantum, price, currency):
        self.id = id
        self.title = title
        self.quantum = quantum
        self.price = float(price)
        self.currency = currency

    def __str__(self):
        return ('{quantum:5} x {id:5} {title:30} '
                '{price:8.2f} {currency}'.format(**self.__dict__))

class Stock(object):
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def print_contents(self, sorting=None):
        sortkey = attrgetter(sorting) if sorting else None
        print(*sorted(self.items, key=sortkey), sep='\n')


def test():
    stock = Stock()
    stock.add(Item(id=1, title='aaa', quantum=9, price=10, currency='EUR'))
    stock.add(Item(id=2, title='bbb', quantum=8, price=20, currency='USD'))
    stock.add(Item(id=0, title='ccc', quantum=7, price=5, currency='AUD'))

    stock.print_contents()
    print()
    stock.print_contents('currency')
    print()
    stock.print_contents('id')

if __name__ == '__main__':
    test()
...wobei das sicherlich im Auge des Betrachters liegt. ^^

Was man übrigens schön sehen kann, sind die Verrenkungen, die nötig sein, wenn eine Methode direkt mit `print` arbeitet. Sollte man also besser vermeiden. Die Rückgabe eines Strings unter Verwendung von `'\n'.join` (und entsprechender Umbenennung der Methode) hätte es nämlich auch getan. ;)
Antworten