Schiffe versenken

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

Hallo,
Ich habe Schiffe versenken für Python programmiert, es funktionier wie mit Bleistift und Papier.

Die Regeln:
-Jeder hat ein gleichgroßes Spielfeld mit der selben Anzahl Schiffe.
-Die Schiffe dürfen sich nicht berühren.
-Jeder hat genau einen Schuss, danach ist der andere an der Reihe.
-Ziel ist es alle Schiffe des Gegners zu versenken.

So funktioniert es:
-Feld anklicken um es auszuwählen und Schiffsgröße (2-5) mit der Tastatur eingeben, danach Ausrichtung mit Pfeiltasten auswählen.
-Bei Meldungen wie "Achtung Überschneidung" die Leertaste drücken und fortfahren.
-Nachdem die Schiffe alle erstellt wurden wird abwechselnd geschossen.

Version 1: Version 2 Die Grafikversionen benötigen zum Betrieb Pygame.
Zuletzt geändert von Lasse am Dienstag 21. Juni 2011, 18:15, insgesamt 3-mal geändert.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Was mir da als erstes auffällt, ist, dass du die ganzen Daten in irgend welchen Listen speicherst. Das wird so unübersichtlich, dass du in Kommentaren beschreiben musst, welches Element der Liste was für eine Bedeutung hat.

Du willst dir für die Datenstrukturen vielleicht mal Klassen angucken. Muss ja nicht gleich alles objektorientiert sein, aber schöne Datenstrukturen wären schon ganz nützlich :-)

Als zweites entferne alle "global" aus deinem Code. Das wird erstmal alles kaputt machen, d.h. du wirst dir andere Wege suchen müssen, die Daten/Änderungen durchzureichen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Da steckt bestimmt einiges an Zeit drin, also nimm folgendes als konstrucktive Kritik auf und nicht als Versuch dich runter zu "putzen" :D

1. OOP wäre vieleicht angebracht gewesen, gerade wenn man mit Pygame arbeitet. Vorallem stören die relativ unübersichtlichen Listen.
2. Sieh dir mal deine ganzen globals an, aus meiner Sicht wird das echt widerlich das ganze bei einem Fehler zu debuggen, zudem man globals nach möglichkeit nie aufgerufen werden sollten. (Was du aber gut 40 mal tust)
3. Deutsche Variablen und Funktionnamen halte ich zwar nicht besonders schön, aber habe Prinzipiell nichts dagegen, solange sie nicht mit englischen gemischt werden, dennoch kann man sich an die PEP8 halten und Funktionsnamen klein und mit Unterstrichen schreiben. Einige bevorzugen da zwar das von dir verwendete CamelCase, aber man sollte diese (zB bei "Wert_testen") nicht mischen.
4. Bei normalen Modul importen, sollte man sich schon für jeden import eine Zeile gönnen.
5. Was sollten immer diese "while any == false:" Geschichten, nutze doch einfach "while not any:" und bei deinen "while test = ...", kann man auch getrost "while True" nehmen und dann bei der korrekten Eingabe ein "break" benutzen. Dann sparst du dir dieses ständige "test = True; test = False; test=....."
6. Du solltest, gerade bei so einem großen Script, deine Main mal richtig Kennzeichnen, dies tut man in Python für gewöhnlich mit "if __name__ == '__main__':", zudem sollte wohl "pygame.init()" auch im Main-Bereich liegen.
7. Für deine Zahlen- und Buchstaben- und Richtungsabfragen würde sich eine Dictionary doch Ideal eignen, wieso machst du daraus einen ganzen if-Stapel. Wobei sich mir auch gleich die Frage gestellt hat, warum man eine GUI nimmt, wenn man dann doch mit der Tastatur die Kästchen auswählt, ich bin mir sicher, das das in Pygame auch die Maus ohne weiteres hierfür nutzen kann.
8. Hast du auch schonmal davon gehört, das man die GUI von der Logik trennen sollte (ich weiß das fällt schwer, auch mir, aber dennoch sollte man es wenigstens Versuchen)
9. Zur Info, das "alphabeet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'", exisitiert im Modul "string", als "string.ascii_uppercase".
10. Irgendwie erschließt sich bei mir nicht der Sinn der ganzen Zähler in "ZeichneSpielfeld", überhaupt, sind deine Funktionen alle ziemlich aufgebläht, vieleicht solltes du mal darüber Nachdenken, die Funktionen in mehrere kleinere Teilaufgaben zu zerlegen.
11. "time.sleep"s mitten im Programm(bzw mitten in Funktionen), können für ein ziemlich Irre führend sein, zumal die meisten GUIs dies nicht vertragen, da ihre Haupt-Schleife nicht mehr aufgerufen wird und damit sich die GUI "einfriert".
12. Sofort raus mit dem "sys.exit" das hat hier nichts verloren, du musst die Hauptschleife der GUI an der Stelle "töten", leider weiß ich nicht was man in Pygame normaler weise dafür nutzt, aber "sys.exit" wird es bestimmt nicht sein.
13. Du solltest dringend deine Abfragen prüfen, ob verschiedene Sachen nicht einfacher gehen, zB lässt sich die Abfrage ob die x- und y-Werte in einem bestimmten Rahmen sind, sehr einfach so abfragen

