Feld erstellen

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.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Hätte nicht gedacht, das mein bisschen Code solche Wellen schlägt :)

Jonas, Field-Exemplare werden in Zeile 8 mit x und y initialisiert. `cls(x, y)` erzeugt, da `cls==Field`, entsprechende Exemplare, was dazu führt, dass `Field.__init__` aufgerufen wird, was dann die beiden Koordinaten setzt. Die "list comprehension" (der Ausdruck in eckigen Klammern mit den beiden for-in-Ausdrücken) sorgt dafür, dass für alle x von 0 bis `width-1` und für alle y von 0 bis `height-1` jeweils ein Field-Exemplar erzeugt und initialisiert wird, die dann alle zusammen in Form einer Liste der Exemplarvariablen `fields` zugewiesen werden.

Die spezielle Methode `__iter__` sorgt dafür, dass ein Objekt aufzählbar wird und damit in einer for-Schleife benutzt werden kann (siehe Zeile 18 in meinem Code). Das Objekt aufzuzählen interpretiere ich als auf Aufzählen aller Felder und daher gebe ich einen mit `iter()` erzeugten Iterator für die Liste aller Felder zurück. Man hätte auch `for f in b.fields` schreiben können.

Die spezielle Methode `__getitem__` sorgt dafür, dass man mit `[]` auf ein Board-Exemplar zugreifen darf. Ein `b[2,1]` ist die Kurzform für `b.__getitem__((2, 1))`. Beachte, dass `(2, 1)` ein Tupel ist, welches ist dann in meiner `__getitem__`-Implementierung durch die Extraklammern in der Parameterliste sofort auf zwei Variablen aufspalte.

Wuf, ein `output_board` passt IMHO besser als Methode. Auch finde ich nicht so gut, fehlende `name`-Attribute über eine Exception -- zumal noch eine "catch all"-Exception -- aufzufangen. Wenn man viele unterschiedliche Attribute hat, die häufig fehlen, würde ich's eher so machen:

Code: Alles auswählen

class Field...
    def __getattr__(self, name):
        return getattr(self, name, None)
In der Regel ist aber wohl der richtige Weg, das Attribut in `__init__` zu initialisieren.

Hyperion, wenn schon "themes", dann bitte nicht als globale Variable. Besser wäre es, so ein Dictionary als weiteres Argument der Methode bzw. Funktion `output_board` zu übergeben. Andererseits: Solange man sich nicht sicher ist, dass man verschiedene Varianten benötigt, sollte man YAGNI beachten.

Stefan
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo sma

Besten Dank für deinen Feedback. Ich sehe jetzt klarer. Ich muss nur feststellen, dass Tag für Tag in der Python-Sprache neu Elemente auftauchen die intensives Doc-Lesen fordern, dass nicht mehr von den geschriebenen Worte abgelesen werden kann was abläuft.

Gruss wuf :wink:
Take it easy Mates!
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Eigentlich kann man's schon ablesen (es geht gar nicht anders, sonst wäre es keine für einen Computer eindeutig interpretierbare Sprache), nur ist der Sprachumfang größer als du zur Zeit denkst.

Ich bin mir sicher, dass dir auch irgendwann "Pattern matching, "Sequence comprehensions" oder Funktionen höherer Ordnung als ganz normale Sprachkonstrukte vorkommen werden.

Ich gestehe, bei Dingen wie dem Y-Kombinator komme ich auch nicht mehr mit:

Code: Alles auswählen

def Y(f):
    l = lambda cc: f(lambda x: cc(cc)(x))
    return l(l)

fac = Y(lambda f: lambda n: 1 if n == 0 else n * f(n - 1))
Stefan
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo sma

Danke für deine guten Erklärungen. Muss zugeben bei dem von dir vorgestellten Y-Kombinator gerät meine Sprache ins stottern. :lol:

Gruss wuf :wink:
Take it easy Mates!
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Och, vorlesen kann ich's schon:

Das innere lambda in Zeile 5 ist die Fakultätsfunktion, die aber statt sich selbst rekursiv aufzurufen, das in dieser Funktion freie "f" als Funktion benutzt. Das äußere Lambda stellt diese Funktion zur Verfügung und ist damit eine Funktion, die eine Funktion liefert, die ein "n" für die Faktultätsfunktion erwartet. Der Y-Kombinator nimmt nun diese Funktion, die eine Funktion liefert, die das "n" erwartet, und macht sie zu einer vollständigen Fakulitätsfunktion, die sich rekursiv aufruft und ein "n" erwartet.

Der Y-Kombinator macht offenbar aus einer dergestalten Funktion eine rekursive Funktion.

In Zeile 3 liefert er das Ergebnis von "l" auf sich selbst angewandt zurück. "l" ist eine Funktion, die eine Funktion übergeben bekommen muss, die sagt, wie es weiter geht, eine sogenannte "continuation" (auch current continuation bzw. cc genannt). Diese ist sie selbst. Damit ist "l(l)" eine Funktion, die an "f" übergeben, "f" wieder aufruft (bis das `if n==0` in Zeile 5 wahr ist). Arg... Hut ab vor den verdrehten Gedanken von Haskell Curry, der das Ding erfunden hat.

Stefan
Benutzeravatar
jonas
User
Beiträge: 156
Registriert: Dienstag 9. September 2008, 21:03

nabend.
Hallo Freunde (falls ihr mir erlaubt diesen Ausdruck zu nutzen!)

@sma:
Vielen Dank für diese ausführliche Beschreibung dessen was geschieht!
:D

In dieser Sache auch noch einmal danke an alle anderen, die mir geholfen haben das Skript zu verstehen.
Hätt ich ohne euch niemals so "schnell" geschafft :oops:

(@ alle Kritiker: ich weiß, dass ausführlicheres Tutorial lesen mich besser
auf diese Art von Code vorbereitet hätte...)

Mit freundlichen Grüßen
Jonas
Antworten