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

Ich komme mal wieder mit einer Anfaengerfrage. Als Teil eines groesseren Programms (Fragmente davon gab's hier schonmal) moechte ich Zahlengruppen erzeugen, die irgendwie so aussehen sollen:

1 ... 1 1
1 ... 1 2
1 ... 1 3
1 ... 1 4
1 ... 2 1
1 ... 2 2
.
.
.

Fuer jede "Position" beginnt das Zaehlen bei "1" und es gibt einen "Maximalwert", bis zu dem jeweils hochgezaehlt werden soll; fuer die letzte Position ist das im Beispiel "4".

Nun habe ich mir ein Programm zurechtgestrickt, was das im Prinzip auch ausgibt - nur habe ich mir da auch eine Schleife gebastelt, aus der ich nicht mehr hinauskomme.

Zum Programm: "evaluate" und "endstep" enthalten derzeit nur jeweils eine print-Anweisung, die spaeter noch durch andere Befehle ersetzt werden. Auch "anz" und "ber" sind derzeit nur aus Bequemlichkeit fest; spaeter sollen sie per "raw_input" geholt werden.

Code: Alles auswählen

def evaluate():
    print "evaluate: ", calclis

def endstep():
    print "endstep"

def calc(pz):
    if done == "nein":
        for i in range(0,grolis[pz]):
            i = i+1
            calclis[pz] = i
            if i < grolis[pz]:
                evaluate()
            elif i == grolis[pz]:
                evaluate()
                counton(pz)
            else:
                print "Das darf nicht passieren!"
    else:
        print "Genug!"

def counton(pz):
    # if done == "nein":
        pz = pz - 1
        if calclis[pz] < grolis[pz]:
            calclis[pz] = calclis[pz] +  1
        else:
            if pz >= 0:
                counton(pz)
            else:
                done = "ja"
                endstep()
        ipz = anz + 1 - pz
        while ipz < anz:
            calclis[ipz] = 1
            ipz = ipz + 1
            calc(ipz-1)
    # else:
      #  print "Das wars..."

#
#
#
# Hier beginnt das eigentliche Programm:


anz= 4
ber = 4
done = "nein"

grolis=[]
a = 0
while a < anz:
    grolis.append(ber)
    a = a + 1

calclis = [1] * anz

pz = len(grolis) - 1 

if done == "nein":
    calc(pz)
elif done == "ja":
    print "Programm beendet"
else:
    print "Wie konnte das passieren?"
Die Ausgabe sieht dann ungefaehr folgendermassen aus:

Code: Alles auswählen

 >>> 
evaluate:  [1, 1, 1, 1]
evaluate:  [1, 1, 1, 2]
evaluate:  [1, 1, 1, 3]
evaluate:  [1, 1, 1, 4]
evaluate:  [1, 1, 2, 1]
evaluate:  [1, 1, 2, 2]
evaluate:  [1, 1, 2, 3]
evaluate:  [1, 1, 2, 4]
evaluate:  [1, 1, 3, 1]
evaluate:  [1, 1, 3, 2]
evaluate:  [1, 1, 3, 3]
evaluate:  [1, 1, 3, 4]
evaluate:  [1, 1, 4, 1]
evaluate:  [1, 1, 4, 2]
evaluate:  [1, 1, 4, 3]
evaluate:  [1, 1, 4, 4]
evaluate:  [1, 2, 4, 1]
evaluate:  [1, 2, 4, 2]
evaluate:  [1, 2, 4, 3]
evaluate:  [1, 2, 4, 4]
evaluate:  [1, 3, 4, 1]
evaluate:  [1, 3, 4, 2]
evaluate:  [1, 3, 4, 3]
evaluate:  [1, 3, 4, 4]
evaluate:  [1, 4, 4, 1]
evaluate:  [1, 4, 4, 2]
evaluate:  [1, 4, 4, 3]
evaluate:  [1, 4, 4, 4]
evaluate:  [2, 4, 4, 1]
evaluate:  [2, 4, 4, 2]
evaluate:  [2, 4, 4, 3]
evaluate:  [2, 4, 4, 4]
evaluate:  [3, 4, 4, 1]
evaluate:  [3, 4, 4, 2]
evaluate:  [3, 4, 4, 3]
evaluate:  [3, 4, 4, 4]
evaluate:  [4, 4, 4, 1]
evaluate:  [4, 4, 4, 2]
evaluate:  [4, 4, 4, 3]
evaluate:  [4, 4, 4, 4]
endstep
evaluate:  [4, 4, 4, 1]
evaluate:  [4, 4, 4, 2]
evaluate:  [4, 4, 4, 3]
evaluate:  [4, 4, 4, 4]
endstep
evaluate:  [4, 4, 4, 1]... 
und immer so weiter.

Erstens stimmt da nochwas nicht, weil in dem Moment, wo die erste Position auf "2" umspringt, Position 2 und 3 nicht auf "1" zurueckgesetzt werden. Aber was mir im Moment mehr Kummer macht, ist, dass nach dem "endstep" das Programm weiter in der Berechnung feststeckt.
Ich habe versucht, das durch die "done"-Variable zu beenden, aber wenn ich die "#" in Zeile 24, 39 und 40 wegnehme, bekomme ich die Fehlermeldung:
File "C:/Program Files/Python24/Lib/Programmversuche/Trockentest06d2.py", line 24, in counton
if done == "nein":
UnboundLocalError: local variable 'done' referenced before assignment
Insofern zwei Fragen:
1.) Geht das alles auch viel einfacher, und ich habe nur nicht herausbekommen, wie?
2.) Wenn nein: Wie komme ich aus meiner selbstgebauten Falle wieder heraus?

Mit bestem Dank fuer alle Hilfe schon im Voraus,
Merlin Emrys
Zuletzt geändert von merlin_emrys am Freitag 18. August 2006, 06:55, insgesamt 1-mal geändert.
BlackJack

merlin_emrys hat geschrieben:Fuer jede "Position" beginnt das Zaehlen bei "1" und es gibt einen "Maximalwert", bis zu dem jeweils hochgezaehlt werden soll; fuer die letzte Position ist das im Beispiel "4".
Das klingt nach einem guten Einsatz für eine relativ einfache Generatorfunktion:

Code: Alles auswählen