Code: Alles auswählen

def test_value(x, y, size=10):
    return 0 < x < size and 0 < y < size 
Deine Methode, packt diese ja noch in einen String, was wiie du vileicht gemerkt hast, nicht gerade eine Sinnvolle Lösung war, da bei 999 Schluß ist. Aber selbst wenn du es so machen willst, wäre es hierfür besser die Sachen getrennt zu machen.
14. Strings kannst du gleich als Listen nutzen, nur verändern geht nicht, so kann man sich aber zB.: "random.choice(['H', 'D', 'L', 'R'])" auf "random.choice('HDLR')" kürzen.
#---------
15. Die Auswahl zu Beginn des Spieles ist sehr verwirrend, zum einen ist dies im Terminal, was ja nicht wild wäre(wirk aber in einer GUI unbequem), aber wieso muss man erst eine Anzahl der Schiffe definieren und dann die einzelnen Schiffe? Es würde doch reichen die Anzahl der einzelnen Schiffe anzugeben, die gesamt Zahl ergibt sich doch daraus.
16. Weiterhin wäre es schön eine Liste mit Schiffen am Rand gelistet zu haben, um diese immer schön im Blick zu haben.

Mir würde noch mehr einfallen, aber ich belasse es erstmal dabei.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Ich finde deine Formulierungen teilweise echt unangebracht vorwurfsvoll, so nach dem Motto "du weißt doch, dass XYZ, warum setzt du es dann nicht um", obwohl Lasse XYZ offensichtlich nicht kennen kann. Konstruktive Kritik sieht anders aus.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@Dauerbaustelle
Sry :( , wenn das so rüber kommt

@Lasse
Es ist spät und auch wenn die schnellen Formulierungen vieleicht etwas Vorwurfsvoll klingen, bitte nicht so ernst nehmen. Ist schon eine ganze Menge Ausdauer und Zeit nötig um so ein Spiel zu schreiben, besonders wenn man noch nicht lange programmiert. Sieh dir einfach die einzelnen Punkte an und denk darüber nach, keiner wird dich zwingen das in deinem Programm zuändern. Meist dienen diese Infos aber für spätere Programme, denn Fehler sollten nach Möglichkeit nicht wiederholt werden.
Die Punkte davon-hast-du-aber-schonmal-gehört-Sachen, wenn das bisher noch nicht der Fall war, dann jetzt :wink: (und diese sollten eigentlich kein Vorwurf sein)
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

Danke für alle eure Antworten. :)
Es wird auf jeden Fall eine weitere Version von "Schiffe versenken" geben.

Diese wird einige einige Veränderungen enthalten:

