Welche Methodenparameter

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
Lina
User
Beiträge: 4
Registriert: Samstag 23. November 2019, 11:47

Hallo Miteinander

Ich möchte die Nährstofftabelle eines Lebensmittels darstellen, für das ich bereits eine Klasse geschrieben habe.
Dabei sollten sowohl die Spalten, als auch die Zeilen anpassbar sein.
Bei den Zeilen möchte ich standardmäßig die Kalorienanzahl und die üblichen Makronährstoffe (Fett, gesättigtes Fett, Kohlenhydrate, Zucker, Ballaststoffe und Proteine) darstellen, aber auch andere Modi ermöglichen, etwa alle Nährstoffe oder ebene einzelne zusätzlich auszuwählen. Hier habe ich schon eine Idee, die ich im Code unten umgesetzt habe, nur gefällt sie mir überhaupt nicht.
Für die Spalten habe ich noch gar kein Konzept. Momentan habe ich nur den Namen und die Nährwerte /100g - hier möchte ich etwa noch die Möglichkeit diese pro Portion, pro auswählbarer/eingegebener Menge, in % der Kalorien, in % der Masse usw. anzuzeigen. Die Berechnung dieser einzelnen Größen ist mit der Klasse, die ich für die Lebensmittel angelegt habe kein Problem (wenngleich auch vermutlich noch nicht sehr sauber). Aber wie kann ich hier eine sinnvolle Auswahl bzw. Übergabe machen? Wie gestalte ich die Schnittstelle am besten? Gibt es für so etwas Vorgehensweisen? Oder ist es besser wenn ich das auf mehrere Methoden aufteile?

Vielleicht noch eine kleine Nebenfrage:
Ist es möglich den Text in der linken Spalte der Tabelle linksbündig und in den anderen rechtsbündig anzuordnen? Wenn ja, wie? (Man beachte mein Experiment mit dem Tuple in cellLoc, das nicht funktioniert und eigentlich gelöscht werden sollte xD)

Hier eine verkürzte Version meines Codes:

Code: Alles auswählen

import matplotlib.pyplot as plt

class Nutrient(object):    
    def __init__(self, name, column, unit, amount = 0):
        self.name = name
        self.column = column
        self.unit = unit
        self.amount = amount
		

class Food(object): 
    def __init__(self,line_number, amount, database=False):        
        self.line_index = line_number - 1
        self.basic_keys = ['kcal','fat','sat_fat','carbs','sugar','fibres','protein']
        self.amount = amount        
        self.name = 'Haferflocken'

        self.nutrients = {}
        self.nutrients['kcal'] = Nutrient('Energie', 6, 'kcal', 381)
        self.nutrients['fat'] = Nutrient('Fett', 7, 'g', 7.5)
        self.nutrients['carbs'] = Nutrient('Kohlenhydrate', 12, 'g', 59.5)
        self.nutrients['protein'] = Nutrient('Eiweiß', 16, 'g', 13.5)

        self.nutrients['sat_fat'] = Nutrient('ges. Fett', 8, 'g', 1) 
        self.nutrients['mono_fat'] = Nutrient('einfach unges. Fett', 9, 'g', 3) 
        self.nutrients['poly_fat'] = Nutrient('mehrfach unges. Fett', 10, 'g', 3) 
        self.nutrients['cholesterin'] = Nutrient('Cholesterin', 11, 'mg', 0)
        self.nutrients['sugar'] = Nutrient('Zucker', 13, 'g', 1)
        self.nutrients['starch'] = Nutrient('Stärke', 14, 'g', 58)
        self.nutrients['fibres'] = Nutrient('Ballaststoffe', 15, 'g',10.5)

        self.nutrients['salt'] = Nutrient('Salz', 17, 'g', 0.1)
        # ...

        #Werte Beschreiben für den Post manuell in Initialisierung
        #self.get_values_from_DB(self.line_index) 
	
		
    def naehrstofftabelle(self, mode = 'basic', additional_nutrients = [], save=False, show=False):
        #ToDo: Bessere Lösungsmöglichkeit für mode finden!
        lines = []
        if mode == 'basic':
            lines = self.basic_keys
        elif mode == 'all':
            lines = self.nutrients.keys()
        elif mode == 'iron':
            lines = self.basic_keys
            lines.append('iron')
        else:
            lines = self.basic_keys

        lines += additional_nutrients
            
        fig, ax = plt.subplots()
        ax.xaxis.set_visible(False) 
        ax.yaxis.set_visible(False)
        table = []
        
        #ToDo: Spalten: Name, Menge, (%Bedarf?), (%Kcal?) -> deshalb auch unterschiedliche Modi            
        for key in lines:
            table.append([self.nutrients[key].name, str(self.nutrients[key].amount) + self.nutrients[key].unit])
        collabel=("Nährstoff", "Menge")
        ax.table(cellText=table,colLabels=collabel, loc='center', colWidths=(0.2,0.2), cellLoc=('left','right'))

        plt.title(self.name + ' (' + str(self.line_index + 1) + ')')
        
        if save:
            plt.savefig('Nährstofftabelle ' + self.name + '.png')

        if show:
            plt.show()