def icounter(max_values, start_value=1):
    values = [start_value] * len(max_values)
    last_index = len(max_values) - 1
    while True:
        yield tuple(values)
        i = last_index
        values[i] += 1
        while values[i] > max_values[i]:
            values[i] = start_value
            i -= 1
            if i < 0:
                raise StopIteration()
            values[i] += 1

for values in icounter((2, 2, 4)):
    print values
Ausgabe ist:

Code: Alles auswählen

(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 1, 4)
(1, 2, 1)
(1, 2, 2)
(1, 2, 3)
(1, 2, 4)
(2, 1, 1)
(2, 1, 2)
(2, 1, 3)
(2, 1, 4)
(2, 2, 1)
(2, 2, 2)
(2, 2, 3)
(2, 2, 4)
Zum Programm: "evaluate" und "endstep" enthalten derzeit nur jeweils eine print-Anweisung, die spaeter noch durch andere Befehle ersetzt werden. Auch "anz" und "ber" sind derzeit nur aus Bequemlichkeit fest; spaeter sollen sie per "raw_input" geholt werden.
Du solltest möglichst nicht mit globalen Variablen arbeiten. Wenn `evaluate` auf die Zahlen zugreifen soll, dann ist es besser sie als Argument zu übergeben anstatt darauf zu vertrauen das der Name `calclis` im Modul existiert.
pr0stAta
User
Beiträge: 271
Registriert: Freitag 17. September 2004, 11:49
Wohnort: Bremen

Hi Blackjack, ich finde deine Lösung recht interessant doch
muss ich gestehen, das ich Generatorfunktion nicht wirklich verstehe :)
Könntest du speziell yield tuple(values) vielleicht ein wenig
genauer erklären? Danke im voraus

prosta
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi,

also die Kombinationen würde ich wie bei Binärzahlen berechnen:

Code: Alles auswählen

iMax = 4

def create_list(iMax, m, n): return reduce(lambda x,y:x+y,[[i+1]*m for i in range(iMax)]*n)

lStrips = [create_list(iMax,iMax**(iMax-i-1),iMax**i) for i in range(iMax)]
lResult = apply(zip, lStrips)

for l in lResult: print l
(ginge auch kürzer, aber es sollte übersichtlich bleiben ;-))

Die Funktion erzeugt nur Listen mit n mal m gleichen Zahlen aus 1 bis Max. Beispiel:
iMax = 3, m = 9, n = 1
[1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4] - 1 mal
iMax = 3, m = 3, n = 3
[1,1,1,2,2,2,3,3,3] - 3 mal
iMax = 3, m = 1, n = 9 (richtig, immer Potenzen)
[1,2,3] - 9 mal.

Wenn man die mit zip kombiniert, erhält man alle Kombinationen. Wo war doch gleich das Problem? :)

Grüße,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BlackJack

Generatorfunktionen erkennt der Übersetzer daran, das mindestens ein ``yield`` im Körper der Funktion vorkommt. Wenn man so eine Funktion aufruft, dann wird noch kein Code der Funktion ausgeführt, sondern es wird ein Objekt zurückgegeben, das eine `next()` Methode besitzt.

Wenn diese `next()` Methode aufgerufen wird, läuft der Code der Funktion ab und zwar solange bis ein ``yield xyz`` auftritt. Das `xyz` ist der Rückgabewert von `next()`. Wenn man das nächste mal `next()` aufruft, dann läuft das Programm nach der letzten ausgeführten ``yield`` Anweisung in der Funktion weiter bis der Interpretierer wieder auf ein ``yield`` trifft. Dann gibt das wieder den Rückgabewert der `next()` Methode an.

Das läuft solange bis der Programmfluss das Ende der Funktion erreicht oder eine `StopIteration` Ausnahme ausgelöst wird. Letztere wird vom Interpretierer auch ausgelöst, wenn das Funktionsende erreicht ist.

Da Generatorobjekte auch eine `__iter__()` Methode besitzen, kann man sie in Schleifen benutzen oder überall anders, wo ein "iterable" erwartet wird.

Als kleines Beispiel ein Endloszähler:

Code: Alles auswählen

In [26]: def simple_counter():
   ....:     i = 0
   ....:     while True:
   ....:             yield i
   ....:         i += 1
   ....:

In [27]: a = simple_counter()

In [28]: a
Out[28]: <generator object at 0xb7b78f8c>

In [29]: a.next()
Out[29]: 0

In [30]: a.next()
Out[30]: 1

In [31]: a.next()
Out[31]: 2

In [32]: a.next()
Out[32]: 3
Oder falls es `enumerate()` nicht schon geben würde, kann man es so schreiben:

Code: Alles auswählen

def enumerate(iterable):
    i = 0
    items = iter(iterable)
    while True:
        yield (i, items.next())
        i += 1
Das ist keine Endlosschleife, weil irgendwann das ``items.next()`` eine `StopIteration` Ausnahme auslöst. Es sei denn `iterable` ist ein "Endlositerator". `list(enumerate(simple_count()))` wäre keine gute Idee. ;-)
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi Prosta,

Generatoren sind Berechnungsvorschriften und man kann sie als Funktionen oder direkt deklarieren. Als Funktionen enthalten sie die yield-Anweisung, die einen Wert zurück liefert, aber sich auch den Zustand der Funktion merkt. Beim nächsten Aufruf der "next"-Methode wird die Funktion fortgesetzt, bis zum nächsten yield oder bis eine StopIteration Ausnahme geworfen wird.

Alternativ kann man sie auch direkt deklarieren, ähnlich wie List Comprehensions, nur in runden Klammern:

Code: Alles auswählen

liste = [i for i in range(10) if i % 2]
gen = (i for i in range(10) if i % 2)
Beide liefern alle ungeraden Elemente zwischen 0 und 10. Nur wird liste sofort berechnet, während gen erst beim Aufruf seiner next-Methode (automatisch in Schleifen) den nächsten Wert berechnet (weniger Speicherbedarf). Range ist übrigens auch ein Generator, habe ich gelesen, so kannst Du Dir ihre Anwendung gut vorstellen.

Leider gibt es sie nicht für Python 2.2

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BlackJack

Michael Schneider hat geschrieben:Hi,

also die Kombinationen würde ich wie bei Binärzahlen berechnen:

Code: Alles auswählen

iMax = 4

def create_list(iMax, m, n): return reduce(lambda x,y:x+y,[[i+1]*m for i in range(iMax)]*n)

lStrips = [create_list(iMax,iMax**(iMax-i-1),iMax**i) for i in range(iMax)]
lResult = apply(zip, lStrips)