-eine Klasse für jedes Spielfeld
-nicht mehr mein "String-Format", bei dem allerdings nicht bei 999 Ende ist sondern erst bei 9999 und das entspricht immerhin einem Feld von der Größe 99*99 :D , Aber dieses Format ist recht Fehleranfällig, deshalb gibts jetzt Koordinaten als mini Integerliste [x , y].
-das "string.ascii_uppercase" werde ich an den 1-2 Stellen verwenden.
-auf die "global"s werde ich nicht ganz verzichten können sie dürften aber viel weniger werden.
-Das Fenster schließen mit sys.exit() habe ich aus dem Buch "Hello World" übernommen, werde aber ab jetzt pygame.display.quit() verwenden. (sys.exit() tötet auch die Hauptschleife nur dummerweise das ganze Programm mit :( )
-bei meinen Time.sleep weiß ich nicht wie ich die ersetzen soll, die GUI soll ja warten damit man Zeit hat den Text zu lesen. Hat da jemand eine Idee?
-werde häufiger while True verwenden
-diese Dictionarys kenne ich nicht, gibt es dazu eine gute Erklärung (auf Deutsch)?
-Logik und GUI werde ich versuchen zu trennen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Lasse hat geschrieben:eine Klasse für jedes Spielfeld
:?: - ich glaube du hast da was an den Klassen nicht verstanden, eine Klasse soll Eigenschaften, Attribute und Fähigkeiten eines Objektes definieren. Das heißt du brauchst im Grunde nur eine Klasse "Spielfeld", die Größe dessen, sollte man über die Attribute setzen können.
Lasse hat geschrieben:...Koordinaten als mini Integerliste [x , y].
Das klingt schon besser, auch wenn ich hier ein Tuple nutzen würde, denn eine Liste braucht es eigentlich nicht. Man könnte auch ein Objekt Koordinaten nutzen, finde ich aber etwas dick aufgetragen, kommt aber ganz auf den Zweck an.
Lasse hat geschrieben:auf die "global"s werde ich nicht ganz verzichten können sie dürften aber viel weniger werden.
Doch wirst du, wir werden dich schon noch so weit bringen :). Es gibt wirklich nur sehr sehr wenige Fälle wo man diese wirklich braucht.
Lasse hat geschrieben:sys.exit() tötet auch die Hauptschleife nur dummerweise das ganze Programm
Es "tötet" die Hauptschleife ebend nicht direkt sondern, wie du bemerkt hast, den gesamten Python Prozess. Deswegen sollte es hier auch vermieden werden.
Lasse hat geschrieben:bei meinen Time.sleep weiß ich nicht wie ich die ersetzen soll...
Mit einem Pygame-Timer, hier wirst du fündig: http://www.pygame.org/docs/ref/time.html
diese Dictionarys kenne ich nicht, gibt es dazu eine gute Erklärung (auf Deutsch)? hat geschrieben:werde häufiger while True verwenden
"while True" sollte man auch nicht allzu häufig nutzen, aber hier, bei solchen Eingaben ist es durchaus Sinnvoll, aber achte immer darauf, dass das "break" auch ereicht werden kann, sonst hast du schnell eine Endlosschleife.
Lasse hat geschrieben:diese Dictionarys kenne ich nicht, gibt es dazu eine gute Erklärung (auf Deutsch)?
Ein Wörterbuch, sehr wichtig für's programmieren in höheren Programiersprachen, den Link hat Dauerbaustelle schon geschrieben.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

@Xynon1
Ich erstelle ein Objekt von dem ich zwei Kopien anfertige, eine für jedes Spielfeld.
Habe die Listen in tupels geändert.
Ja, ich werde das "pygame.time.wait(milliseconds)" verwenden.
Juhu, Fast bin ich über den Berg, bisher nur 2 globals haben es als Konstanten in mein Programm geschafft! Die werde ich auch noch los.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ok, das mit dem Spielfeld hatte ich wohl falsch verstanden.
Was die "global"s angeht - Wozu brauchst du bei Konstanten "global"? Wenn in Python eine Variable nicht in einem Namensraum gefunden werden kann, wird im nächst höheren Namensraum gesucht. Das lesen der Variable ist also nicht das Problem und eine Konstante muss man ja nicht ändern. Also einfach eine Modul-weite Variable nutzen und die "global"s weglassen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

Hallo,

