Funktionen und Variable (war: "Schleife")

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.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

bb1898 hat geschrieben: Im übrigen gilt generell: der Versuch, ein Problem auf ein kurzes Programm zu reduzieren, bringt Dir nicht nur mehr Helfer, sondern oft schon die Lösung. Gerade am Anfang ist es absolut keine vergeudete Zeit, haufenweise Mini-Skripte zu schreiben, um eine Sache nach der anderen zu verstehen.
An sich habe ich das versucht. Das Problem mit den Parametern ist mir aber erst begegnet, als ich einige Mini-Skripte kombiniert habe - vorher ist es nicht aufgetreten, weil ich meine Variablen jeweils eingeben oder fest vorgeben konnte, aber sie nicht von einem Teil in den andern schicken musste.
Eine Funktion kann Werte von außen bekommen (als Parameter, in Klammern hinter dem Funktionsaufruf), oder in ihrem Inneren können Variable neu definiert werden. Egal, was sie damit anfängt, der Rest des Programms bekommt davon nur in zwei Fällen etwas mit:

- es ist ein Parameter von einem veränderlichen Datentyp (wichtigste Beispiele: Liste, Dictionary, selbst definierte Klasse; Gegenbeispiele: Zahlen, Strings, Tupel). Dann hat dieser Parameter nach dem Funktionsaufruf einen neuen Wert.
Danke, das ist schon wichtig zu wissen... Ich haette nicht erwartet, dass sich Listen einerseits und Strings und Tupel andererseits an dieser Stelle unterschiedlich verhalten.
Ich hatte heute nacht erwogen, die lange Parameterliste irgendwie in einen einzigen "Zwischenspeicher" zu packen und diesen dann am Anfang von "evaluate" wieder zu "entpacken". Offenbar macht es dabei dann einen Unterschied, ob ich sie zu einer Liste mache (was gehen muesste, wenn ich nur Zahlen und Listen habe), oder ob ich daraus ein Tupel mache. Im ersten Fall muesste das Programm nach Abschluss des "evaluate"-Teils bei Verwendung einer Liste als "Zwischenspeicher" die neuen Werte direkt weiterverwenden, waehrend ich, wenn ich daraus einen Tupel gemacht habe, diesen am Ende von "evaluate" per return mit den geaenderten Werten fuellen muesste?

In "Pseudocode" umgesetzt: Im "Hauptprogramm":

Code: Alles auswählen

 # Dateneingabe usw.

param1 = 0
param2 = []
param3 = [1,1,1]

Zwischenspeicher = [param1,param2,param3]
evaluate(aktuList,gro,Zwischenspeicher) 
und zu Beginn von "evaluate":

Code: Alles auswählen

def evaluate(aktuList,gro,Zwischenspeicher):
   param1 = Zwischenspeicher[1]
   param2 = Zwischenspeicher[2]
   param3 = Zwischenspeicher[3]
   ... 
Das ist der Fall mit einer Liste. In dem Fall koennte ich fuer die Auswertung nach Ende von "evaluate" direkt auf die geaenderten param1, param2 und param3 zugreifen.
Aber wenn ich fuer "Zwischenspeicher" runde Klammern nehme, wird daraus ein Tupel. Und das verhaelt sich anders...
- der Wert wird mit "return <Ausdruck>" zurückgegeben. Dabei kann <Ausdruck> auch ein Tupel sein, auf diese Weise können mehrere Werte auf einmal zurückgegeben werden. Damit der Wert an anderer Stelle tatsächlich benutzt werden kann, muss der Funktionsaufruf entsprechend aussehen, im einfachsten Fall so:

meinNeuerWert = meineFunktion(meinEingabeparameter1, ...)

Jetzt hat meinNeuerWert den Wert, den meineFunktion ausgerechnet und zurückgegeben hat.
Der Teil ist mir jetzt noch nicht so klar. Versuchsweise wuerde ich in meinen "Pseudocode" so etwas einbauen:

Code: Alles auswählen

 def evaluate(aktuList,gro,Zwischenspeicher):
   ...
   # viel code
   ...
   Zwischenspeicher = (param1,param2,param3)
   return Zwischenspeicher 