for l in lResult: print l
(ginge auch kürzer, aber es sollte übersichtlich bleiben ;-))
So würdest Du Binärzahlen bzw. Zahlen zu einer Basis `iMax` berechnen? Wundervoll. Kennst'e schon www.perl.com? ;-)

Eine lesbare Variante die auf Zahlen zu einer beliebigen Basis aufbaut könnte zum Beispiel so aussehen:

Code: Alles auswählen

def base_counter(base, length):
    for value in xrange(base ** length):
        result = list()
        for dummy in xrange(length):
            value, digit = divmod(value, base)
            result.append(digit + 1)
        yield tuple(reversed(result))

for values in base_counter(3, 3):
    print values
jAN
User
Beiträge: 170
Registriert: Samstag 4. Juni 2005, 18:51
Wohnort: Großmehlra (in Thüringen)
Kontaktdaten:

Michael Schneider hat geschrieben:Range ist übrigens auch ein Generator
soweit ich weis gibt range eine liste zurück... xrange ist ein genertator... aber ich hab grad kein python da... sonst würd ich mal schauen
#adios.py
import os,sys
while 1: os.startfile(sys.argv[0])
BlackJack

`xrange()` ist auch keine Generatorfunktion sondern liefert ein Objekt, welches das Sequence-Protokoll implementiert.
pr0stAta
User
Beiträge: 271
Registriert: Freitag 17. September 2004, 11:49
Wohnort: Bremen

Juhu, sehr nett erklärt. Danke euch beiden. Besonders das sehr simple Beispiel von Blackjack hat mir gut gefallen! Ich denke das ich es nun verstanden habe!

Gruss prosta
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

merlin_emrys hat geschrieben: Erstens stimmt da nochwas nicht, weil in dem Moment, wo die erste Position auf "2" umspringt, Position 2 und 3 nicht auf "1" zurueckgesetzt werden. Aber was mir im Moment mehr Kummer macht, ist, dass nach dem "endstep" das Programm weiter in der Berechnung feststeckt.
Ich habe versucht, das durch die "done"-Variable zu beenden, aber wenn ich die "#" in Zeile 24, 39 und 40 wegnehme, bekomme ich die Fehlermeldung:
File "C:/Program Files/Python24/Lib/Programmversuche/Trockentest06d2.py", line 24, in counton
if done == "nein":
UnboundLocalError: local variable 'done' referenced before assignment
Die Fehlermeldung weist schon sehr schön auf den Kern des Problems hin: Du benutzt "done", als wäre es eine globale Variable, Python sieht das aber anders. Weil in der Funktion "counton()" der Name "done" neu gebunden wird (in der Zuweisung "done = 'ja'"), ist es hier eine lokale Variable. Und zwar in der ganzen Funktion, nicht etwa ab der Stelle der Zuweisung. Damit handelst Du Dir erstens den Abbruch ein, wenn Du den Wert von "done" vor der Zuweisung abzufragen versuchst, zweitens kommt der Wert "ja" niemals nach außen und so kommt es zu der Endlosschleife.

In anderen Programmiersprachen (Pascal, Perl, Basic) läuft das anders, aber globale Variablen sollte man nirgendwo ohne Not verwenden. Übergib "done", "calclis" und "grolis" als Parameter und mach aus "done" den Rückgabewert von counton(). So und nur so kannst Du in der Funktion den Wert ändern und außerhalb davon einen Nutzen haben.
Insofern zwei Fragen:
1.) Geht das alles auch viel einfacher, und ich habe nur nicht herausbekommen, wie?
Dazu hast Du ja schon eine Menge Antworten bekommen.

Drei Nebenbemerkungen:

- Die eigenen Programme in einem Unterverzeichnis von "C:\Program Files" unterzubringen, halte ich für problematisch. Es geht überhaupt nur, weil Du offensichtlich entweder immer mit Administratorrechten oder mit einem Uralt-Windows unterwegs bist. Keins von beiden ist eine wirklich gute Idee. Und auch im Hinblick auf Sicherungen und Programm-Aktualisierungen scheint mir das Linux-Verfahren sehr viel einleuchtender, alles Eigene in einem separaten Verzeichnisbaum unterzubringen.

- Bist Du mit der Suche nach einem deutschsprachigen Python-Buch weitergekommen oder hast Du Dich inzwischen mit dem Gedanken angefreundet, es auf Englisch zu versuchen? Früher oder später wirst Du um letzteres kaum herumkommen (und nur einer winzigen Minderheit in diesem Forum dürfte das mühelos zugeflogen sein). Dein Programm sieht mir aus, als sei noch etwas Grundlagenlektüre fällig (Parameter-Übergabe an Funktionen, Gültigkeitsbereich von Namen).

- Ich habe eine starke Vermutung zur Herkunft Deines Benutzernamens. Wenn Du das im Original gelesen hast, ist jedes englischsprachige Python-Buch nicht schwerer, sondern leichter.
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi,

