Seite 1 von 1

Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 12:36
von LiLaLaunebär
Hi,
habe eine Frage.
Ich habe z.B. eine Klasse Produkt

Code: Alles auswählen

class Produkt:
self.gewicht=10
self.volumene=2
jetzt möchte ich das Gewicht eine Liste mit Produkten aufsummieren:

Code: Alles auswählen

f=[Produkt(),Produkt(),Produkt(),Produkt()]
g = lambda x: x.gewicht
print sum(g(f))
es kommt der Fehler: Listenobjekt hat kein Attribut 'gewicht'

was muss ich hier ändern um mit der sum Funktion arbeiten zu können?...das lambda funzt hier nicht so, wie ich mir das erhofft habe, vermutlich weil sum nicht mit den Listeneinträgen sondern mit der gesamten Liste arbeitet (denke ich mal)

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 12:49
von jerch
Du hast das schon richtig erkannt. Wenn Du g(f) durch map(g, f) ersetzt, sollte es funktionieren.

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 12:53
von LiLaLaunebär
excellent...läuft wie geschmiert
danke

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 13:01
von Defnull
Ich finde

Code: Alles auswählen

sum(g.gewicht for g in f)
leserlicher.

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 13:04
von jerch
Ja, ist es auch. Und wahrscheinlich auch ressourcenschonender für größere Listen.

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 13:26
von LiLaLaunebär
danke für euere tipps, aber ein Problem führt zum nächsten...
mit untenstehende Code möchte ich die Anzahl der "Products" in der Liste f zählen...aber es funzt nicht...
habe versucht das map beispiel von http://docs.python.org/tutorial/datastructures.html zu übertragen...waaah!

Code: Alles auswählen

class Product:
    def __init__(self):
        self.name="lala"
        self.weight=5
        
class Nix:
    def __init__(self):
        pass

def sufficient(x):
    return type(x) == type(Product())

g=lambda x: type(x) == type(Product())
        
f=[Product(),Product(),Product(),Nix()]

print sum(map(sufficient,f))
print sum(map(g,f))

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 13:47
von jerch
Für die Anzahl würde ich eher filter() verwenden und mit isinstance() auf "Produkt-Typ" prüfen:

Code: Alles auswählen

len(filter(lambda x: isinstance(x, Product), f))
NB: Solche Typprüfungen sind in Python eher unerwünscht bzw. laufen dem duck typing zuwider. Vllt. kannst Du ja designtechnisch was umstellen, um nicht auf eine solche Prüfung angewiesen zu sein.

Und defnulls Generatorausdruck solltest Du dem map() vorziehen.

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 13:58
von LiLaLaunebär
danke!
ja, das mit dem ducktyping ist mir bewusst, aber es handelt sich um eine simulation bei der es darum geht aus einem lager produkte zu entnehmen, die vorher jmd reingelegt hat...wüsste nicht wie ich das einfacher machen kann?

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 14:07
von DasIch
LiLaLaunebär hat geschrieben:[...]...aber es funzt nicht...[...]
Entsprechend dem Link zur Dokumentation den du gepostet hast gehe ich mal davon aus dass du 2.x benutzt. Dementsprechend gilt ``type(o) != o.__class__``, für Instanzen von Klassen die nicht von `object` erben.

Grundsätzlich solltest du Typprüfungen vermeiden, wenn du trotzdem nicht darauf verzichten möchtest nutze isinstance. Desweiteren solltest du einfach prinzipiell von `object` erben wenn du von keiner anderen Klasse erbst.

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 14:40
von BlackJack
@jerch: Warum `len()` auf eine Liste statt `sum()`? Und auf der anderen Seite dann einen Generatorausdruck bevorzugen, dass passt IMHO nicht zusammen.

@LiLaLaunebär: Ich fände hier ``sum(1 for x in xs if isinstance(x, Product))`` recht leserlich.

Ich kenne den genauen Anwendungszweck ja nicht, aber normalerweise versucht man bei OOP über die Eigenschaften statt über den Typ eines Objekts zu gehen. `isinstance()` ist nämlich nicht nur bei "duck typing" ungern gesehen, sondern auch bei statisch typisierten OO-Sprachen ist eine Typprüfung ein "code smell".

Bei Deinem `Nix` könnte man zum Beispiel vielleicht das "Null-Objekt"-Entwurfsmuster verwenden, das heisst ein Singleton erstellen, das die Eigenschaften eines Produkts hat was "nichts" ist.

Code: Alles auswählen

class Product(object):
    def __init__(self):
        self.name = "lala"
        self.weight = 5

class _Nix(object):
    self.name = None
    self.weight = 0

NIX = _Nix()
Jetzt kann man problemlos das Gesamtgewicht von einer Liste mit Produkten und "Nichts"-Exemplaren bilden, ohne `NIX` irgenwie besonders behandeln zu müssen. `NIX` wiegt halt nix. :-)

Und da es Sinn macht (IMHO) nur ein "Nichts" zu haben, kann man auch Tests auf die Identität von `NIX` machen wenn man die zum Beispiel rausfiltern möchte.

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 14:50
von LiLaLaunebär
erstmal danke an alle
@ dasich:wo liegt denn der vorteil wenn man immer von object erbt? muss ich dann nicht auch immer den konstruktor von objekt auffrufen?

@blackjack:
der grund ist der folgende: ich habe eine liste, die ein lager repräsentiert. da kannst du jetzt alles mögliche reinpacken. fünf paar schuhe, ein auto, was weiß ich.
und jetzt möchte ich wieder 3 paar schuhe rausholen. Die Frage ist nun, wie machen...?
ich habe dazu jede klasse mit einem typ-attribut ausgestattet und habe geprüft, ob das passt...das gefiel aber manchen leuten nicht und man hat mir typvergleiche empfohlen...

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 15:00
von DasIch
LiLaLaunebär hat geschrieben:@ dasich:wo liegt denn der vorteil wenn man immer von object erbt? muss ich dann nicht auch immer den konstruktor von objekt auffrufen?
Wenn du von `object` erbst hast du eine sogenannte New-style Klasse, diese wurden mit Python 2.2 eingeführt um Typen und Klassen zusammenzuführen, diese hat man vorher unterschieden. Abgesehen davon funktionieren einige Sachen nur mit/in diesen Klassen wie z.B. Typprüfungen mit type() oder properties.

In Python besteht der Konstruktor aus 3 Teilen, wenn du wissen willst ob du object.__init__ aufrufen musst wenn du __init__ definierst so ist die Antwort nein.

Re: Liste mit Objekten aufsummieren

Verfasst: Dienstag 18. Mai 2010, 15:09
von BlackJack
@LiLaLaunebär: Tja, und nun kennst Du auch mindestens einen, der von der Typprüfung abraten und stattdessen lieber ein oder mehrere Attribute für den Typ oder die Kategorie vorschlagen würde. :-)

Re: Liste mit Objekten aufsummieren

Verfasst: Mittwoch 19. Mai 2010, 16:29
von LiLaLaunebär
ok, danke an euch beiden.
@BlackJack: ich bin auf deiner seite ;-)