ich bin eifrig am programmieren der neuen Version hier ein kleines Beispiel aus dem Programm. Der Code zeigt die Funktion Nachbarfelder in der neuen Version mit mehr Möglichkeiten:
-Verarbeitung mehrerer Werte auf einmal
-Suche nach Schusspositionen horizontal, vertikal und beides.
-Verwendung eines Objektes (kommt in diesem Beispiel nicht so gut zum Einsatz)
-Verwendung von Dictionarys

Code: Alles auswählen

class Feld:
    def __init__(self):
        self.schussliste = [] #Hier Koordinaten als (x, y) einfügen
        self.vir_schussliste = [] #Hier Koordinaten als (x, y) einfügen
        self.grosse_feld = 10

    def Nachbarfelder(self, werteliste, typ):
        umrand_liste = []
        for kor in werteliste:
            neue_pos = {"senkrecht": [(kor[0], kor[1]-1),(kor[0], kor[1]+1)],
                        "waagerecht": [(kor[0]+1, kor[1]), (kor[0]-1, kor[1])],
                        "unbekannt": [(kor[0], kor[1]-1),(kor[0], kor[1]+1),(kor[0]+1, kor[1]), (kor[0]-1, kor[1])],
                        "umrandung": [(kor[0], kor[1]-1),(kor[0], kor[1]+1),(kor[0]+1, kor[1]), (kor[0]-1, kor[1]),
                                      (kor[0] -1, kor[1]-1),(kor[0]+1, kor[1]+1),(kor[0]+1, kor[1]-1), (kor[0]-1, kor[1]+1)]}
            if type(kor) == tuple:
                for n_kor in neue_pos[typ]:
                    if not n_kor in self.schussliste and not n_kor in self.vir_schussliste and not n_kor in umrand_liste: #Sortiert schon vorhandene Koordinaten aus
                        if 0 < n_kor[0] <= self.grosse_feld and 0 < n_kor[1] <= self.grosse_feld: #Sortiert ungültige Koordinaten aus.
                            umrand_liste.append(n_kor)
        return umrand_liste

Testobjekt = Feld()
umrandungsfelder = Testobjekt.Nachbarfelder([(1, 1)], "senkrecht") #Hier Art der Nachbarfelder auswählen, die gefunden werden sollen
print umrandungsfelder
Über Kommentare und Verbesserungsmöglichkeiten freue ich mich!

PS: Das neue Programm ist fast fertig.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Anstatt ständig ``foo[0]`` und ``foo[1]`` zu schreiben würde ich das einmal auspacken:

Code: Alles auswählen

x, y = foo
.