ist zwar wahrscheinlich Off-Topic, aber ich finde "Das Python-Buch" einfach genial für Einsteiger! 97iger Auflage zwar, aber für die Grundlagen unbezahlbar. Selbst ich als Intermediate werde versuchen, das noch gebraucht zu bekommen, bevor es die Biblio für mich sperrt. ;-)

Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Erstmal einen ganz grossen Dank an alle, die mitlesen und mitdenken! Das ist schon eine Menge zu lesen und zu verstehen...
Ich fang mal bei meinen einfachen Fragen und Anmerkungen an:
Michael Schneider hat geschrieben:ist zwar wahrscheinlich Off-Topic, aber ich finde "Das Python-Buch" einfach genial für Einsteiger!
Hast Du dazu noch mehr Angaben? "Phyton-Buch" gibt bei der Amazon-Schnellsuche keinen Treffer :-( ... Allerdings komme ich ohnehin an deutsche Literatur hier (in Japan) nur sehr schwer, und die Versandkosten verringern den Spass zusaetzlich.
bb1898 hat geschrieben:Bist Du mit der Suche nach einem deutschsprachigen Python-Buch weitergekommen oder hast Du Dich inzwischen mit dem Gedanken angefreundet, es auf Englisch zu versuchen?
Ich bin seit letztem Sonntag im Besitz von "Learning Python" (von Lutz&Ascher). War auch nicht so einfach, aber schlussendlich hat sich jemand erbarmt und mir geholfen, es in Englisch zu ordern. (Mehr dazu siehe PN.) Derzeit bin ich aber mit dem Lesen erst auf Seite 36... bis zu den Generatofuntionen dauert es also noch fast 200 Seiten *seufz*.
bb1898 hat geschrieben: Die eigenen Programme in einem Unterverzeichnis von "C:\Program Files" unterzubringen, halte ich für problematisch. Es geht überhaupt nur, weil Du offensichtlich entweder immer mit Administratorrechten oder mit einem Uralt-Windows unterwegs bist.
Ich bin ohnehin immer als Admin unterwegs - daheim, weil sonst ein paar Programme nicht recht wollen, und auf der Arbeit, weil die Rechnerrechte hier normalerweise nicht so eifersuechtig gehuetet werden wie in Deutschland. Und ich bin in einigen Dingen noch auf die Hilfe von Kollegen angewiesen.
bb1898 hat geschrieben:Du benutzt "done", als wäre es eine globale Variable, Python sieht das aber anders. Weil in der Funktion "counton()" der Name "done" neu gebunden wird (in der Zuweisung "done = 'ja'"), ist es hier eine lokale Variable.
Oh... das war mir in keiner Weise klar. Ich hatte angenommen, dass die Reihenfolge bei der Ausfuehrung zaehlt (wie in Pascal und Basic, wenn mich meine Erinnerungen nicht im Stich lassen). Danke!
bb1898 hat geschrieben:Übergib "done", "calclis" und "grolis" als Parameter und mach aus "done" den Rückgabewert von counton().
Den ersten Teil des Satzes verstehe ich (vermutlich), mit dem zweiten habe ich noch Probleme. Was mich dazu bewogen hat, nichts in die Klammern (=Parameter?) meiner selbstdefinitierten Programmteile (=Module?) zu setzen, ist, dass ich mir nicht sicher war, ob ich da ungestraft immer dieselben Benennungen verwenden kann. Konkret: Wenn ich meine Listen als "grolis" und "calclis" bezeichne, kann ich dann def evaluate(grolis,calclis,done) schreiben und da, wo ich "evaluate" aufrufen moechte, auch evaluate(grolis,calclis,done) verwenden, oder fuehrt das zu fehlerhaften Zuordnungen? Ich habe dazu bisher beim Querblaettern und Quersuchen nichts gefunden, aber den Eindruck gewonnen, dass man normalerweise verschiedene Bezeichnungen nimmt.
Aber was meint der zweite Teil des Satzes? Dass ich, wie im vorigen Absatz, "done" als etwas definiere, was die Funktion entgegennimmt und hinterher wieder ausgibt?
Michael Schneider hat geschrieben:also die Kombinationen würde ich wie bei Binärzahlen berechnen: ...

Wenn man die mit zip kombiniert, erhält man alle Kombinationen. Wo war doch gleich das Problem? :)
Ich glaube, das Problem ist im Thread-Titel mit "Anfaengerproblem" angedeutet... Und "Anfaenger" heisst in diesem Fall, dass ich spaetestens beim ersten Auftreten von "lamda" so meine Zweifel bekomme, ob es nicht den Rahmen des Forums sprengt, um Erklaerungen zu bitten, was es damit auf sich hat... Und auch die Aufforderung, etwas Kompliziertes mit etwas Unbekanntem zu kombinieren, ueberfordert mich gerade doch etwas :-( .
BlackJack hat geschrieben:Das klingt nach einem guten Einsatz für eine relativ einfache Generatorfunktion:
Die sieht fuer mich schon genial aus, und es funktioniert auf Anhieb :-) ! Danke!!
Aber ich muss zugeben, mich wuerde noch interessieren, wie es funktioniert?
Zeile 4 leitet eine Schleife ein, aber was wird da eigentlich geprueft? Ein Wert, der immer stimmt, offensichtlich... Wenn ich mal davon ausgehe, dass die Zeile eine Funktion hat, muss es also darum gehen, einfach eine (beliebige) Schleife zu erzeugen? Derselbe Ausdruck taucht auch in dem Zaehlerbeispiel wieder auf (und im Buch gibt es immer eine "for"-Schleife um die Generatorbeispiele drumherum); braucht also der Generator immer eine Schleife, in der er steht?
Zu Zeile 5: Zu den Generatorfunktionen insgesamt werde ich erst noch ein bisschen lesen muessen, bevor ich weiss, was ich nicht verstehe :-( .
Mit tuples habe ich mich noch nicht so genau beschaeftigt, ich habe erstmal versucht, Listen zu lernen; aber wenn ich das richtig ueberflogen habe, kann ich die Tuples erstmal wie Listen behandeln - beispielsweise, wenn es darum geht, das nte Element mit einem anderen Wert zu vergleichen oder irgendwelche Rechenoperationen auszufuehren?
Zu Zeile 12: Woher kommt das "StopIteration()"? Es gibt keine Fehlermeldung, mein Python muss also wissen, was es damit anfangen soll, aber woher eigentlich :-o ? Ist das irgendwo vordefiniert?

Und noch eine Frage zur Einbindung in das gesamte Programm:
Wenn ich das richtig sehe, kann ich meine "evaluate"-Funktion an zwei Stellen einbauen: Zwischen Zeile 4 und 5, oder in Zeile 17 (oder statt Zeile 16). Gibt es von der "programmtechnischen" Seite da einen Unterschied?
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

merlin_emrys hat geschrieben:nichts in die Klammern (=Parameter?) meiner
Ja, die Dinger in den Klammern nennt man Parameter. :)
merlin_emrys hat geschrieben:selbstdefinitierten Programmteile (=Module?)
Du meinst Funktionen. Ein Modul ist etwas, was in einer eigenen Datei steht und dann mit import importiert wird.
merlin_emrys hat geschrieben:dass ich mir nicht sicher war, ob ich da ungestraft immer dieselben Benennungen verwenden kann. Konkret: Wenn ich meine Listen als "grolis" und "calclis" bezeichne, kann ich dann def evaluate(grolis,calclis,done) schreiben und da, wo ich "evaluate" aufrufen moechte, auch evaluate(grolis,calclis,done) verwenden, oder fuehrt das zu fehlerhaften Zuordnungen?
Kein Problem. Bei

Code: Alles auswählen

def evaluate(grolis,calclis,done):
    ....