Wie man vermutlich ohnehin schnell sehen kann habe ich noch nicht allzu viel Erfahrung in Pyhton und OOP generell, bin da natürlich offen für alle Verbesserungen, wenn ihr diverse Hässlichkeiten entdeckt ;-)

Vielen Dank schonmal für eure Hilfe

ganz liebe Grüße
Line
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Och, sieht doch gar nicht so schlecht aus. Anmerkungen gibt's natuerlich trotzdem :)

Erstmal im groben. Ich würde das Modell von den Operationen die du darauf ausfuehren willst trennen. Also naehrstofftabelle zu einer frei stehenden Funktion machen, die ein Food-Objekt als Argument bekommt. Dafuer sollten sich die Modell-Klassen auf das konzentrieren, was sie wirklich ausmacht: Werte und Beziehungen modellieren. Und das natuerlich auch nicht so hart-kodiert wie du das gerade machst. Es gibt viele Moeglichkeiten sowas zu machen. Gerade diese Minute versuche ich mich zum ersten mal in meinem Leben mit CoreData von Apple. Aber allegmeiner waehlt man fuer solche Daten eine Technologie zum speichern und laden, und baut die Modelle entsprechend. Ein Weg waere zB SQLAlchemy zu verwenden, sqlite als Backend, und dann baust du Tabellenobjekte. ZB

Nutrient - ein bestimmter Naehrstoff mit seinen Eigenschaften.
Food - das eigentliche Lebensmittel
Ingredient - ein Objekt das ein Food mit einem Nutrient und dessen relativer Menge pro zb 100g Food repraesentiert.

Alternativ kannst du JSON-Dateien waehlen. Oder XML, oder CSV. Letztere waeren aber nicht meine erste Wahl, das waere tatsaechlich SQL.
Lina
User
Beiträge: 4
Registriert: Samstag 23. November 2019, 11:47

Erstmal vielen Dank für die Antwort :-)
Also naehrstofftabelle zu einer frei stehenden Funktion machen, die ein Food-Objekt als Argument bekommt.
So weit, so gut, das bringe ich hin, gefällt mir auch gleich weit besser. Irgendwie hat es ja nicht so wirklich in die Klasse gepasst
Dafuer sollten sich die Modell-Klassen auf das konzentrieren, was sie wirklich ausmacht: Werte und Beziehungen modellieren. Und das natuerlich auch nicht so hart-kodiert wie du das gerade machst.
Was meinst du mit hard-coded? Die nutrients des jeweiligen Foods? Weil die lese ich eigentlich eh schon aus einem csv-file aus, deswegen wird auch die line_number (quasi als ID) übergeben. Allerdings lese ich da nur den amount-Parameter aus, die anderen sind ja eigentlich statisch - auch hier glaube ich, dass dieses Design nicht optimal ist. Für den Beitrag habe ich meinen Code etwas gekürzt, sonst müsste ich das alles auch hier rein packen. Dabei war mir eigentlich klar, dass SQL die bessere Alternative wäre. Damit habe ich aber noch keine Erfahrungen und habs mal auf späteren Umbau verschoben.

Das Modell mit dem Ingredient werde ich auf jeden Fall umsetzten, das ist meinem definitv überlegen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na, hartkodiert meint, dass du zwar eine Klasse "Food" hast, aber konkret darin dann nur Haferflocken angelegt hast. Aber du willst ja stattdessen eine Datei oder Datenbank, in der eben Haferflocken, und Toblerone, und Doener-Kebab definiert sind, und die du dann einliest.
Antworten