Statt ``type(a) == b`` verwendet man üblicherweise ``isinstance(a, b)``. Statt ``not a in b`` wird empfohlen ``a not in b`` zu verwenden (meiner Meinung nach ist ersteres manchmal aber auch bessser angebracht, kommt auf die "Fragestellung" der Bedingung an).
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Also was mir so auf die schnelle aufgefallen ist:
  • "Nachbarfelder" ist kein guter Name für eine Funktion / Methode. Generell sollte die auf einem Verb basieren, in diesem Falle also eher get_neighbours() o.ä. Da sieht man auch den Vorteil englischer Bezeichner; die sind idR kürzer als äquivalente deutsche Namen; bekomme_nachbarfelder() :mrgreen:
  • andere Namen sind auch wenig aussagekräftig. "umrand_liste" z.B. Das das eine Liste ist (Oder zumindest ein iterable!), sollte der Name an sich hergeben. "raender" wäre da evtl. passend.
  • Beachte PEP8 mehr; die Definition von "neue_pos" ist so schwer lesbar. Z.B. so:

    Code: Alles auswählen

                neue_pos = {
                    "senkrecht": [
                        (kor[0], kor[1]-1),
                        (kor[0], kor[1]+1)
                        ],
                    "waagerecht": [
                        (kor[0]+1, kor[1]), 
                        (kor[0]-1, kor[1])
                    ],
                    "unbekannt": [
                        (kor[0], kor[1]-1),
                        (kor[0], kor[1]+1),
                        (kor[0]+1, kor[1]), 
                        (kor[0]-1, kor[1])
                    ],
                    "umrandung": [
                        (kor[0], kor[1]-1),
                        (kor[0], kor[1]+1),
                        (kor[0]+1, kor[1]), 
                        (kor[0]-1, kor[1]),
                        (kor[0] -1, kor[1]-1),
                        (kor[0]+1, kor[1]+1),
                        (kor[0]+1, kor[1]-1), 
                        (kor[0]-1, kor[1]+1)
                    ]
                }
    
  • "neue_pos" immer neu zu definieren, zudem noch in einer Schleife (!), ist vom Laufzeitverhalten schlecht. Definiere das ganze doch zu Beginn der Methode oder am besten als Klassenattribut oder gar auf Modulebene. Wenn ich das richtig verstehe sind das ja dynamische Berechnungen ausgehend von einem speziellen Koordinatenpärchen. Du solltest das generischer Formulieren. Z. B. so:

    Code: Alles auswählen

    # auf Modulebene
    VERTICALLS = [(0, 1), (0, -1)]
    HORIZONTALS = [(1, 0), (-1, 0)]
    UNKNOWN = VERTICALLS + HORIZONTALS
    DIAGONALS = [(1, 1), (-1, -1), (1, -1), (-1, 1)]
    BOX = UNKNOWN + DIAGONALS
    
    POSITIONS = {
        "vertical": VERTICALLS,
        "horizontal": HORIZONTALS,
        "unknown": UNKNOWN,
        "box": BOX,
    }
    
    # und dann unten:
            for x, y in werteliste:
               for x_aim, y_aim in ((x+x_off, y+y_off) 
                            for x_off, y_off in POSITIONS[typ]):
                        if 0 < x_aim <= self.grosse_feld and \
                           0 < y_aim <= self.grosse_feld:
                                umrand_liste.append((x_aim, y_aim))
    
  • Generell könnte man sich mal überlegen, sich eine Klasse für Koordinaten zu bauen, damit Addition usw. ein wenig einfacher zu formulieren wäre.
  • Die Typprüfung wenn mit isinstance() wie Dauerbaustelle das schon vorgeschlagen hat. Die ist aber sowieso sinnlos an der Stelle, da es keine Alternative gibt ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Lasse
User
Beiträge: 112
Registriert: Donnerstag 3. Februar 2011, 18:25

Hallo Python Forums Nutzer,

hier ist erstmal eine Textausgabe der Version 2 von Schiffe versenken.

Veränderungen:
-eine Klasse für das Spielfeld
-eine Statistik (C=Computer, S=Spieler, G=Anzahl Schiffe zu Spielstart
-Datenformat der Koordinaten von String auf Tupel (x, y)
-eine bessere Schusslogik (vorher wurde jedes Feld getroffen, nun Gitternetz.
-keine globals
-einige kleine Änderungen

http://www.python-forum.de/pastebin.php?mode=view&s=162

Kritik, aber auch Lob sind gerne willkommmen.

PS: in der Version könnten noch einige Fehler sein, ich ändere die Datei bei Bedarf.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

  • Typprüfung mit `isinstance`.
  • Entweder Deutsch oder Englisch, nicht beides vermischen.
  • Zeile 64: Niemals alle Fehler abfangen, gib hinter `except` an, welche Fehler du erwartest.
  • noch ein `global` in Zeile 99
BlackJack

@Lasse: `HIGHT` sollte wohl `UP` heissen.

In den Namen kommt zu oft der Typ vor. `liste` sollte kein Bestandteil von Namen sein. Wenn man den Typ ändert, muss man entweder alle vorkommen des Namens ändern, oder man hat falsche und irreführende Namen im Programm. Das sind zum Beispiel einige Listen die man wahrscheinlich durch `set`\s ersetzen könnte.

Abkürzungen sollte man auch vermeiden. `FeCom`, `FeSpi`, `compu` oder `aSchiffeGrJe` werfen mehr Fragen auf, als sie beim Programmverständnis helfen.

Die Reihenfolge bei zusammengesetzten Namen ist teilweise auch "unnatürlich": `grosse_feld`, `grosse_schiff`, oder `ausrichtung_shiff` heissen zum Beispiel auf deutsch eigentlich `feldgroesse`, `schiffsgroesse`, und `schiffsausrichtung`.

Ein Objekt sollte nach der `__init__()` in einem benutzbaren Zustand sein. Ein ``print Feld()`` sollte zum Beispiel kein `AttributeError` zur Folge haben. In der `__init__()` sollten alle Attribute des Objektes erzeugt werden. Dann sieht man wenn man sich die durchgelesen hat, was für Attribute ein Objekt hat, und wundert sich nicht wo die in anderen Methoden herkommen, oder in welcher Reihenfolge man Methoden aufrufen muss, bis ein Objekt "funktioniert". Sollte es diesbezüglich Einschränkungen geben, sollte man die dokumentieren.

Typprüfungen sollte man vermeiden. Am besten man vermeidet das irgendwo nicht-polymorphe Typen in einer Struktur stecken, oder man versucht einfach was man will und reagiert dann entsprechend auf die Ausnahme.

Statt ``x_a = kor_a[0]`` und ``y_a = kor_a[1]`` kann man das auch in einer Zeile als ``x_a, y_a = kor_a`` schreiben. Oder halt gleich in der ``for``-Schleife als ``for x_a, y_a in werteliste:``.

Diese Koordinatenlisten sind IMHO eine reichlich ungünstige Datenstruktur. Wenn man wissen will, was mit einem Feld los ist, muss man ja teilweise mehrere Listen linear nach den Koordinaten durchsuchen. Eine 2D-Struktur mit einer moderaten Grösse kann man besser und IMHO auch viel naheliegender als Liste von Listen mit Feldern darstellen bzw. Zellen, da der Name Feld ja schon für das Ganze vergeben ist.

Globale Variablen kennzeichnen sich ja nicht nur durch das Schlüsslwort ``global``. Lass mal den Quelltext auf Modulebene der hinter dem ``if __name__``... steht, in einer Funktion verschwinden. Dann wirst Du feststellen auf was Du noch so zugreifst, was eigentlich nicht sein sollte.

Einiges ist für meinen Geschmack zu lang, zu tief verschachtelt, und zu kompliziert. Das kann man durch aufteilen in mehr und gut benannte Funktionen und durch bessere Aufteilung in Klassen und Methoden verständlicher schreiben.

Der Code am Modulende geht so IMHO gar nicht. Das ist eindeutig zu viel in einer "Funktion".
Silmaril
User
Beiträge: 55
Registriert: Sonntag 21. September 2008, 17:10
Wohnort: Franken

die imports würde ich nirgends anders als oben unter der coding-Zeile definieren. Dort erwartet man sie.
Auf Modulebene mit if __name__ == '__main__': quasi die Mainfunktion zu emulieren, ist zwar möglich aber warum gönnst du dir nicht einfach eine Funktion "main" und rufst sie ganz unten mit if __name__ == '__main__': auf? Das ist übersichtlicher.
Lebe jeden Tag, als wäre es Absicht.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@Silmaril
Bei erstens geb ich dir vollkommen Recht, aber bei zweitens, ist das wohl reine Geschmackssache. Der einzige Vorteil den ich in einer "main"-Funktion sehe, wie du sie Vorschlägst, besteht darin das sie auch von einem anderen Modul aus benutzt werden kann. Dies wird aber eigentlich nie benötigt, unterm Strich meiner Meinung nach egal. Ich bevorzuge die Schreibweise ohne extra "main"-Funktion auch meist. Vorallem wenn man einfache Terminal-Argumente(sys.argv) im Script auswerten will, macht eine "main" AFAIK keinen Sinn.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Wenn man die Sachen nicht in eine Funktion steckt, dann sind die Namen, die man in dem Quelltext bindet im Modulnamensraum. Das verleitet Anfänger öfter mal dazu aus dem Funktionen/Methoden im Modul direkt auf solche "globalen" Objekte zuzugreifen. Bei einer eigenen Funktion kommt man gar nicht erst in die Verlegenheit, dass das funktioniert. Da sind auch diese Namen in einem eigenen, lokalen Namensraum "weg gesperrt".
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ok, das ist zumindest ein besserer Vorteil als den ich genannt hatte. Dennoch nicht zwingend erforderlich, wenn man nicht dazu tendiert Variablen irgendwo her zunehmen, wie es einem gerade passt :roll:.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Antworten