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

Funktionen und Variable (war: "Schleife")

Beitragvon merlin_emrys » Dienstag 15. August 2006, 09:00

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

Re: Anfaengerproblem: Aus selbstgebauter Schleife entkommen

Beitragvon BlackJack » Dienstag 15. August 2006, 12:22

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

Beitragvon pr0stAta » Dienstag 15. August 2006, 14:40

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: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Beitragvon Michael Schneider » Dienstag 15. August 2006, 14:52

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

Beitragvon BlackJack » Dienstag 15. August 2006, 15:08

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: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Beitragvon Michael Schneider » Dienstag 15. August 2006, 15:14

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

Beitragvon BlackJack » Dienstag 15. August 2006, 15:29

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:

Beitragvon jAN » Dienstag 15. August 2006, 16:02

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

Beitragvon BlackJack » Dienstag 15. August 2006, 16:56

`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

Beitragvon pr0stAta » Dienstag 15. August 2006, 16:59

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: 130
Registriert: Mittwoch 12. Juli 2006, 14:28

Re: Anfaengerproblem: Aus selbstgebauter Schleife entkommen

Beitragvon bb1898 » Dienstag 15. August 2006, 17:24

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: 567
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Beitragvon Michael Schneider » Dienstag 15. August 2006, 18:49

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

Beitragvon merlin_emrys » Mittwoch 16. August 2006, 04:10

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:

Beitragvon Rebecca » Mittwoch 16. August 2006, 08:02

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

Beitragvon BlackJack » Mittwoch 16. August 2006, 09:38

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.

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]