Funktionen als Parameter

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
aug_lager
User
Beiträge: 26
Registriert: Sonntag 4. Januar 2015, 12:01

Hallo zusammen!

Ich bin noch ziemlich unerfahren was Python und auch Programmierung allgemein betrifft. Als Übungsprojekt schreibe ich ein Programm, das mir Siebversuche auswertet (ich studiere Geowissenschaften). Der Ablauf und die Auswertung eines solchen Versuchs erfolgt nach einer klaren Linie und die Parameter, die ich aus solch einem Versuch gewinnen kann, bauen aufeinander auf. Ich brauche zum Beispiel eine Funktion, die mir den Korndurchmesser bei 60% und bei 10% Durchgang ausrechnet und eine andere, die mir daraus die Ungleichförmigkeit berechnet. Ich würde gerne eure Meinung zum Aufbau meines Programms wissen, da ich mir selbst nicht ganz sicher bin, ob das denn so sinnvoll ist.

Code: Alles auswählen

class siebversuch(object):
    def __init__(self, einwaage, siebe, rueck):
        self.einwaage = einwaage
        self.siebe = siebe
        self.rueck = rueck
        
    def verlust(self):
        """Berechnet den Siebverlust als Differenz zwischen Einwaage und der
        Summe der Rückstände.
        """
        self.verlust = self.einwaage - sum(self.rueck)
        return self.verlust

    def durch(self):
        """Berechnet die Durchgänge für jedes Sieb. Rückgabe als list in Gramm."""
        self.durch = []
        for i in range(len(rueck)):
            self.durch.append(sum(self.rueck)-self.rueck[i])

    def kum_rueck_gr(self):
        """Berechnet die kumulativen Rückstände in Gramm"""        
        self.kum_rueck_gr = []
        for i in range(len(self.rueck)):
            if i == 0:
                self.kum_rueck_gr.append(self.rueck[i])
            else:
                self.kum_rueck_gr.append(self.kum_rueck_gr[i-1]+self.rueck[i])
        return self.kum_rueck_gr
    
    def kum_rueck_pr(self, kum_rueck_gr):
        """Berechnet die kumulativen Rückstände in Prozent"""
        self.kum_rueck_pr = [] 
        for i in range(len(self.rueck)):
            self.kum_rueck_pr.append((self.kum_rueck_gr[i]/sum(self.rueck)) * 100)
        return self.kum_rueck_pr

    def kum_durch_gr(self, kum_rueck_gr):
        """Berechnet über die kumulativen Rückstände die kumulativen Durchgänge
        in Gramm.
        kum_rueck_gr -- kumulative Rückstände in Gramm.
        """
        self.kum_durch_gr=[]
        for i in range(len(self.kum_rueck_gr)):
            self.kum_durch_gr.append(sum(self.rueck) - self.kum_rueck_gr[i])
        return self.kum_durch_gr
    
    def kum_durch_pr(self, kum_rueck_pr):
        """Berechnet über die kumulativen Rückstände die kumulativen Durchgänge
        in Prozent.
        kum_rueck_pr -- kumulative Rückstände in Prozent.
        """
        self.kum_durch_pr=[]
        for i in range(len(self.kum_rueck_gr)):
            self.kum_durch_pr.append(100 - self.kum_rueck_pr[i])
        return self.kum_durch_pr
Ich habe also ein paar Attribute zu Beginn, aus denen sich weitere Werte ableiten. Diese werden dann als Parameter für weitere Funktionen benötigt. kum_durch_gr/kum_durch_pr sind da nur die erste von einigen. Ich weiß mittlerweile, dass es unter Python im Grunde kein Problem ist, Funktionen als Parameter zu verwenden, aber hier wäre ja sogar der Parameter des Parameters eine Funktion. kum_durch_pr könnte ich dann als

Code: Alles auswählen

 s.kum_durch_pr(s.kum_rueck_pr(s.kum_rueck_gr()))
abrufen. Im Programm selbst möchte ich die meisten Parameter ohnehin als Variablen speichern, um sie wiederverwenden zu können. Aber dennoch stell ich mir die Frage, ob ich hier auf dem richtigen Weg bin oder ob ich die Funktionen nicht stärker zusammenfassen sollte. Vielleicht spielt das ja auch gar keine Rolle, aber wie gesagt, ich bin ziemlich ahnungslos und möchte nicht zu Beginn schon grundlegendes falsch machen, was sich später rächen könnte. Wenn ihr zum Code allgemein noch ein paar Worte verlieren könntet, würde ich mich ebenfalls freuen. Für mich sieht er in Ordnung aus und er scheint zu funktionieren. Aber vielleicht sind da ja ein paar böse Schnitzer enthalten, die ich mir nicht angewöhnen möchte :wink:
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@aug_lager: Methoden sollten immer nur eine Sache machen, also entweder ein Attribut setzen, oder einen Wert zurückliefern, aber nicht beides. In Deinem Fall könnte man alle Methoden durch Properties ersetzen, weil ja nicht wirklich aufwändige Rechnungen gemacht werden.

"for i in range(len(rueck))" ist ein anti-pattern, Du solltest direkt über die Elemente der Liste iterieren. "rueck" ist in diesem Fall auch gar nicht definiert; in dieser Methode wird "durch", die Methode selbst, durch eine Liste "durch" ersetzt. Sowas darf man nie machen, jeden Schleifendurchgang die Summe neu zu berechnen ist auch unnötig. Da kommt dann sowas raus:

Code: Alles auswählen

def durch(self):
    gesamt = sum(self.rueck)
    return [gesamt - r for r in self.rueck]
Dieses Muster wiederholt sich bei allen anderen Methoden. Die Methoden kum_blablabla benutzen ihre Argumente gar nicht!
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@aug_lager
Du solltest Dir einmal properties ansehen. Dadurch, dass Du Werte erst dann setzt bzw. erneuerst, wenn die zugehörige Methode aufgerufen wird, läufst Du Gefahr, mit inkonsistenten Werten zu arbeiten.
Sowas könnte z. B. so aussehen:

Code: Alles auswählen

class Siebversuch(object):
    def __init__(self, einwaage, siebe, rueck):
        self.einwaage = einwaage
        self.siebe = siebe
        self.rueck = rueck

    @property
    def verlust(self):
        return self.einwaage - sum(self.rueck)

    @property
    def durch(self):
        summe = sum(self.rueck)
        return [summe - rueck for rueck in self.rueck]
mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten