Liste mit Objekten aufsummieren

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
LiLaLaunebär
User
Beiträge: 55
Registriert: Sonntag 11. April 2010, 14:41

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)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Du hast das schon richtig erkannt. Wenn Du g(f) durch map(g, f) ersetzt, sollte es funktionieren.
LiLaLaunebär
User
Beiträge: 55
Registriert: Sonntag 11. April 2010, 14:41

excellent...läuft wie geschmiert
danke
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Ich finde

Code: Alles auswählen

sum(g.gewicht for g in f)
leserlicher.
Bottle: Micro Web Framework + Development Blog
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ja, ist es auch. Und wahrscheinlich auch ressourcenschonender für größere Listen.
LiLaLaunebär
User
Beiträge: 55
Registriert: Sonntag 11. April 2010, 14:41

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))
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

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.
LiLaLaunebär
User
Beiträge: 55
Registriert: Sonntag 11. April 2010, 14:41

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?
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

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.
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.
LiLaLaunebär
User
Beiträge: 55
Registriert: Sonntag 11. April 2010, 14:41

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...
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

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.
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. :-)
LiLaLaunebär
User
Beiträge: 55
Registriert: Sonntag 11. April 2010, 14:41

ok, danke an euch beiden.
@BlackJack: ich bin auf deiner seite ;-)
Antworten