sind grolis,calclis,done nur lokal innerhalb der Funktion evaluate definiert. Von aussen ist das wie eine Black Box. Du weisst, was fuer Parameter du reinstecken kannst und was hinten herauskommt, der Rest ist egal. Stell dir vor, du muesstest bei Funktionen von anderen Leuten und bei Funktionen, die in der Standardbibliothek von Python sind, darauf Ruecksicht nehmen, wie die interne Benamsung ist...
merlin_emrys hat geschrieben:Aber was meint der zweite Teil des Satzes? Dass ich, wie im vorigen Absatz, "done" als etwas definiere, was die Funktion entgegennimmt und hinterher wieder ausgibt?
Genau das. Dafuer gibt's return;

Code: Alles auswählen

>>> def addieren(a, b):
...     ergebnis = a + b
...     return ergebnis
... 
>>> addieren(3, 4)
7
>>> a = 10; b=12; #Hier kann ich wieder a und b als Variablen verwenden
>>> addieren(b, a)
22
>>> a = addieren(1, 2)
>>> print a
3
>>> 
BlackJack

merlin_emrys hat geschrieben:
BlackJack hat geschrieben:Das klingt nach einem guten Einsatz für eine relativ einfache Generatorfunktion:
Die sieht fuer mich schon genial aus, und es funktioniert auf Anhieb :-) ! Danke!!
Aber ich muss zugeben, mich wuerde noch interessieren, wie es funktioniert?
Zeile 4 leitet eine Schleife ein, aber was wird da eigentlich geprueft? Ein Wert, der immer stimmt, offensichtlich... Wenn ich mal davon ausgehe, dass die Zeile eine Funktion hat, muss es also darum gehen, einfach eine (beliebige) Schleife zu erzeugen?
So sieht eine Endlosschleife aus. Hier ist sie es nicht wirklich weil sie mit der `StopIteration` abgebrochen wird, wenn alle Kombinationen durchgelaufen sind. Im `icounter()` Beispiel haben wir aber eine echte Endlosschleife. Naja, irgenwann gibt's einen `MemoryError` wenn `i` zu gross wird.
Derselbe Ausdruck taucht auch in dem Zaehlerbeispiel wieder auf (und im Buch gibt es immer eine "for"-Schleife um die Generatorbeispiele drumherum); braucht also der Generator immer eine Schleife, in der er steht?
Braucht er nicht, man kann auch die `next()` Methode benutzen um die Werte zu bekommen. Oder "versteckte" Schleifen wenn man so einen Generator an eine Funktion übergibt, die ein "iterable" erwartet. Dann wird innerhalb der Funktion eine Schleife sein oder die `next()` Methode aufgerufen werden.
Mit tuples habe ich mich noch nicht so genau beschaeftigt, ich habe erstmal versucht, Listen zu lernen; aber wenn ich das richtig ueberflogen habe, kann ich die Tuples erstmal wie Listen behandeln - beispielsweise, wenn es darum geht, das nte Element mit einem anderen Wert zu vergleichen oder irgendwelche Rechenoperationen auszufuehren?
Tupel können nicht verändert werden. Du kannst also nicht ``t[x] = y`` ausführen. Und es gibt weniger Methoden als auf Listen. Wenn Du lieber Listen von der Funktion haben möchtest, dann kannst Du einfach anstelle des `tuple()` ein `list()` benutzen.
Zu Zeile 12: Woher kommt das "StopIteration()"? Es gibt keine Fehlermeldung, mein Python muss also wissen, was es damit anfangen soll, aber woher eigentlich :-o ? Ist das irgendwo vordefiniert?
Das gehört zu den "eingebauten" Objekten und steckt im `__builtin__` Modul. Dieses Modul wiederrum importiert das `exceptions` Modul. Beide sind im Modulindex dokumentiert.
Und noch eine Frage zur Einbindung in das gesamte Programm:
Wenn ich das richtig sehe, kann ich meine "evaluate"-Funktion an zwei Stellen einbauen: Zwischen Zeile 4 und 5, oder in Zeile 17 (oder statt Zeile 16). Gibt es von der "programmtechnischen" Seite da einen Unterschied?
Wenn Du `evaluate()` in die Funktion einbaust, dann spezialisierst Du damit die Funktion stärker. Wenn beides getrennt bleibt, dann kannst Du die Zahlen mit verschiedenen Auswertungsfunktionen benutzen und auch verschiedene Funktionen zum Generieren der Zahlen verwenden.
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

@ Rebecca und BlackJack: Noch ein ganz warmes Dankeschoen!
Rebecca hat geschrieben:Du meinst Funktionen. Ein Modul ist etwas, was in einer eigenen Datei steht und dann mit import importiert wird.
Das heisst, wenn ich meine Funktionen in eine eigene Datei stecke und von dort zu Beginn per import hole, werden sie zu Modulen? Oder ist das Modul dann die gesamte Datei?
Rebecca hat geschrieben:
merlin_emrys hat geschrieben:Aber was meint der zweite Teil des Satzes? Dass ich, wie im vorigen Absatz, "done" als etwas definiere, was die Funktion entgegennimmt und hinterher wieder ausgibt?
Genau das. Dafuer gibt's return;
Danke fuer den Tip, allerdings laesst er mich doch noch ein wenig ratlos. Das, was return hier tut, entspricht erstmal dem, was ich von einem print auch erwarten wuerde. Mein Buch sagt mir leider auch nicht viel dazu... Koenntest Du dazu noch ein Wort verlieren? Ich vermute mal, man kann return irgendwie dazu verwenden, sich Werte auch fuer andere Zwecke (also nicht nur analog zu print) zu holen? Ich habe es mal mit Deinem Beispielprogramm und dann

Code: Alles auswählen

liste = []
liste.append(addieren(4,5))
versucht und festgestellt, dass es einen Unterschied macht, wenn ich die return-Zeile weglasse... ist das also ungefaehr die gedachte Verwendung?

