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