Dann muessten fuer die weitere Auswertung die geaenderten Werte zur Verfuegung stehen.
Ganz gluecklich bin ich mit dieser Version noch nicht, weil der "Zwischenspeicher" bei hohen Eingabewerten am Ende von "evaluate" doch ziemlich umfangreich wird. Im Moment habe ich die Variablen erstmal nach "brauche ich spaeter noch" und "brauche ich nur innerhalb von evaluate" sortiert und festgestellt, dass ich 5 wohl nur "lokal" innerhalb von evaluate brauche. 9 bleiben damit, die evaluate veraendern soll, und wenn ich die als lange Liste uebergebe, funktioniert es zumindest schonmal fuer die Listen.

Wenn es irgendwen interessiert, kann ich auch nochmal eine genauer kommentierte Version des Programms abliefern...
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

merlin_emrys hat geschrieben:
- es ist ein Parameter von einem veränderlichen Datentyp (wichtigste Beispiele: Liste, Dictionary, selbst definierte Klasse; Gegenbeispiele: Zahlen, Strings, Tupel). Dann hat dieser Parameter nach dem Funktionsaufruf einen neuen Wert.
Danke, das ist schon wichtig zu wissen... Ich haette nicht erwartet, dass sich Listen einerseits und Strings und Tupel andererseits an dieser Stelle unterschiedlich verhalten.
Das ist gerade einer der wesentlichen Unterschiede zwischen Tupeln und Listen.
In "Pseudocode" umgesetzt: Im "Hauptprogramm":

Code: Alles auswählen

 # Dateneingabe usw.

param1 = 0
param2 = []
param3 = [1,1,1]

Zwischenspeicher = [param1,param2,param3]
evaluate(aktuList,gro,Zwischenspeicher) 
und zu Beginn von "evaluate":

Code: Alles auswählen

def evaluate(aktuList,gro,Zwischenspeicher):
   param1 = Zwischenspeicher[1]
   param2 = Zwischenspeicher[2]
   param3 = Zwischenspeicher[3]
   ... 
Das ist der Fall mit einer Liste. In dem Fall koennte ich fuer die Auswertung nach Ende von "evaluate" direkt auf die geaenderten param1, param2 und param3 zugreifen.
Nicht ganz. Auf geänderte param1, param2, param3 kannst Du nicht zugreifen. Auf geänderte Zwischenspeicher dagegen schon. Die Bindung der Namen param1, param2, param3 an die Elemente von Zwischenspeicher überlebt das Funktionsende nicht. Und wenn Du param1 änderst, aber danach nicht den neuen Wert explizit dem passenden Listenelement zuweist, dann geht es wieder nicht.

Das ist aber alles im Lehrbuch besser erklärt (Stichwort mutable / immutable values). Und übrigens, die diversen Links zu deutschsprachigen Tutorials im entsprechenden Teil dieses Forums hast Du gefunden?

Der Teil ist mir jetzt noch nicht so klar. Versuchsweise wuerde ich in meinen "Pseudocode" so etwas einbauen:

Code: Alles auswählen

 def evaluate(aktuList,gro,Zwischenspeicher):
   ...
   # viel code
   ...
   Zwischenspeicher = (param1,param2,param3)
   return Zwischenspeicher 
Dann muessten fuer die weitere Auswertung die geaenderten Werte zur Verfuegung stehen.
Richtig. Vorausgesetzt, Du rufst die Funktion richtig auf:

Code: Alles auswählen

Zwischenspeicher = evaluate(aktuList, gro, Zwischenspeicher) 
(die Namen können auch andere sein!)

Dagegen ist die Zuweisung vor dem return nicht wirklich nötig, Du kannst statt dessen einfach

Code: Alles auswählen

return (param1, param2, param3)
schreiben.
Ganz gluecklich bin ich mit dieser Version noch nicht, weil der "Zwischenspeicher" bei hohen Eingabewerten am Ende von "evaluate" doch ziemlich umfangreich wird. Im Moment habe ich die Variablen erstmal nach "brauche ich spaeter noch" und "brauche ich nur innerhalb von evaluate" sortiert und festgestellt, dass ich 5 wohl nur "lokal" innerhalb von evaluate brauche. 9 bleiben damit, die evaluate veraendern soll, und wenn ich die als lange Liste uebergebe, funktioniert es zumindest schonmal fuer die Listen.
Bequemer als eine lange Liste ist m.E. ein Dictionary: dann kannst Du Deine Variablennamen als Schlüssel nehmen und musst nicht auf die Indizes innerhalb der Liste aufpassen. Oder gleich eine selbstdefinierte Klasse. Für beides gilt: wahrscheinlich erst mal ungewohnt, aber die investierte Lernzeit lohnt sich.
Antworten