BlackJack hat geschrieben:
... braucht also der Generator immer eine Schleife, in der er steht?
Braucht er nicht, man kann auch die `next()` Methode benutzen um die Werte zu bekommen.
Die `next()` Methode hast Du weiter oben auch schon erwaehnt, aber mein Buch hat sie zumindest im Index nicht aufgefuehrt... Darf ich noch eine Runde weiter dumme Fragen stellen und mich erkundigen, was das fuer eine Methode ist?
BlackJack hat geschrieben:Tupel können nicht verändert werden. Du kannst also nicht ``t[x] = y`` ausführen. Und es gibt weniger Methoden als auf Listen. Wenn Du lieber Listen von der Funktion haben möchtest, dann kannst Du einfach anstelle des `tuple()` ein `list()` benutzen.
Ah, das ist prima! :-)
BlackJack hat geschrieben:Wenn Du `evaluate()` in die Funktion einbaust, dann spezialisierst Du damit die Funktion stärker. Wenn beides getrennt bleibt, dann kannst Du die Zahlen mit verschiedenen Auswertungsfunktionen benutzen und auch verschiedene Funktionen zum Generieren der Zahlen verwenden.
Das heisst, die Methode, die Funktionen getrennt zu halten, ist vor allem flexibler? Sie scheint mir auch besser zu "lesen", weil besser erkennbar, dass da ein neuer "Block" anfaengt. Wenn es fuer das Ausfuehren des Programms keinen Unterschied macht, werde ich dann die zweite Version nehmen.
BlackJack

merlin_emrys hat geschrieben:@ Rebecca und BlackJack: Noch ein ganz warmes Dankeschoen!
Rebecca hat geschrieben:Du meinst Funktionen. Ein Modul ist etwas, was in einer eigenen Datei steht und dann mit import importiert wird.
Das heisst, wenn ich meine Funktionen in eine eigene Datei stecke und von dort zu Beginn per import hole, werden sie zu Modulen? Oder ist das Modul dann die gesamte Datei?
Alles was in einer *.py Datei steht bildet zusammen ein Modul und kann von anderen Modulen aus oder im interaktiven Interpretierer importiert werden.
Danke fuer den Tip, allerdings laesst er mich doch noch ein wenig ratlos. Das, was return hier tut, entspricht erstmal dem, was ich von einem print auch erwarten wuerde. Mein Buch sagt mir leider auch nicht viel dazu... Koenntest Du dazu noch ein Wort verlieren? Ich vermute mal, man kann return irgendwie dazu verwenden, sich Werte auch fuer andere Zwecke (also nicht nur analog zu print) zu holen? Ich habe es mal mit Deinem Beispielprogramm und dann

Code: Alles auswählen

liste = []
liste.append(addieren(4,5))
versucht und festgestellt, dass es einen Unterschied macht, wenn ich die return-Zeile weglasse... ist das also ungefaehr die gedachte Verwendung?
Mit ``return`` gibt man an, was eine Funktion zurückgibt. Man kann sich auch vorstellen, das bei der Ausführung der Aufruf der Funktion durch den Rückgabewert ersetzt wird. Genau wie in der Mathematik. Bei Deinem Listenbeispiel wird ``addieren(4,5)`` ausgegeführt und durch das was ``return`` zurückgibt ersetzt. Und diese 9 wird dann an die Liste angehängt.

In Python hat jede Funktion einen Rückgabewert, wenn man selbst keinen festlegt, dann wird `None` zurückgegeben. Das wirst Du sicher in der Liste gesehen haben, wenn Du aus dem ``return`` ein ``print`` gemacht hast.
BlackJack hat geschrieben:
... braucht also der Generator immer eine Schleife, in der er steht?
Braucht er nicht, man kann auch die `next()` Methode benutzen um die Werte zu bekommen.
Die `next()` Methode hast Du weiter oben auch schon erwaehnt, aber mein Buch hat sie zumindest im Index nicht aufgefuehrt... Darf ich noch eine Runde weiter dumme Fragen stellen und mich erkundigen, was das fuer eine Methode ist?
Die sollte im Zusammenhang mit Iteratoren erwähnt werden. In der Python-Doku werden sie Zusammenhänge hier erklärt:

http://docs.python.org/lib/typeiter.html
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi Merlin!
merlin_emrys hat geschrieben:
Michael Schneider hat geschrieben:ist zwar wahrscheinlich Off-Topic, aber ich finde "Das Python-Buch" einfach genial für Einsteiger!
Hast Du dazu noch mehr Angaben? "Phyton-Buch" gibt bei der Amazon-Schnellsuche keinen Treffer :-( ... Allerdings komme ich ohnehin an deutsche Literatur hier (in Japan) nur sehr schwer, und die Versandkosten verringern den Spass zusaetzlich.
Amazon: http://www.amazon.de/gp/product/3827311 ... y&v=glance
Ist eben ein deutsches Buch und bei .com wahrscheinlich nicht erhältlich. Und wegen dem schicken - mal sehen, ob ich diese Woche noch eine Lieferung nach Japan habe... nein, leider nicht. ;-)
merlin_emrys hat geschrieben:
Michael Schneider hat geschrieben:also die Kombinationen würde ich wie bei Binärzahlen berechnen: ...

Wenn man die mit zip kombiniert, erhält man alle Kombinationen. Wo war doch gleich das Problem? :)
Ich glaube, das Problem ist im Thread-Titel mit "Anfaengerproblem" angedeutet... Und "Anfaenger" heisst in diesem Fall, dass ich spaetestens beim ersten Auftreten von "lamda" so meine Zweifel bekomme, ob es nicht den Rahmen des Forums sprengt, um Erklaerungen zu bitten, was es damit auf sich hat...
Lambda Ausdrücke generieren Funktionen ohne def-Anweisung. Das ist nützlich, wenn man sie direkt als Parameter übergeben möchte.

Allgemeine Syntax:
lambda arg1, arg2[, ...] : Ausdruck
Ich verwendete:
lambda x, y: x+y
Was soviel bedeutet wie: "Erzeuge eine Funktion, die zwei Werte erwartet und dann die Summe dieser zurückgibt." Bei Listen bedeutet das, dass beide Listen zu einer großen zusammengefügt werden.

Die reduce-Funktion erwartet als erstes Argument ein Funktionsobjekt und als zweites Argument ein iterierbares Objekt, z.B. eine Liste [1, 2, 3, 4]. Dann wendet sie die übergebene Funktion erst auf die ersten beiden Elemente an, dann auf deren Ergebnis und das dritte Element usw. bis es nur noch einen Wert gibt, der zurückgegeben wird.
Also:
a) 1+2
b) (3)+3
c) (6)+4
-> Rückgabewert 10

Zugegeben, man koennte den Code meines Vorschlags noch etwas strecken. Aber ihn mit Perl zu vergleichen ist eine Beleidigung. Ich wollte nur mal eine Alternative zum üblicherweise verwendeten divmod aufzeigen. ;-)

Grüße,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
merlin_emrys
User
Beiträge: 110
Registriert: Freitag 3. März 2006, 09:47

Zuerst zwei kleine Dinge am Rande:

Das erste:
Michael Schneider hat geschrieben:Ist eben ein deutsches Buch und bei .com wahrscheinlich nicht erhältlich. Und wegen dem schicken - mal sehen, ob ich diese Woche noch eine Lieferung nach Japan habe... nein, leider nicht. ;-)
Uebernaechste Woche waere schon auch noch ok... :-) Nein, im Ernst: Vielen Dank. Ich habe das Buch auf meine Liste zu besorgender Buecher gesetzt und hoffe mal, wenn ich naechstes Jahr wieder in Deutschland bin, noch ein Exemplar auftreiben zu koennen. Danke fuer den Tip, und auch danke fuer die Erklaerung der lambda-Funktion :-) .

Das zweite: Das Problem war (und ist) offenbar mein Umgang mit den Variablen - sollte ich das Thema ("Aus selbstgebauter Schleife entkommen") entsprechend umbenennen ("Globale und lokale Variablen")?

Mit den Variablen habe ich naemlich wohl schon wieder das naechste Problem... Ich habe den Zaehler in das gesamte Programm eingebaut, aber in dem ist "evaluate" mehr als nur eine "print"-Funktion. Sie rechnet und vergleicht einige Dinge - ich habe den Code unten angehaengt; "evaluate" geht derzeit von Zeile 24 bis Zeile 99. Wenn ich richtig gezaehlt habe, tauchen da mindestens 14 Variable auf (im Grunde die Zeilen 26 bis 39), und ein paar von denen brauche ich spaeter noch zum weiteren Auswerten.
Urspruenglich waren die Variablen-Definitionen im "allgemeinen" Teil (vor Zeile 190) untergebracht, aber dann haette ich sie alle als Parameter an die "evaluate"-Funktion uebergeben muessen, und das waere eine ziemlich lange Liste. Eventuell komme ich aber doch nicht umhin; jetzt komme ich naemlich an die Werte nicht dran, wenn ich meine Auswertung weiterfuehren will.
Oder hilft mir da "return" weiter? Ich habe es, weil sich die erste auftauchende Fehlermeldung derzeit ueber "fallzahl" in Zeile 212 beschwert, erstmal mit "fallz = return fallzahl" (als Zeile 99, jetzt mit #)versucht und in Zeile 212 entsprechend "fallzahl" durch "fallz" ersetzt, das hat aber jedenfalls nicht funktioniert.

Hier das Programm, wie es derzeit aussieht; und falls sich jemand über völlig sinnlose else-Anweisungen wundert: Die sind noch Reste meines Misstrauens, ob sich nicht manchmal doch unmoegliche Zustaende einstellen...

Code: Alles auswählen

# Programmentwurf

#
# Zaehlschleife
#
def counter(gro):
    aktuList = [1] * len(gro)
    last_index = len(gro) - 1
    while True:
        yield list(aktuList)
        i = last_index
        aktuList[i] += 1
        while aktuList[i] > gro[i]:
            aktuList[i] = 1
            i -= 1
            if i < 0:
                raise StopIteration()
            aktuList[i] += 1

#
# Einzelauswertung der Werte
#
#
def evaluate(aktuList,gro,bezl,konto,begausw):
    if begausw == "ja":
        gel = 0
        ausgegl = 0
        miss = 0
        fallzahl = 0
        summenliste = []
        fehlbetrag = 0
        fehlbetragliste = []
        kontonutzung = 0
        kontonutzliste = []
        ueberschuss = 0
        ueberschussliste = []
        treffer = 0
        trefferliste = []
        geprueft = []
    else:
        pass
    nochgel = 1
    for i in range(0,len(aktuList)-1):
        if aktuList[i] > bezl[i]:
            ueberschuss = ueberschuss + (bezl[i]-aktuList[i])
        elif aktuList[i] == bezl[i]:
            pass
        else:
            diff = aktuList[i]-bezl[i]
            if konto == []:
                nochgel = 0
                fehlbetrag = fehlbetrag - diff
            else:
                if len(konto) == 1:
                    konto[0] = konto[0] - diff
                    if konto[0] >= 0:
                        pass
                    else:
                        nochgel = 0
                        fehlbetrag = fehlbetrag - diff
                else:
                    if konto[i] >= aktuList[i]-bezl[i]:
                        kontonutzung = kontonutzung + diff
                    else:
                        nochgel = 0
                        fehlbetrag = fehlbetrag - diff
    if nochgel == 1:
        gel = gel + 1
        if ueberschuss > 0:
            ueberschussliste.append(aktuList)
            ueberschussliste.append(ueberschuss)
        else:
            treffer = treffer + 1
            trefferliste.append(aktuList)
    else:
        if fehlbetrag == 0:
            fehlbetragliste.append(aktuList)
            fehlbetragliste.append([0])
            # die innere Liste ist Fehlerindikator: Fehlbetrag 0 ist geschafft
        elif fehlbetrag < 0:
            fehlbetragliste.append(aktuList)
            if konto == []:
                fehlbetragliste.append(aktuList)
                fehlbetragliste.append(fehlbetrag)
                # der Eintrag ist für kein Konto und gem. Konto ist identisch
            elif len(konto) == 1:
                fehlbetragliste.append(aktuList)
                fehlbetragliste.append(fehlbetrag)
            else:
                fehlbetragliste.append(aktuList)
                fehlbetragliste.append(konto)
        else:
            fehlbetragliste.append(aktuList)
            fehlbetragliste.append([])
            # die innere Liste ist Fehlerindikator: Fehlbetrag > 0 ist unzulaessig
    begausw = "nein"
    fallzahl = fallzahl + 1
    geprueft.append(aktuList)
#    fallz = return(fallzahl)


#
# Eingabe und Definition der Anfangswerte
#
#
print "Werte festlegen:"
#
# Maximalwertabfrage:
#
f = False
groabfr = raw_input("Alle Maximalwerte gleich gross? j_a, n_ein: ")
while f == False:
    try:
        if groabfr == "j":
            ff = False
            while ff == False:
                try:
                    anz = int(raw_input("Anzahl der Werte eingeben: "))
                    ff = True
                except ValueError:
                   print "Keine gültige Eingabe, nochmal bitte: "
            gro = [int(raw_input("Maximalwert angeben: "))] * anz
            f = True
        elif groabfr == "n":
            i = 1
            gro = []
            while i > 0:
                i = int(raw_input("Naechster Maximalwert, 0 zum Abbruch: "))
                gro.append(i)
            if gro == [0]:
                print "So geht das nicht, ein Wert muss schon sein..."
            else:
                f = True
        else:
            f = False
    except ValueError:
        print "Keine gültige Eingabe, nochmal bitte: "

#
# Bezugswertabfrage:
#
f = False
bezabfr = raw_input("Bezugswert e_inheitlich oder s_pezifisch? e/s: ")
banz = len(gro)
while f == False:
    try:
        if bezabfr == "e":
            bezl = [int(raw_input("Gib den Bezugswert an: "))] * banz
            f = True
        elif bezabfr == "s":
            bezl = [0] * banz
            for i in range(banz):
                bezl[i] = int(raw_input("Naechsten Bezugswert angeben: "))
            f = True
        else:
            f = False
    except ValueError:
        print "Keine gültige Eingabe, nochmal bitte: "

#
# Kontoabfrage:
#
f = False
kanz = len(gro)
while f == False:
    try:
        kontoabfr = raw_input("Gibt es ein Konto? j_a,n_ein: ")
        if kontoabfr == "n": 
                konto = []          
                f = True
        elif kontoabfr == "j":
                konto = [0]
                kontodef = raw_input("Ge_m_einsames oder ge_t_renntes Konto? m/t: ")
                if kontodef == "m":
                    konto = [int(raw_input("Kontogröße angeben: "))]
                    f = True
                elif kontodef == "t":
                    konto = [0] * kanz
                    for i in range(kanz):
                        konto[i] = int(raw_input("Naechsten Kontowert angeben: "))            
                    f = True
                else: 
                    f = False
        else: 
                print "Keine gültige Eingabe"
    except ValueError:
        print "Keine gültige Eingabe, nochmal bitte: "


# 
# Kontrolle: Werte ausgeben:
#
print "Folgende Werte werden verwendet:"
print "Maxima: ", gro
print "Bezugswerte: ", bezl
print "Kontowerte: ", konto

#
# Zaehlschleife und Pruefung aufrufen:
#
begausw = "ja"
for aktuList in counter(gro):
    evaluate(aktuList,gro,bezl,konto,begausw)

#
# Abschliessende Pruefung der Fallzahl (tfz = theoretische Fallzahl)
#
tfz = gro[0]    
for i in range(1,len(gro)):
    tfz = tfz*gro[i]
    i = i + 1
if fallzahl == tfz:
    print "Auswertung erfolgreich"
else:
    print "Theoretische Fallzahl und Zahl gepruefter Faelle stimmen nicht ueberein."
 
#
# Ausgabe
#
if anz == 0:
    print "Irgendwas ist da schiefgegangen, bitte um Entschuldigung..."
else:
    print "Die Zahl der misslungenen Faelle ist ", miss
    print "Die Zahl der gelungenen Faelle ist ", ausgegl + gel
    print "Von den gelungenen Faellen mussten ", ausgegl, " mithilfe des Kontos ausgeglichen werden"
    vollstausg = raw_input("Listen ausgeben? j_a, n_ein: ")
    if vollstausg == "j":
        print "Liste der geprueften Faelle: ", geprueft
        print "Liste der Fehlbetraege: ", fehlbetragliste
        print "Liste der Kontonutzungen: ", kontonutzungliste
        print "Liste der Ueberschuesse: ", ueberschussliste
    elif vollstausg == "n":
        print "ok"
    else:
        print "Keine gültige Eingabe"
bb1898
User
Beiträge: 200
Registriert: Mittwoch 12. Juli 2006, 14:28

merlin_emrys hat geschrieben: Das zweite: Das Problem war (und ist) offenbar mein Umgang mit den Variablen - sollte ich das Thema ("Aus selbstgebauter Schleife entkommen") entsprechend umbenennen ("Globale und lokale Variablen")?
Ich denke eher, Dein Problem ist der Umgang mit Funktionen, ihren Parametern und Rückgabewerten; deswegen habe ich die Überschrift mal so formuliert.

Ich muss gestehen, dass ich nicht versucht habe, Dein Programm zu verstehen - es ist zu lang, und für Leser, die das zugrundeliegende Problem nicht kennen, wären mehr Kommentare ganz dringend nötig.

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.
Mit den Variablen habe ich naemlich wohl schon wieder das naechste Problem... Ich habe den Zaehler in das gesamte Programm eingebaut, aber in dem ist "evaluate" mehr als nur eine "print"-Funktion. Sie rechnet und vergleicht einige Dinge - ich habe den Code unten angehaengt; "evaluate" geht derzeit von Zeile 24 bis Zeile 99. Wenn ich richtig gezaehlt habe, tauchen da mindestens 14 Variable auf (im Grunde die Zeilen 26 bis 39), und ein paar von denen brauche ich spaeter noch zum weiteren Auswerten.
Urspruenglich waren die Variablen-Definitionen im "allgemeinen" Teil (vor Zeile 190) untergebracht, aber dann haette ich sie alle als Parameter an die "evaluate"-Funktion uebergeben muessen, und das waere eine ziemlich lange Liste. Eventuell komme ich aber doch nicht umhin; jetzt komme ich naemlich an die Werte nicht dran, wenn ich meine Auswertung weiterfuehren will.
Oder hilft mir da "return" weiter? Ich habe es, weil sich die erste auftauchende Fehlermeldung derzeit ueber "fallzahl" in Zeile 212 beschwert, erstmal mit "fallz = return fallzahl" (als Zeile 99, jetzt mit #)versucht und in Zeile 212 entsprechend "fallzahl" durch "fallz" ersetzt, das hat aber jedenfalls nicht funktioniert.
Also ein paar allgemeine Bemerkungen zu Funktionen, ihren Parametern und ihren Rückgabewerten. Lutz & Ascher sagen es besser, aber das soll uns jetzt mal nicht stören.

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.

- 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.

Ein "meinNeuerWert = return Ausdruck" in der Funktionsdefinition ist ein Syntaxfehler. return ist ja nicht selbst eine Funktion, sondern eine Anweisung.

Ich höre hier mal auf und warte besser auf Deine Rückfragen.
Antworten